Migrations
Salve DB auto-migrates SQLite tables from your schema definitions. There is
no migration file to write or run — the native Migration Engine
diffs the declared schema against the stored table on every Database.register() call.
How it works
Each schema declares a version: number. The engine tracks the last-applied version per
table in an internal _salve_schema_versions table and compares it against the schema's
declared version every time that schema is registered:
- First run — no stored version for the table yet. The engine creates the table from scratch, with every declared column, index, and reserved sync-metadata column.
- Version bump — the declared
versionis higher than the stored one. The engine diffs the declared columns against the table's actual columns and runsALTER TABLE ... ADD COLUMNfor anything missing. Columns markeduniqueget a companionCREATE UNIQUE INDEX IF NOT EXISTSright after, sinceADD COLUMNcan't carry aUNIQUEconstraint directly. - Same version — the engine still checks for reserved/internal columns the library itself may have added in a later release, so upgrading the package version is safe even without bumping your own schema version.
Only ADD COLUMN — no DROP/RENAME
The engine only ever adds columns. It never drops a column, renames a column, or changes a column's type. This is intentional, not a missing feature:
ADD COLUMNis always safe against data already on the device — there is no destructive path.DROP/RENAME COLUMNrequire a rebuild-and-copy in SQLite in general, which is riskier to run automatically against production data you don't control the timing of.
If you need to remove or rename a field, add the new column, migrate data in application code, and stop reading the old column — don't rely on the migration engine to drop it.
Bumping a schema version
export const CustomerSchema = {
name: "customers",
version: 2, // bumped from 1
primaryKey: "id",
columns: {
id: { type: "string" },
name: { type: "string" },
// new in v2
loyaltyTier: { type: "string", nullable: true },
},
};
Registering this schema (via Database.register({ schema: CustomerSchema })) against a
device that already has version 1 runs a single ALTER TABLE customers ADD COLUMN loyaltyTier TEXT and stores 2 as the new version for customers. A brand-new install
registering the same schema for the first time just creates the table with loyaltyTier
already present — there's no intermediate v1 state to pass through.
See Schemas for the full column/index/relation contract, and Architecture for where the Migration Engine sits in the native core.