"It works on my machine" and "it is production-ready" are very different statements. Here is the checklist I worked through to take an Express + Prisma + MySQL API from the first to the second — using this very portfolio backend as the guinea pig.
1. Real migrations, not db push
prisma db push is great for prototyping and dangerous in production — there is no history and no safe rollback. The fix is committed migrations applied on deploy:
npx prisma migrate dev --name init # generate + commit
npx prisma migrate deploy # run on startup (never prompts)
If the database already has tables but no migration history you will hit P3005. Baseline it once by marking the migration as already applied, then deploys are clean forever after.
2. Graceful shutdown
Containers get SIGTERM on every redeploy. Without handling it you drop in-flight requests and leak database connections. Close the server, then disconnect Prisma:
process.on('SIGTERM', async () => {
server.close(async () => {
await prisma.$disconnect();
process.exit(0);
});
});
3. Map errors to real status codes
A blanket 500 tells the client nothing. A small helper maps known Prisma errors — unique violation to 409 , record-not-found to 404 — and keeps the raw error server-side only.
4. Liveness vs readiness
Two different questions. /health answers "is the process up?" cheaply. /health/ready answers "can I serve traffic?" by actually pinging the database with SELECT 1 — that is what your load balancer should probe.
5. Config and secrets
- Fail fast at startup if a required secret like JWT_SECRET is missing.
- Never ship a hardcoded admin password — seed a random one and print it once.
- Keep .env out of git; commit a .env.example template instead.
6. A lean Docker image
A multi-stage build compiles TypeScript in a builder stage and ships only the runtime deps and compiled output, running as a non-root user. Migrations run as the first thing the container does on boot.
None of this is exciting, and that is the point. Production-ready means boring, predictable and observable.
Top comments (0)