CLI & base image to deploy React applications with docker containers.
- Configuration
- Command-line arguments
- Configuration file
- Lightweight nginx docker container
- CLI
- Runtime environment variable injection & validation
- Javascript
- HTML
- Hash file for cache invalidation
- Application initialization (
init/check)-
index.htmlfile modification -
Dockerfilegeneration - Schema generation
- Types generation
-
- Runtime environment variable injection & validation
- Support for serving at a path
- Vite
- Zod
- Example projects
- Cookbook for proxying the container with cloudflare
- Cookbook for handling "in-the-wild" chunks
- Research plugin possibilities with the supported tooling
- Server side rendering
The quickest way to set up a consuming project is the init command, which performs
most of this setup for you, paired with check, which validates it (and is CI-friendly):
# Scaffold env.schema.js, inject the window.env.js script tag, generate the
# Dockerfile + .dockerignore, and wire the npm scripts. Idempotent — safe to re-run.
npx docker-react init
# Validate that every setup step is complete (non-zero exit on any failure).
npx docker-react checkinit performs steps 2–6 below. Steps 1 (install dependencies) and 7 (replace env
references in your source) are advisory — init reports what's needed but never runs
npm or rewrites your code. check validates all seven steps. Pass --force to overwrite
files that have diverged, and --help to see the remaining flags.
The manual steps are documented below for reference and to show what init produces.
-
Install
docker-reactandzod(zod version should match the peer dependency version exactly)npm i -S docker-react zod@4.4.3
-
Create environment variable schema (
initscaffolds this for you; currently only Zod is supported, others may follow)The schema is loaded via dynamic
import(), so use whichever module syntax matches your project'spackage.json. CommonJS projects export withmodule.exports; ESM projects ("type": "module") useexport default. (initscaffolds the ESM form.)// env.schema.js (CommonJS) const { z } = require('zod'); module.exports = z.object({ VITE_API_URL: z.url(), });
// env.schema.js (ESM — "type": "module") import { z } from 'zod'; export default z.object({ VITE_API_URL: z.url(), });
-
Add env import to your
index.htmlhead (initinjects this for you, before</head>)<head> ... <script src="/window.env.js"></script> </head>
-
Create
Dockerfile(initgenerates this for you). NOTE thedocker-reactimage version must match your installed npm version of docker-react —initpins theFROMtag to it automatically.FROM demery/docker-react:vX.X.X COPY env.schema.js ./env.schema.js COPY dist /usr/share/nginx/html
When generated by
init, the build directory is auto-detected from your Vite config'sbuild.outDir(falling back todist); override it with--build-dir. -
Create
.dockerignore(initgenerates this for you)node_modules -
Update npm scripts (
initadds theinit-localscript and wires it intodev; pass--env-filefor thenode --env-filevariant){ "dev": "npm run init-local && vite", "init-local": "npx docker-react prep -s ./env.schema.js -d public" }Note if you are using a
.envfile the current recommended way is to use node directly.{ "init-local": "node --env-file=.env ./node_modules/.bin/docker-react prep -s ./env.schema.js -d public" }There is a pending feature request for npx commands to support loading .env files directly, once it's implemented these docs will be updated accordingly. npm/cli#7069
-
Replace all references to environment variables with
window.env, eg.process.env=>window.env(for create-react-app and others)import.meta.env=>window.env(for vite)
(Advisory:
initandcheckreport the locations of these references in yoursrc/but never rewrite your source — you make the replacements.)
Note: This instructions are to be performed in the consuming application.
# Perform a local production build (using whichever command)
npm run build
# Build a local image tagged with local
docker build -t my-app:local .
# Run local build using the env file
docker run -p 3000:80 --env-file=.env --name=my-app my-app:localThe app should now be available at http://localhost:3000
# Cleanup
docker rm my-app && docker image rm my-app:local