Contents
Docker init tutorial: Generate a Dockerfile and compose.yaml automatically
For beginners, the hardest part of writing a Dockerfile is knowing where to start. docker init detects your project's language, asks a few questions, and then generates a set of Docker files you can run right away. In this section, we test the full process with the Express project from Node.js applications and inspect the generated files line by line.
docker initis a plugin included with Docker Desktop. Linux hosts with only Docker Engine installed do not have this command, but the generated files work anywhere.
Prepare the project
The init-demo folder contains only three files and no Docker-related files yet:
init-demo/
├── package.json
├── package-lock.json
└── server.js
server.js is an Express app that listens on port 3000. Its contents are the same as in Node.js applications.
Run docker init
Run this command in the project folder:
$ docker init
Welcome to the Docker Init CLI!
This utility will walk you through creating the following files with sensible defaults for your project:
- .dockerignore
- Dockerfile
- compose.yaml
- README.Docker.md
Let's get started!
? What application platform does your project use? [Use arrows to move, type to filter]
> Node - (detected) suitable for a Node server application
Go - suitable for a Go server application
Python - suitable for a Python server application
Rust - suitable for a Rust server application
ASP.NET Core - suitable for an ASP.NET Core application
PHP with Apache - suitable for a PHP web application
Java - suitable for a Java application that uses Maven and packages as an uber jar
Other - general purpose starting point for containerizing your application
Don't see something you need? Let us know!
Quit
docker init finds package.json, marks Node as (detected), and selects it. Use the arrow keys to choose an option, then press Enter to confirm. Next, it asks these questions in order:
? What application platform does your project use? Node
? What version of Node do you want to use? 24
? Which package manager do you want to use? npm
? What command do you want to use to start the app? npm start
? What port does your server listen on? 3000
✔ Created → .dockerignore
✔ Created → Dockerfile
✔ Created → compose.yaml
✔ Created → README.Docker.md
→ Your Docker files are ready!
Review your Docker files and tailor them to your application.
Consult README.Docker.md for information about using the generated files.
What's next?
Start your application by running → docker compose up --build
Your application will be available at http://localhost:3000
| Question | Answer in this example | Notes |
|---|---|---|
| application platform | Node | package.json was detected, so press Enter |
| version of Node | 24 | No default; you must enter a value, or you'll see Value is required |
| package manager | npm | package-lock.json was detected, so npm is the default |
| command to start the app | npm start | The default comes from scripts.start in package.json |
| port | 3000 | The port the app listens on; there is no default |
If you press Enter without entering a Node version, you'll see:
? What application platform does your project use? Node
X Sorry, your reply was invalid: Value is required
? What version of Node do you want to use?
If the project has an
.nvmrcfile orengines.nodeinpackage.json,docker inituses it as the default.
It generates four files: .dockerignore, Dockerfile, compose.yaml, and README.Docker.md.
The generated Dockerfile
Here is the content with the explanatory comments removed (the original file has English comments throughout):
# syntax=docker/dockerfile:1
ARG NODE_VERSION=24
FROM node:${NODE_VERSION}-alpine
# Use production node environment by default.
ENV NODE_ENV production
WORKDIR /usr/src/app
RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=package-lock.json,target=package-lock.json \
--mount=type=cache,target=/root/.npm \
npm ci --omit=dev
USER node
COPY . .
EXPOSE 3000
CMD npm start
| Syntax | Purpose |
|---|---|
# syntax=docker/dockerfile:1 | Use the latest Dockerfile syntax version (Docker downloads docker/dockerfile:1 before building) |
ARG NODE_VERSION=24 | Store the version in a variable so you can change it with --build-arg NODE_VERSION=22 |
--mount=type=bind,source=package.json | Mount package.json directly during the build instead of using COPY, saving an image layer |
--mount=type=cache,target=/root/.npm | Share npm's download cache across builds without adding it to the image |
npm ci --omit=dev | Install production dependencies only |
USER node | Run as a non-root user |
Overall, this follows the best practices covered in Node.js applications.
Check with docker build --check
docker build --check checks Dockerfile syntax without building the image. Run it on the generated Dockerfile:
$ docker build --check .
#0 building with "default" instance using docker driver
#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 1.20kB done
#1 DONE 0.0s
#2 resolve image config for docker-image://docker.io/docker/dockerfile:1
#2 DONE 0.2s
#3 docker-image://docker.io/docker/dockerfile:1@sha256:4edf897a3ffa55b89f906fc8cc78afdb3f1834cc9c7083565e611a8a7d5fe99e
#3 resolve docker.io/docker/dockerfile:1@sha256:4edf897a3ffa55b89f906fc8cc78afdb3f1834cc9c7083565e611a8a7d5fe99e done
#3 CACHED
#4 [internal] load metadata for docker.io/library/node:24-alpine
#4 DONE 0.2s
#5 [internal] load .dockerignore
#5 transferring context: 663B done
#5 DONE 0.0s
Check complete, 2 warnings have been found!
WARNING: LegacyKeyValueFormat - https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/
"ENV key=value" should be used instead of legacy "ENV key value" format
Dockerfile:14
--------------------
12 |
13 | # Use production node environment by default.
14 | >>> ENV NODE_ENV production
15 |
16 |
--------------------
WARNING: JSONArgsRecommended - https://docs.docker.com/go/dockerfile/rule/json-args-recommended/
JSON arguments recommended for CMD to prevent unintended behavior related to OS signals
Dockerfile:38
--------------------
36 |
37 | # Run the application.
38 | >>> CMD npm start
39 |
--------------------
The template has two warnings:
- LegacyKeyValueFormat:
ENV NODE_ENV productionuses the old syntax. Change it toENV NODE_ENV=production. - JSONArgsRecommended:
CMD npm startuses shell form. JSON array form is recommended to avoid possible issues forwarding stop signals. See Dockerfile instructions for details.
Change these two lines:
ENV NODE_ENV=production
CMD ["node", "server.js"]
The CMD also runs node directly, removing an npm process. See the test in Node.js applications for why. Adding docker build --check to your CI workflow is a good way to catch syntax issues before building.
The generated compose.yaml
After removing the comments, only a few lines remain:
services:
server:
build:
context: .
environment:
NODE_ENV: production
ports:
- 3000:3000
The lower half of the original file is a large commented-out PostgreSQL example. If you uncomment it, keep two issues in mind:
# db:
# image: postgres
# ...
# volumes:
# - db-data:/var/lib/postgresql/data
# ...
# healthcheck:
# test: [ "CMD", "pg_isready" ]
image: postgresdoes not specify a version, so it currently pulls version 18. Version 18 requires the volume to be mounted at/var/lib/postgresql. Mounting it at/var/lib/postgresql/datawill cause startup to fail. See PostgreSQL.pg_isreadydoes not include-h 127.0.0.1, so the database may be reported as healthy before initialization is complete.
.dockerignore and README.Docker.md
The generated .dockerignore excludes common files that are not needed, including **/node_modules, **/.env, **/.git, **/Dockerfile*, and **/compose.y*ml. It is more complete than the version you wrote by hand earlier in this tutorial, so you can use it as-is.
README.Docker.md is a brief guide in English. It explains how to start the app with docker compose up --build and notes building for different CPU architectures (see Multi-platform images).
Start the app
Follow the prompt and run docker compose up --build. Here, add -d to run it in the background, then check the results:
$ docker compose up -d --build
[+] Building 15.1s (13/13) FINISHED
=> [internal] load local bake definitions 0.0s
=> => reading from stdin 486B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 1.20kB 0.0s
=> resolve image config for docker-image://docker.io/docker/dockerfile:1 1.1s
=> docker-image://docker.io/docker/dockerfile:1@sha256:4edf897a3ffa55b89f906fc8cc78afdb3f1834cc9c7083565e611a8a7d5fe99e 3.9s
=> => resolve docker.io/docker/dockerfile:1@sha256:4edf897a3ffa55b89f906fc8cc78afdb3f1834cc9c7083565e611a8a7d5fe99e 0.0s
=> => sha256:9d2b4f57f9e20f33279375ce25c6ff14f30f64270ed5c7b613b2b30256754f62 14.28MB / 14.28MB 3.5s
=> => extracting sha256:9d2b4f57f9e20f33279375ce25c6ff14f30f64270ed5c7b613b2b30256754f62 0.4s
=> [internal] load metadata for docker.io/library/node:24-alpine 0.9s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 663B 0.0s
=> [stage-0 1/4] FROM docker.io/library/node:24-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 3.2s
=> => resolve docker.io/library/node:24-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1 0.0s
=> => extracting sha256:e2de96513ba9eb53b431787ec8a65cdde380ac4772a3e4c4b714dcfde2a102b5 0.2s
=> => sha256:02f40d53b06f6b91fec0cd6a6719656da99270bff8ee54ed8dcdf4c157763fc1 1.26MB / 1.26MB 0.8s
=> => sha256:7ce7dcbafb7f750cf0c6be3c30e34372b06dd1182fa67f6ae30782c8150c5444 444B / 444B 0.2s
=> => sha256:3c504d5a797be28f9de43147d49cd8ecb2eea46dfaf7beb8715db695d5f0a7f0 56.52MB / 56.52MB 1.1s
=> => extracting sha256:3c504d5a797be28f9de43147d49cd8ecb2eea46dfaf7beb8715db695d5f0a7f0 1.9s
=> => extracting sha256:02f40d53b06f6b91fec0cd6a6719656da99270bff8ee54ed8dcdf4c157763fc1 0.1s
=> => extracting sha256:7ce7dcbafb7f750cf0c6be3c30e34372b06dd1182fa67f6ae30782c8150c5444 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 31.23kB 0.0s
=> [stage-0 2/4] WORKDIR /usr/src/app 0.1s
=> [stage-0 3/4] RUN --mount=type=bind,source=package.json,target=package.json --mount=type=bind,source=package-lock.json,target=package-l 2.6s
=> [stage-0 4/4] COPY . . 0.0s
=> exporting to image 2.7s
=> => exporting layers 0.3s
=> => exporting manifest sha256:1278071dc9c5842ea834d9abc8c01262b999118ef6903ed4998b8cc8ccc5aaba 0.0s
=> => exporting config sha256:879a23594d9f079707b7b35c022fb427cebaaa18db9701eb78b1fbaf82efed06 0.0s
=> => exporting attestation manifest sha256:012342031ad01079856bb6ebf257f096c2d8f9ff12d448ed86a58a645d64bb5d 0.0s
=> => exporting manifest list sha256:19aee69cf5d970c251d176f2f533bb918f9e72edf675b109b569ae2ff25cb4f3 0.0s
=> => naming to docker.io/library/init-demo-server:latest 0.0s
=> => unpacking to docker.io/library/init-demo-server:latest 2.3s
=> resolving provenance for metadata file 0.0s
[+] up 3/3
✔ Image init-demo-server Built 15.2s
✔ Network init-demo_default Created 0.0s
✔ Container init-demo-server-1 Started 0.4s
$ curl -s http://localhost:3000
{"message":"Hello from Express","node":"v24.21.0"}
$ docker compose exec server ps
PID USER TIME COMMAND
1 node 0:00 npm start
18 node 0:00 {MainThread} node server.js
25 node 0:00 ps
$ time docker compose stop
Container init-demo-server-1 Stopping
Container init-demo-server-1 Stopped
real 0m 0.21s
user 0m 0.04s
sys 0m 0.02s
$ docker compose logs server
server-1 |
server-1 | > express-app@1.0.0 start
server-1 | > node server.js
server-1 |
server-1 | Listening on port 3000
server-1 | SIGTERM received, closing server
server-1 | npm notice
server-1 | npm notice New major version of npm available! 11.19.0 -> 12.2.0
server-1 | npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.2.0
server-1 | npm notice To update run: npm install -g npm@12.2.0
server-1 | npm notice
- The first build step downloads
docker/dockerfile:1, which is caused by the# syntax=line. - The service is named
server, and the app responds successfully. psshows that PID 1 isnpm startand node is its child process.docker compose stopfinishes in 0.21 seconds, and npm forwards the stop signal to node.
When to use docker init
- A new project, and you're unfamiliar with Dockerfiles: Generate a starting point, then understand and edit it line by line alongside this tutorial.
- A project that already has a Dockerfile: Generate another copy in a separate folder and use it as a reference (for example, for cache mounts).
- What it won't do: It won't handle database migrations, environment variables, HTTPS, or the details of multi-stage builds for you. The generated files are only a starting point.
Recap
docker initdetects your project's language, asks a few questions, and generates aDockerfile,compose.yaml,.dockerignore, andREADME.Docker.md.- The Node version and port have no defaults; you must enter them.
- The generated Dockerfile uses BuildKit bind and cache mounts. The approach is good, but it still triggers warnings about old syntax.
- Use
docker build --checkto check any Dockerfile. - The commented-out PostgreSQL example in the template needs changes to work with
postgres:18.
Exercises
Exercise 1: Run docker build --check . on a Dockerfile you've written (for example, the one in Dockerfile basics) and see whether it produces warnings.
Hint
If there are no issues, it displays Check complete, no warnings found.. The most common warnings are JSONArgsRecommended (shell form used for CMD or ENTRYPOINT) and LegacyKeyValueFormat (ENV used without =).
Exercise 2: Change the Node version in the generated Dockerfile to 22 without editing the file.
Answer
NODE_VERSION is an ARG, so pass it in at build time:
docker build --build-arg NODE_VERSION=22 -t init-demo:node22 .
In Compose, set it under build.args:
services:
server:
build:
context: .
args:
NODE_VERSION: "22"
Exercise 3: Follow the instructions in this chapter to fix the ENV and CMD lines. Then run docker build --check . again and confirm the warnings are gone.
FAQ
Can I use docker init with Docker Engine on Linux?
docker init is a CLI plugin included with Docker Desktop (available on Windows, macOS, and Linux). Linux hosts with only Docker Engine installed do not have this command by default, so running it displays docker: unknown command: docker init.
Can I run docker init in a project that already has a Dockerfile?
Yes, but it will ask whether to overwrite existing files. Commit your work to Git first, or try it in another folder so you can compare the generated files before deciding whether to use them.
Which languages does docker init support?
In v1.4.0, the menu includes Node, Go, Python, Rust, ASP.NET Core, PHP with Apache, Java, and the general-purpose Other option. It detects files in your project (such as package.json) and selects defaults automatically.
Can I use the generated files in production as-is?
They make a good starting point, but review them yourself. For example, the template tested in this chapter uses the outdated ENV key value syntax and shell-form CMD, which docker build --check warns about. The commented-out PostgreSQL example in the template also does not work with postgres:18.
Updated October 13, 2026