Dockerfile Builder for React Static Site (Nginx)

Build and serve a React app in a single Nginx-based Dockerfile

Generate a multi-stage Dockerfile that builds a React, Vite, or Create React App project with Node and serves the static output through a minimal Nginx image, plus a matching nginx.conf with SPA routing. Runs entirely in your browser.

Why serve a React app with Nginx instead of Node?

A built React app is just static HTML, CSS, and JavaScript — there is no server-side rendering to do. Nginx serves static files faster and with a far smaller memory footprint than a Node process, and the runtime image contains no Node, no npm, and no source code.

A Dockerfile builder for static React sites that emits a multi-stage Dockerfile: one stage builds your app with Node, and a second tiny stage serves the compiled output with Nginx. It also generates a matching nginx.conf with sensible caching headers and optional single-page-app routing.

How it works

The build stage uses node:<version>-alpine. It copies package.json and your lockfile first and runs a clean install (npm ci, yarn install --frozen-lockfile, or pnpm install --frozen-lockfile) so dependencies are cached independently of your source. It then copies the rest of the project and runs your build script, producing static assets in dist, build, or out.

The runtime stage starts from nginx:alpine, copies only the built assets into /usr/share/nginx/html, and copies the generated nginx.conf over the default config. That config sets a one-year immutable cache on hashed assets and, when SPA fallback is on, uses try_files $uri $uri/ /index.html; so any unmatched route is handed to your client-side router instead of returning a 404.

Tips and notes

  • Add a .dockerignore with node_modules, .git, and dist so the build context is small and the dependency cache is not invalidated by stale local builds.
  • If your app reads runtime configuration, remember the bundle is built at image build time — environment variables baked in then cannot change without rebuilding. Use a runtime config file or an entrypoint that templates one instead.
  • The included HEALTHCHECK does a simple HTTP GET of /; orchestrators use it to know the container is serving before sending traffic.
  • Hashed asset filenames (app.4f3c1.js) are safe to cache for a year because a new build produces a new filename — never long-cache index.html itself.