Skip to content

Scaffolded app ships no initial migration — first deploy against an empty database creates no schema #4958

Description

@michaelbromley

Problem

A fresh app created with @vendure/create ships with dbConnectionOptions.synchronize: false and a migrations glob, but no migration files. As a result, the first deployment against a fresh/empty production database creates no tables — the schema is never built, and nothing in the flow explains why.

This is currently masked during local development because @vendure/create force-sets synchronize: true while populating the seed data, so the local schema is created by synchronize, not by a migration. The gap therefore only surfaces on the first real deployment, where nothing turns synchronize on.

The manual workaround — temporarily enabling synchronize: true for the first deploy, or hand-generating an initial migration against a throwaway empty database — is not something a first-time user would know to do, and synchronize: true is not acceptable for production.

Root cause

generateMigration() produces a migration by diffing the entity metadata against whatever database is currently connected (TypeORM's SchemaBuilder.log()):

  • against an empty database → the diff is the full schema (exactly the "initial migration" we want);
  • against a populated database → the diff is empty, so no migration can be generated.

So once the local database has been built (via synchronize), there is no straightforward way to bootstrap the initial migration — you'd need to point at an empty database of the same dialect.

Proposed solution

Two complementary changes:

1. Generate an initial migration at scaffold time (@vendure/create)

At scaffold time the configured database is genuinely empty, so a plain generateMigration({ name: 'init' }) yields the complete baseline. The scaffold then runs that migration to build the schema and populates with synchronize: false. Result: every new project ships with a schema-creating migration from day one, the first deployment builds its schema via migrations, and local dev matches production (no synchronize).

2. Add a shadow-database baseline mode to the CLI

vendure migrate --generate <name> --from-empty — generate a complete "zero to current schema" baseline even when the configured database is already populated, by diffing against a freshly-provisioned, disposable empty database of the same dialect (the approach used by Prisma's shadow DB and Atlas's dev DB). For Postgres/MySQL this creates and drops a temporary database on the same server; for SQLite it uses an in-memory database. This covers CI, regeneration, and scaffold paths where no empty database is available at generate time.

Prototype status

A working prototype exists for both parts (in @vendure/core, the CLI, and @vendure/create) and has been verified against Postgres 16 and better-sqlite3:

Scenario Result
--from-empty against an empty Postgres full baseline (87 CREATE TABLE + 260 ALTER TABLE)
plain generate against a populated DB "No changes found" — reproduces the bug
--from-empty against a populated DB full baseline anyway
shadow DB lifecycle created and dropped, no leaks, target DB untouched
scaffold path (generate → runMigrations → populate) 88 tables created and recorded in the migrations table
SQLite --from-empty (in-memory) full baseline, real db file untouched

Remaining work

  • Productionize the @vendure/create change (generate + run init migration, drop synchronize: true)
  • Productionize vendure migrate --generate <name> --from-empty (core shadow-DB provisioning + CLI flag)
  • e2e coverage for the shadow-DB path on Postgres and MySQL/MariaDB
  • Handle scaffold paths with no live DB at generate time (e.g. bring-your-own-DB, sql.js) by falling back to --from-empty
  • Clear, actionable error when the database user lacks CREATE DATABASE privilege
  • Fix a latent bug found along the way: resetConfig() reloads the default config via a synchronous require() of an extensionless module path, so generateMigration() cannot run under the vitest/SWC runtime without a mock
  • Docs for the new flag and the updated scaffold behaviour

Metadata

Metadata

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions