Schema: api/src/db/schema.ts
Migrations: api/drizzle/
Config: api/drizzle.config.ts
pnpm db:push # Push schema directly to local DB (dev only)
pnpm db:generate # Generate a migration file from schema changes
pnpm db:migrate # Apply migration files to database (dev)
pnpm db:studio # Open Drizzle Studio at https://local.drizzle.studioUse db:push to experiment freely, then db:generate once you're happy with the result.
db:push syncs your schema.ts directly to your local database — no migration files, no history.
# Edit schema.ts, then push
pnpm db:pushOnce the schema is final, generate a migration:
pnpm db:generate
# or with a custom name:
pnpm db:generate -- --name add-user-rolesThis diffs schema.ts against the last snapshot and creates one clean SQL file with only the net changes.
cat api/drizzle/0001_*.sql
git add api/drizzle/
git commit -m "migration: add project description column"After db:generate, you do NOT need to run db:migrate locally — your database is already up to date from db:push. The migration file is for production and fresh setups.
If you generated a migration you don't want (before deploying):
- Delete the SQL file (e.g.,
api/drizzle/0001_*.sql) - Delete its snapshot (e.g.,
api/drizzle/meta/0001_snapshot.json) - Remove its entry from
api/drizzle/meta/_journal.json
docker compose down -v # removes postgres volume
docker compose up postgres -d # fresh database
pnpm db:push # apply current schemaMigrations run automatically at container startup via node dist/migrate.js && node dist/index.js. If migrations fail, the server won't start.
The migrator reads SQL files from api/drizzle/, checks __drizzle_migrations for what's already applied, and runs only new ones.
The production image uses node dist/migrate.js (runtime), NOT drizzle-kit migrate (dev dependency).
Can't connect: Check DATABASE_URL in api/.env, ensure postgres is running (docker compose up postgres -d).
Migration files not found: Run commands from the project root. Check api/drizzle/ exists.