Dockerfile for Node.js: example and generator
A small, working Dockerfile for a Node.js app, with build step, non-root user and health check options.
A Dockerfile is a recipe that packs your app and everything it needs into an image. Fill in your Node version, port and start file below, save the result as Dockerfile in your project folder, then build and run it.
Create your config file
Type your own values. The file below updates as you type, and nothing you type leaves your browser.
FROM node:24-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
ENV NODE_ENV=production
USER node
EXPOSE 3000
CMD ["node", "server.js"]How this setup works
Step-by-step setup
- Save the file above as Dockerfile (no extension) in your project folder, next to package.json.
- Create a file named .dockerignore with the lines node_modules and .git, so they are not copied into the image.
- Build the image: docker build -t myapp .
- Run it: docker run -p 3000:3000 myapp.
- Open http://localhost:3000 in your browser.
What the important lines mean
- FROM node:24-alpine picks the base image with Node 24 already installed.
- npm ci installs the exact versions in package-lock.json. It fails if that file is missing.
- EXPOSE 3000 only documents the port. You still need -p when you run the container.
- CMD is the command that starts your app when the container runs.
Common errors and how to fix them
- npm error The npm ci command can only install with an existing package-lock.json
- The lock file is missing or was not copied. Run npm install once on your machine and commit package-lock.json, or change npm ci to npm install.
- Error: Cannot find module '/app/server.js'
- The start file name or path is wrong, or the file was never copied. Check the name, and make sure .dockerignore does not exclude it.
- The container runs but the browser cannot connect
- Your app must listen on 0.0.0.0, not only 127.0.0.1, and you must publish the port with -p 3000:3000.
- sh: tsc: not found, or the build fails
- The build tools are dev dependencies, which are skipped by default. Tick the build step option above so they are installed first.
- npm error gyp ERR! or a native module fails on Alpine
- Some packages need tools that Alpine lacks. Switch the image type to Slim.
Frequently asked questions
- Should I use Alpine or Slim?
- Alpine gives the smallest image. Slim is based on Debian and works with more native packages. If an install fails on Alpine, try Slim.
- Why use npm ci instead of npm install?
- npm ci installs exactly what the lock file says and stops if it does not match, so every build gives the same result.
- Do I need EXPOSE?
- No. The app works without it. EXPOSE just documents the port. What actually opens the port to your computer is the -p option on docker run.
Free tools that help
- Common ports listSearch a list of common TCP and UDP port numbers: SSH 22, HTTP 80, HTTPS 443, MySQL 3306, PostgreSQL 5432 and more, with dev server ports.
Fix a problem with this setup
- Node EADDRINUSEFix EADDRINUSE in Node, Express, Next.js and Vite: find the program using the port, stop it, or start on another port.
- Docker port already allocatedFix "port is already allocated" in Docker and Docker Compose: find the container or program that holds the port and free it.
- Docker container cannot reach localhostFix "connection refused" when an app in Docker calls localhost: use host.docker.internal, a Compose service name or host networking.
More container configs
- Dockerfile for PythonA working Dockerfile for a Python web app, with Gunicorn, Uvicorn or a plain script.
- Docker Compose for MailpitRun a fake mail server on your computer, so test emails from your app show up in a web page instead of being sent.
- Kubernetes Deployment and ServiceA Deployment and Service YAML for your container image, with replicas, port, resource limits and health checks.
- Docker Compose for MySQL and phpMyAdminRun MySQL and the phpMyAdmin web page on your computer with one docker compose command.
- Docker Compose for PostgreSQL and pgAdminRun PostgreSQL and the pgAdmin web page on your computer with one docker compose command.
- docker-compose for MongoDBRun a local MongoDB database with a password that keeps its data.