Postgres
SQLite is the default because a store should run without provisioning anything, and for a small shop it is the right answer indefinitely. Move when one of these is true:
- You want more than one instance of the API. Two processes cannot share a SQLite file safely under load, and a volume attaches to one machine.
- The catalogue or order history outgrows what a single file on a small volume handles comfortably.
- Your platform offers managed Postgres with backups and you would rather not write the cron job yourself.
Switching
Section titled “Switching”DATABASE_URL=postgres://user:pass@host:5432/beluga npm run db:migrateMigrations for Postgres live in db/migrations/pg/ and run at boot exactly as the
SQLite ones do. A fresh Postgres database boots unconfigured, and the setup wizard
or npm run db:seed creates the administrator.
There is no SQLite-to-Postgres data migration tool. For a store with real orders, export them as CSV for your records, export the catalogue CSV, and import the catalogue into the new store. Stripe Products and Prices are untouched by any of this; republish and the existing Stripe objects are reused where the ids match.
What it unlocks
Section titled “What it unlocks”Sessions live in the database, and the background timers for webhook delivery and abandoned-cart reminders are guarded by conditional updates, so multiple API instances are safe on Postgres. Two ticks racing to send the same reminder cost one wasted query, never a duplicate email. Pair Postgres with a bucket for images and nothing in the deployment needs a disk. See the shape of a deployment.
Both engines are tested together
Section titled “Both engines are tested together”db/dialect.test.ts runs the same repository assertions against SQLite and
Postgres, the latter through embedded-postgres so no system install is needed.
If embedded-postgres cannot start, that half of the suite skips silently and
the run is still green. Confirm with:
npm test -- --reporter=verbose | grep "repository on postgres"Schema changes
Section titled “Schema changes”Both dialect files are edited together, then npm run db:generate emits a
migration for each. That is invariant 6; the
adding a field tutorial walks through it.