Script Valley
Node.js: The Complete Runtime
Databases, Testing, and DeploymentLesson 6.5

Deploying Node.js to production: Docker and cloud platforms

Dockerfile for Node.js, .dockerignore, multi-stage builds, non-root user, docker-compose, environment variables in Docker, graceful shutdown, Render deployment

A Production Dockerfile

Always use multi-stage Docker builds for Node.js โ€” the final image contains only production dependencies and the app code, not devDependencies or build tools.

FROM node:20-alpine AS base
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:20-alpine AS production
WORKDIR /app
COPY --from=base /app/node_modules ./node_modules
COPY . .
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
EXPOSE 3000
CMD ["node", "src/index.js"]

Graceful Shutdown

const server = app.listen(config.PORT);

async function shutdown() {
  logger.info('Shutting down gracefully...');
  server.close(async () => {
    await prisma.$disconnect();
    logger.info('Shutdown complete');
    process.exit(0);
  });
}

process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);

Deploy to Render

Push your Dockerfile to GitHub. On Render: New โ†’ Web Service โ†’ Connect repo โ†’ Runtime: Docker. Set environment variables in the dashboard. Render pulls the image, runs your container, and provides HTTPS automatically. For Railway the process is nearly identical โ€” connect the repo, set env vars, deploy.

Deploying Node.js to production: Docker and cloud platforms โ€” Databases, Testing, and Deployment โ€” Node.js: The Complete Runtime โ€” Script Valley โ€” Script Valley