elefcode

Dockerfile Generator

Multi-stage Dockerfiles for Node, Next.js, SPAs, Python and Go — small images, cached builds, non-root users — plus a .dockerignore.

Stack
Base image
Package manager
Build & run
Hardening
# syntax=docker/dockerfile:1

FROM node:24-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci

FROM node:24-slim AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:24-slim AS prod-deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci --omit=dev

FROM node:24-slim AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=prod-deps /app/node_modules ./node_modules
COPY package.json ./
COPY --from=build /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]

Build with docker build -t my-app . and run with docker run -p 8080:3000 my-app

  • RUN --mount=type=cache needs BuildKit, which is the default from Docker 23. Build with docker build -t app .

Advertisement

Guide

About the Dockerfile Generator

A Dockerfile is the recipe Docker follows to build an image. A multi-stage Dockerfile uses one stage with compilers and dev dependencies to build the app, then copies only the result into a clean, small runtime stage, so build tools and source never ship to production.

Choose your stack and the generator orders the steps so dependency installs are cached and re-run only when your lockfile changes.

Why copy the lockfile first

Docker caches each step and reuses it until something it depends on changes. Copying only package.json and the lockfile before installing means an edit to your code does not bust the install layer, and rebuilds take seconds instead of minutes.

Keep secrets out of the image

Every file you COPY stays in the image’s layers, even if a later step deletes it. The .dockerignore excludes .env files and Git history, and runtime secrets should come from environment variables or your platform’s secret store when the container starts.

How to use it

  1. 1Pick your stack and runtime version.
  2. 2Set the build script, output folder and entry point.
  3. 3Choose a non-root user and health check.
  4. 4Download both files into your project root and run docker build.

Frequently asked questions

Alpine or slim?

Alpine images are smaller, but use musl instead of glibc, which can break native Node modules and Python wheels. Debian slim is a safe default; switch to Alpine if your dependencies are pure JavaScript.

How do I dockerize a Next.js app?

Pick Next.js and add output: "standalone" to next.config. The build writes a self-contained server.js, and the image copies just that, the static assets and the public folder.

Why does the SPA image use nginx?

A built React or Vue app is only static files. nginx serves them efficiently, and the generated config falls back to index.html so client-side routes work on reload.

What is distroless?

Google’s distroless images contain only what a program needs to run, with no shell or package manager. A static Go binary on distroless makes an image of a few megabytes with very little to attack.

Why run as a non-root user?

If an attacker breaks into the app, a non-root process cannot change system files in the container, and container escapes are much harder.

What does RUN --mount=type=cache do?

It gives the package manager a persistent cache folder between builds, outside the image. Downloads are reused across builds without making the image any bigger.

Related tools