Deploy
This guide covers all Neemias deploy procedures: Worker (backend), Cloudflare Pages (frontend + docs), D1 migrations, and automated CI/CD.
Overview
| Layer | Platform | Command |
|---|---|---|
| Backend (Worker) | Cloudflare Workers | pnpm deploy:worker |
| Frontend (SPA) | Cloudflare Pages | pnpm build:app && wrangler pages deploy app/dist |
| Docs (VitePress) | Cloudflare Pages | pnpm deploy:docs |
| Database (D1) | Cloudflare D1 | pnpm db:migrate:local / db:migrate:remote |
Quick Deploy (single script)
The scripts/deploy.sh script automates the full flow — tests, build, and deploy:
./scripts/deploy.sh # dev (default)
./scripts/deploy.sh staging # staging
./scripts/deploy.sh prod # productionThe script runs:
pnpm -r test— all monorepo testsDEPLOY_ENV=$ENV pnpm build:app— frontend buildnpx wrangler deploy— Worker deploynpx wrangler deploy— Worker deploynpx wrangler pages deploy app/dist --project-name neemias— frontend deploy
NODE_ENV=production (v0.54.0+): The build pipeline exports
NODE_ENV=productionso thatgenerate-headers.tsproduces hash-based CSP instead of dev-mode nonce-based CSP. Thescripts/pre-deploy-check.shgate detects dev-mode nonces and blocks the deploy.
Build Pipeline
The frontend build (pnpm build:app) now exports NODE_ENV=production:
NODE_ENV=production pnpm --dir app vite buildThis ensures the CSP header generator produces production-appropriate headers (hash-based CSP instead of nonce-based). The scripts/deploy.sh script also passes NODE_ENV=production during the build step.
CSP in Production
v0.55.0: Content Security Policy now uses edge-generated dynamic nonces via Cloudflare Pages Middleware (functions/_middleware.ts). The middleware generates a cryptographic nonce per HTML request, sets it in script-src, and uses HTMLRewriter to apply it to inline script tags. No 'unsafe-inline' in script-src. For production, see docs/operations/security.md for the complete CSP configuration.
Pre-deploy check: The scripts/pre-deploy-check.sh script validates CSP configuration before deploy. It also validates Turnstile origin configuration.
Worker Deploy
pnpm deploy:workerThis command invokes wrangler deploy to publish the Worker on Cloudflare. The Worker becomes available at the domain configured in wrangler.toml.
Documentation Deploy
pnpm deploy:docsThe scripts/deploy-docs.sh script:
- Runs
pnpm docs:buildto generate the VitePress build with OpenAPI + TypeDoc - Publishes
docs/.vitepress/distviawrangler pages deploy --project-name neemias-docs
D1 Migrations
D1 database migrations are managed with Wrangler:
| Command | Description |
|---|---|
pnpm db:migrate:local | Applies migrations on local D1 (--local) |
pnpm db:migrate:remote | Applies migrations on remote D1 (production) |
Migrations are located in the migrations/ directory and are applied sequentially. Make sure to test migrations locally before running in the remote environment.
Data Seed
The seed populates the database with demo data (500 students, 7 classes, 20 nuclei). Does not run in production.
pnpm db:seedThe seed guard (__DEPLOY_ENV__) prevents execution when VITE_DEPLOY_ENV=prod. See Environments for details about the environment matrix.
CI/CD (GitHub Actions)
Automated deploy is triggered by version tags matching the v* pattern (e.g., v1.0.0, v0.26.0). The workflow:
- Runs
pnpm -r test— full test suite - Runs
pnpm docs:build— documentation build - Deploys the Worker (
pnpm deploy:worker) - Deploys the frontend on Cloudflare Pages
- Deploys the documentation on Cloudflare Pages
To trigger a deploy, create and push a tag:
git tag v1.0.0
git push origin v1.0.0Environments
Neemias uses three environments controlled by the VITE_DEPLOY_ENV variable:
| Environment | VITE_DEPLOY_ENV | Seed | URL |
|---|---|---|---|
| Dev | dev | ✅ | neemias.app |
| Staging | staging | ✅ | staging.neemias.app |
| Production | prod | ❌ | app.neemias.app |
See Environments for detailed environment configuration, Cloudflare Pages secrets, and data flow.
Source: README.md, scripts/deploy-docs.sh