You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The generated multi-stage Dockerfile ends its build stage with pnpm prune --prod, so both images a generated project can produce lack dev tooling: target: build has drizzle-kit/tsx pruned away, and the production stage never had them. There is consequently no way to run database migrations inside the containers a generated project ships — pnpm db:migrate (drizzle-kit) only works on a developer machine with dev dependencies installed.
Discovered while wiring the blog example's compose stack (#121): a migrate one-shot service pointed at target: build failed with Command "drizzle-kit" not found (exit 254), and tsx: not found for the seed.
Why
The generated docker-compose.yml orchestrates API + PostgreSQL, but a fresh docker compose up serves the API against an empty, unmigrated database (the health check reports degraded). The Railway and Fly.io READMEs work around the same gap by running migrations from the host (railway run pnpm db:migrate, fly mpg proxy); the node/docker path has no in-container story at all.
examples/blog-api-node ships the solution: a compiled programmatic runner (src/db/migrate.ts, using drizzle-orm/postgres-js/migrator — a runtime dependency) executed as node dist/db/migrate.js by a one-shot compose service inside the same production image as the API. One image, no dev tooling in containers, API start gated on service_completed_successfully. The same pattern would also unlock Fly.io's release_command (currently ruled out in the generated Fly README precisely because the production image prunes drizzle-kit).
Acceptance Criteria
Add a src/db/migrate.ts snippet (e.g. templates/snippets/shared/src/db/) and have setup-project.sh copy it for the node, railway, and fly targets; it must compile into dist/ with the regular pnpm build
templates/node-server/docker-compose.yml gains the one-shot migrate service (same production image via a shared image: tag); api depends on migrate: service_completed_successfully
Production image continues to copy src/db/migrations (journal + SQL available at runtime — already the case)
Snippets type-check in the typecheck-templates CI job and freshly generated projects still pass the generated-projects job
Railway/Fly generated READMEs updated to mention the in-image migrator (e.g. Fly release_command = "node dist/db/migrate.js") as an alternative to host-side migration
deployment-config-generator skill and docs updated where they describe the compose/migration story
CI passes
Resources
examples/blog-api-node/api/src/db/migrate.ts — working implementation
Description
The generated multi-stage Dockerfile ends its build stage with
pnpm prune --prod, so both images a generated project can produce lack dev tooling:target: buildhas drizzle-kit/tsx pruned away, and the production stage never had them. There is consequently no way to run database migrations inside the containers a generated project ships —pnpm db:migrate(drizzle-kit) only works on a developer machine with dev dependencies installed.Discovered while wiring the blog example's compose stack (#121): a
migrateone-shot service pointed attarget: buildfailed withCommand "drizzle-kit" not found(exit 254), andtsx: not foundfor the seed.Why
The generated
docker-compose.ymlorchestrates API + PostgreSQL, but a freshdocker compose upserves the API against an empty, unmigrated database (the health check reports degraded). The Railway and Fly.io READMEs work around the same gap by running migrations from the host (railway run pnpm db:migrate,fly mpg proxy); the node/docker path has no in-container story at all.examples/blog-api-nodeships the solution: a compiled programmatic runner (src/db/migrate.ts, usingdrizzle-orm/postgres-js/migrator— a runtime dependency) executed asnode dist/db/migrate.jsby a one-shot compose service inside the same production image as the API. One image, no dev tooling in containers, API start gated onservice_completed_successfully. The same pattern would also unlock Fly.io'srelease_command(currently ruled out in the generated Fly README precisely because the production image prunes drizzle-kit).Acceptance Criteria
src/db/migrate.tssnippet (e.g.templates/snippets/shared/src/db/) and havesetup-project.shcopy it for the node, railway, and fly targets; it must compile intodist/with the regularpnpm buildtemplates/node-server/docker-compose.ymlgains the one-shotmigrateservice (same production image via a sharedimage:tag);apidepends onmigrate: service_completed_successfullysrc/db/migrations(journal + SQL available at runtime — already the case)typecheck-templatesCI job and freshly generated projects still pass thegenerated-projectsjobrelease_command = "node dist/db/migrate.js") as an alternative to host-side migrationdeployment-config-generatorskill and docs updated where they describe the compose/migration storyResources
examples/blog-api-node/api/src/db/migrate.ts— working implementationexamples/blog-api-node/api/docker-compose.yml— migrate service wiring (image sharing, dependency gating, in-container seed command)templates/node-server/Dockerfile— build-stagepnpm prune --prod(whytarget: buildhas no dev deps)