Build & Deploy¶
Build process, Docker configuration, and deployment workflows.
NPM Scripts¶
From package.json:
| Script | Command | Purpose |
|---|---|---|
dev |
next dev |
Development server |
build |
next build |
Production build |
start |
next start |
Production server |
lint |
eslint . |
Run linter |
Development¶
Production Build¶
Linting¶
Docker¶
Dockerfile¶
Multi-stage build for optimized production image:
# Stage 1: Builder
FROM node:20-slim AS builder
WORKDIR /app
# Install dependencies
COPY package*.json ./
RUN npm ci --legacy-peer-deps
# Copy source and build
COPY . .
RUN npm run build
# Stage 2: Production
FROM node:20-slim
WORKDIR /app
# Install production dependencies only
COPY package*.json ./
RUN npm ci --only=production --legacy-peer-deps
# TypeScript needed for next.config.ts
RUN npm install typescript
# Copy built assets
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/next.config.ts ./
COPY --from=builder /app/lib ./lib
# Expose port
EXPOSE 3000
# Set environment
ENV NODE_ENV=production
# Start server
CMD ["npm", "start"]
Build Image¶
Run Container¶
docker run -p 3000:3000 \
-e NEXT_PUBLIC_AUTH_API_URL=https://auth.example.com \
-e NEXT_PUBLIC_API_BASE_URL=https://api.example.com \
-e NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_xxx \
-e LOKI_URL=https://loki.example.com \
coordinator-web
Docker Compose¶
version: "3.8"
services:
web:
build: .
ports:
- "3000:3000"
environment:
- NEXT_PUBLIC_AUTH_API_URL=https://auth.example.com
- NEXT_PUBLIC_API_BASE_URL=https://api.example.com
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_xxx
- LOKI_URL=https://loki.example.com
- NODE_ENV=production
restart: unless-stopped
CI/CD Workflows¶
GitHub Actions¶
.github/workflows/ contains workflow files.
Build & Test¶
name: Build and Test
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci --legacy-peer-deps
- name: Run linter
run: npm run lint
- name: Build
run: npm run build
env:
NEXT_PUBLIC_AUTH_API_URL: ${{ vars.AUTH_API_URL }}
NEXT_PUBLIC_API_BASE_URL: ${{ vars.API_BASE_URL }}
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: ${{ secrets.STRIPE_PK }}
Docker Build & Push¶
name: Docker Build
on:
push:
branches: [main]
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Login to Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and Push
uses: docker/build-push-action@v5
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
Documentation Deploy¶
name: Deploy Docs
on:
push:
branches: [main]
paths:
- "docs/**"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: "3.x"
- name: Install MkDocs
run: pip install mkdocs mkdocs-material
- name: Build docs
run: mkdocs build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./site
Deployment Platforms¶
Vercel¶
- Connect GitHub repository
- Set environment variables in Vercel dashboard
- Deploy automatically on push
Railway¶
- Create new project from GitHub
- Add environment variables
- Deploy
Self-Hosted¶
# Clone repository
git clone https://github.com/org/coordinator-web.git
cd coordinator-web
# Install dependencies
npm ci --legacy-peer-deps
# Build
npm run build
# Start with PM2
pm2 start npm --name "coordinator-web" -- start
Kubernetes¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: coordinator-web
spec:
replicas: 3
selector:
matchLabels:
app: coordinator-web
template:
metadata:
labels:
app: coordinator-web
spec:
containers:
- name: web
image: ghcr.io/org/coordinator-web:latest
ports:
- containerPort: 3000
env:
- name: NEXT_PUBLIC_AUTH_API_URL
valueFrom:
configMapKeyRef:
name: coordinator-config
key: auth-url
---
apiVersion: v1
kind: Service
metadata:
name: coordinator-web
spec:
selector:
app: coordinator-web
ports:
- port: 80
targetPort: 3000
Health Checks¶
Endpoint¶
Create a health endpoint:
// app/api/health/route.ts
export async function GET() {
return Response.json({ status: "ok", timestamp: new Date().toISOString() });
}
Docker Health Check¶
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
Build Optimization¶
Bundle Analysis¶
npm install @next/bundle-analyzer
# In next.config.ts
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true"
});
module.exports = withBundleAnalyzer(nextConfig);
# Run analysis
ANALYZE=true npm run build
Caching¶
Next.js caching is automatic. For Docker:
# Cache node_modules
COPY package*.json ./
RUN npm ci
# Separate layer for source
COPY . .
RUN npm run build