Skip to content
DevPlainly

Dockerfile Generator

Pick your framework (React, Angular, Vue, Next.js, NestJS, FastAPI, Django, Spring Boot, .NET, PHP and more) and a few options. You get a production-ready Dockerfile with the usual best practices already applied, and a .dockerignore to go with it.

# syntax=docker/dockerfile:1
# 1. Build the site
FROM node:24-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

# 2. Serve the built files with Nginx
FROM nginxinc/nginx-unprivileged:alpine
# Sends unknown paths to index.html, so client-side routes work on refresh
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 8080

What the generated Dockerfile does

  • Multi-stage build where it helps: the first stage has the compilers and dev dependencies, the final image only has what the app needs to run. Images end up several times smaller.
  • Dependencies before source code. The lockfile or requirements.txt is copied and installed first, so Docker reuses that layer until your dependencies change and rebuilds take seconds.
  • A non-root user. If someone breaks into the app, they don't get root inside the container. Node.js uses the built-in node user, Go uses a distroless nonroot image, .NET uses the image's app user, and frontends use the unprivileged Nginx image on port 8080.
  • Exec-form CMD (["node", "dist/index.js"]), so your app receives stop signals directly and shuts down cleanly.
  • An optional health check that Docker uses to mark the container unhealthy when the app stops answering.

React, Angular and Vue: why Nginx

A React, Angular, Vue or Svelte app is just HTML, CSS and JavaScript once it's built, so it doesn't need Node.js in production. The Dockerfile builds it with Node.js in a first stage and copies only the result into a small Nginx image. The extra nginx.conf sends every unknown path to index.html; without it, refreshing a page like /profile returns a 404 because that file doesn't exist on the server, only in the app's router.

Next.js and Nuxt are different: they render pages on the server, so their images run Node.js. For Next.js, add output: "standalone" to next.config first, which makes the image several times smaller.

Build and run it

docker build -t my-app .
docker run --rm -p 3000:3000 my-app

Change 3000 to your port. Frontends served by Nginx listen on 8080, and PHP on 80. To run it next to a database, the Docker Compose generator writes the compose file for you.

Why the .dockerignore matters

Everything in the folder is sent to Docker when you build. Without a .dockerignore, that includes node_modules, virtual environments, Git history and your .env file, which makes builds slower and can copy secrets into the image. Keep secrets out of images entirely; see how to use .env files safely.

Choosing a base image

The generator uses the official images: -alpine variants for Node.js, -slim for Python (Alpine can break Python packages that ship compiled wheels), distroless for Go, Temurin JRE for Java, Microsoft's ASP.NET runtime for .NET and php:apache for PHP. Pin the version you tested with, and update it on purpose rather than relying on latest.

Keep learning