Skip to content
Agentmart
Submit a tool

dockerfile-frontend

Multi-stage Dockerfile patterns for React/Vite/TypeScript frontends — node:alpine build, lockfile caching, build-time VITE_* vars, nginx SPA fallback…

Skill by ajyadav013

IndexedMIT★ 14
Write a review

Chalk Labs

Need help deploying dockerfile-frontend?

Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.

Book a call

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/ajyadav013-dockerfile-frontend

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Multi-stage Dockerfile patterns for React/Vite/TypeScript frontends — node:alpine build, lockfile caching, build-time VITE_* vars, nginx SPA fallback, envsubst config. Use when containerizing static frontends.

Use cases: frontend, agent-building

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/dockerfile-frontend

What's inside

Skill name
dockerfile-frontend
Description
Multi-stage Dockerfile patterns for React/Vite/TypeScript frontends — node:alpine build, lockfile caching, build-time VITE_* vars, nginx SPA fallback, envsubst config. Use when containerizing static frontends.
License
MIT
Instructions
299 lines in SKILL.md · view on GitHub

Files (4)

  • SKILL.md
  • build-args-and-nginx.md · references/
  • frontend-dockerfile-anatomy.md · references/
  • repo-evidence.md · references/

SKILL.md (first lines)

# Dockerfile for Frontend Applications

Multi-stage Dockerfile patterns for building and serving React/Vite/TypeScript frontend applications with nginx or Node.js static servers.

## When to use

- Containerizing Vite, React, Next.js, or other Node.js-based frontend applications
- Building production-optimized static bundles in Docker
- Implementing build-time configuration via VITE_* or REACT_APP_* env vars
- Setting up nginx to serve SPAs with history API fallback routing
- Configuring runtime environment variables (backend URLs) via envsubst
- Deploying frontend containers to Kubernetes, Cloud Run, or container platforms
- Reverse-proxying API calls from frontend nginx to backend services

## Core conventions

### Multi-Stage Build: Node.js Build + Nginx Runtime

**Build stage (node:alpine)**: Use `node:20-alpine` or `node:22-alpine` for the build stage; install dependencies with lockfile-first caching (`COPY package.json package-lock.json* ./` then `npm ci`), then build the static bundle (`npm run build` or `npx vite build`).

**Runtime stage (nginx:alpine)**: Use `nginx:alpine` for the runtime stage; copy only the built `dist/` directory from the build stage to `/usr/share/nginx/html`. The final image contains no source code, no node_modules, only static files.

**Why**: Multi-stage builds keep the runtime image minimal (nginx:alpine ≈ 40MB vs node:alpine ≈ 180MB); faster deploys, smaller attack surface, lower storage costs.

**Alternative runtime (node server)**: Some projects use a lightweight Node.js static server (e.g., `node server.cjs` serving `./dist`) instead of nginx; useful when you need server-side logic or prefer a single-language stack.

### Lockfile-First Dependency Caching

**Pattern**: `COPY package.json package-lock.json* ./` (or `pnpm-lock.yaml` / `yarn.lock`) before `COPY . .`; run `npm ci` (or `pnpm install --frozen-lockfile` / `yarn install --frozen-lockfile`) immediately after.

**Why**: Docker layer caching reuses the `npm ci` layer unless lockfiles change; code changes don't trigger full npm reinstall. The `*` glob allows optional lockfile (won't fail if missing).

**npm ci vs npm install**: `npm ci` is faster and more deterministic; always uses lockfile, never mutates it. Use `npm ci` in Dockerfiles.

**Clean cache after install**: Run `npm cache clean --force` after `npm ci` to reduce layer size.

### Build-Time Configuration (VITE_*, REACT_APP_*)

**ARG declarations**: Declare build-time env vars as `ARG VITE_API_BASE_URL=/api/v1`, `ARG VITE_APP_NAME=MyApp`, `ARG REACT_APP_ENV=production` before the build command.

**Pass via --build-arg**: In CI/CD, pass values via `docker build --build-arg VITE_API_BASE_URL=https://api.example.com`.

**Baked at build time**: Vite and Create React App embed these variables into the JavaScript bundle at build time (replaced at transpilation); they are NOT runtime configurable. Rebuilding the image is required to change them.

**When to use**: Use build-time vars for values that differ per environment (dev/staging/prod) but are constant within that environment (API base URLs, feature flags, Sentry DSN).

**Defaults in Dockerfile**: Provide sensible defaults in `ARG` declarations (e.g., `ARG VITE_API_BASE_URL=/api/v1`) so the image builds without --build-arg.

### Runtime Configuration via envsubst

**Pattern**: For values that must be runtime-configurable (backend URL in k8s ConfigMap), use nginx config templates with `${BACKEND_URL}` placeholders and envsubst in an entrypoint script.

**nginx template**: Copy nginx config with placeholders to `/etc/nginx/templates/default.conf.template`.

**Entrypoint script**: `envsubst '${BACKEND_URL}' < /etc/nginx/templates/default.conf.template > /etc/nginx/conf.d/default.conf` then `exec "$@"` to start nginx.

**Why**: Allows one image to serve multiple environments; backend URL set at container start via env var, not baked into image.

**nginx:alpine built-in support**: Recent nginx:alpine images support `/etc/nginx/templates/` directory and auto-run envsubst; you can skip the manual entrypoint script if you only need simple env var substitution.

### Nginx SPA History Fallback

**try_files pattern**: In nginx config, use `location / { try_files $uri $uri/ /index.html; }` for SPA routing.

**Why**: Frontend routers (React Router, Vue Router) use browser history API; `/about` is a client-side route, not a file. Without `try_files`, nginx returns 404 for `/about`. With `try_files`, nginx serves `index.html` for all non-file paths, and the JS router handles the route.

**Static asset caching**: Add `location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { expires 1y; add_header Cache-Control "public, immutable"; }` to cache hashed static assets.

**API reverse proxy**: Proxy `/api/*` requests to backend with `proxy_pass http://backend:8000;` (or `${BACKEND_URL}` via envsubst).

### Docker Embedded DNS Resolver

**Pattern**: In nginx config, add `resolver 127.0.0.11 valid=10s;` at the server level; use `set $backend ${BACKEND_URL}; proxy_pass $backend;` instead of `proxy_pass ${BACKEND_URL};` directly.

**Why**: Docker's embedded DNS (`127.0.0.11`) re-resolves hostnames; if the backend container restarts or scales, the IP changes. Using `set $backend` triggers per-request DNS lookup, avoiding stale IPs and 502 errors.

**When to use**: Use when proxying to dynamic backend services in docker-compose or k8s; skip for static external URLs.

### Non-Root User (Optional)

**Pattern**: In nginx stage, `RUN addgroup -S appgroup && adduser -S appuser -G appgroup` then `USER appuser` before `CMD`.

**Why**: Running as non-root reduces privilege escalation risk; some k8s clusters enforce non-root via PodSecurityPolicy.

**Nginx caveat**: nginx:alpine runs as root by default (binding to port 80 requires root); switching to non-root requires changing `listen` to 8080 and setting `pid /tmp/nginx.pid;`.

**Simpler pattern for Cloud Run/k8s**: Many platforms handle user namespacing externally; omitting `USER` is acceptable if your platform enforces it.

### Build Context and Monorepo Support

**Monorepo build context**: If frontend is in `frontend/` subdirectory of a monorepo, build from repo root with `-f frontend/Dockerfile .` and adjust COPY paths: `COPY frontend/package.json ./frontend/`.

**Shared dependencies**: Copy shared libraries before frontend source: `COPY shared/ ./shared/` then `COPY frontend/ ./frontend/`.

**Why**: Vite can import from `../shared/` at build time; the build stage needs access to the full monorepo context.

## Skeleton / example

```dockerfile
# Multi-stage Dockerfile: node build + nginx runtime
FROM node:22-alpine AS build

WORKDIR /app

# Lockfile-first caching
COPY package.json package-lock.json* ./
RUN npm ci && npm cache clean --force

# Copy source
COPY . .

# Build-time env vars (baked into bundle)
ARG VITE_API_BASE_URL=/api/v1
ARG VITE_APP_NAME=MyApp
ARG VITE_APP_ENV=production

# Build static bundle
RUN npm run build

From ajyadav013/claude-kit, MIT.

More from ajyadav013/claude-kit

Signals

Stars
14
Forks
5
Open issues
9
Last commit (this folder)
Aug 22, 2026 (2 months ago)
Last release
Sep 7, 2026 (1 month ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from ajyadav013

Done for you

Rather not set it up yourself?

Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.

See how we build AI agents →Read the case studies

Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.

launches shipped
50+
launches shipped
media placements
500+
media placements
founders on every account
2
founders on every account

Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block

Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.

Get dockerfile-frontend running in your business

Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.

Goes to the Chalk Labs founders, not the newsletter. Privacy

Need help deploying dockerfile-frontend?

CallGet help
Cite this page

dockerfile-frontend skill. Agent Mart. https://agentmart.dev/skills/ajyadav013-dockerfile-frontend (last updated 2026-10-24)