Infrastructure
Turborepo · Vercel · Cloudflare · Inngest · GitHub Actions
The right 2026 infra answer for a small SaaS team is unsexy on purpose: Turborepo monorepo, Vercel for the Next.js app, Cloudflare for static + edge auth, Inngest for background work, GitHub Actions for CI. No Kubernetes, no Terraform-for-everything, no in-house deploy tooling. Every hour spent on bespoke infra is an hour not spent on the product — buy back time aggressively.
Primary stack
The default picks this pillar assumes
- Turborepo
- CloudflareFree tier covers most early…
- Inngest
Alternates worth knowing
Swap in when scale, cost or constraints change
- Nx
- Trigger.dev
- BullMQ
Turborepo
One repo with multiple apps (web, mobile, marketing) + packages (db, ui, config). Turborepo handles the task graph, incremental builds, remote caching. Vercel's remote cache is free; Nx Cloud's is also free for OSS.
How it flows
step by step- 01step
apps/web (Next.js), apps/marketing (Next.js), apps/mobile (Flutter, not in turbo), packages/db, packages/ui, packages/config.
- 02step
pnpm workspaces for dep linking; pnpm install at the root.
- 03step
turbo run build → topological build, parallel where independent, cached on hash.
- 04step
Vercel remote cache: each CI run can pull other devs' / branches' cached outputs.
Cases & edge cases
watch for theseDon't over-modularize — three apps + four packages is the sweet spot for years.
Avoid circular imports between packages — turborepo will flag, lint will too.
Mobile (Flutter) stays outside turbo's task graph — its own CI workflow.
Vendors & tools
what implements thisTask runner + cache for JS monorepos.
Nx
alternateMore opinionated; over-engineered for 1-10 person teams.
Where it lives
code references- turbo.json
- pnpm-workspace.yaml
- packages/db/
Vercel Deploys
Push to main → Vercel builds → if green, promotes to production. Every PR gets a preview URL with the full app on a unique subdomain. No special operations knowledge needed; you focus on the code.
How it flows
step by step- 01step
git push → GitHub webhook to Vercel.
- 02step
Vercel builds (with turbo remote cache) → runs the Next.js build.
- 03step
Output: serverless functions (App Router route handlers, Server Actions) + edge functions (middleware) + static assets to CDN.
- 04step
Atomic deploy: traffic shifts instantly; rollback = promote previous deployment.
Cases & edge cases
watch for thesePreview URLs leak before launch — gate them with a Vercel Password or Cloudflare Access for marketing routes.
Cold starts on rarely-used routes — warm via cron pings or fluid compute (Vercel feature).
Vercel's pricing model: you pay for compute time. Watch image optimization + middleware execution.
Checklist
ship readiness- must
Preview deploys on every PR
- must
Production gated on green CI
- must
Rollback playbook documented
Cloudflare Edge
Cloudflare in front of Vercel: DNS, free DDoS protection, CDN for static assets, Workers for ultra-cheap edge logic (auth gating, A/B routing, geo redirects). Optional: Cloudflare R2 for cheap object storage (no egress).
How it flows
step by step- 01step
Domain registered at Cloudflare (or transferred); DNS points apex + www to Vercel.
- 02step
Cloudflare in front → handles WAF, bot blocking, page rules.
- 03step
Static assets cached at the edge (300+ POPs).
- 04step
Optional Worker layer: pre-Vercel routing, A/B tests, geo-redirects (EU users to eu.app.com etc.).
Cases & edge cases
watch for theseDNS-only mode (gray cloud) when you DON'T want Cloudflare to proxy (e.g. specific subdomain → Vercel directly).
Page Rules → Cache Rules (the new system). Migrate before the old one sunsets.
R2 for user uploads has no egress fees — vs. S3 where bandwidth out is the bill.
Vendors & tools
what implements thisCloudflare
primaryDNS + CDN + DDoS + edge compute.
pricingFree tier covers most early-stage needs.
CI/CD (GitHub Actions)
GitHub Actions runs on every PR: lint, type-check, unit tests, e2e tests (Playwright), DB migration dry-run. Production deploys gate on the same workflow being green on main.
How it flows
step by step- 01step
PR open → workflow runs: pnpm lint + typecheck + test + drizzle-kit dry-run.
- 02step
Playwright e2e against the Vercel preview URL.
- 03step
Merge to main → migration job runs first (against prod DB), then Vercel promotes.
- 04step
On failure: deploy halts, channel notification, rollback link in the message.
Cases & edge cases
watch for theseRun migrations BEFORE the app deploys; old code must work against the new schema.
Cache pnpm store + turbo cache → 5x faster CI.
OIDC for secrets (don't paste AWS keys into Actions secrets — use trust between Actions and your cloud).
Checklist
ship readiness- must
Migration runs before app deploy
- must
PRs blocked on red CI
- should
Cache (pnpm, turbo) configured
- should
OIDC for cloud credentials
Where it lives
code references- .github/workflows/ci.yml
- .github/workflows/migrate.yml
Preview Environments
Every PR gets its own URL, its own database (via Neon branching or Supabase preview projects), and a Stripe test environment. Reviewers can click and use the feature live.
How it flows
step by step- 01step
PR opened → Neon branch created from prod schema (data-less).
- 02step
Vercel preview deployed against the branch DSN.
- 03step
Seed script runs (fixtures only — no real users).
- 04step
Reviewer clicks the preview URL, exercises the change, leaves comments inline.
- 05step
PR merged or closed → branch DB cleaned up after 7d idle.
Cases & edge cases
watch for theseDon't seed real PII into previews — fake data only. GDPR issue otherwise.
Preview URLs need to be password-gated until publish (Vercel SSO or Cloudflare Access).
Long-lived previews ($$$) — auto-tear-down on PR close.
Background Jobs
Inngest for background work and cron. No Redis to manage, serverless-friendly, durable workflows with built-in retries. Triggers from Server Actions or external events; runs on Vercel serverless functions.
How it flows
step by step- 01step
Define: inngest.createFunction({ id, trigger }, async ({ event, step }) => { ... }).
- 02step
Server Action emits: await inngest.send({ name, data }).
- 03step
Inngest delivers to your /api/inngest webhook → executes step-by-step.
- 04step
step.run(name, fn) → automatic retry on throw, idempotency per step.
- 05step
step.sleep, step.waitForEvent for long workflows.
Cases & edge cases
watch for thesestep.run is the unit of retry — chunk work into idempotent steps.
Inngest's dev server (npx inngest-cli@latest dev) → local UI for triggering / debugging.
Don't pass huge payloads in events — pass IDs and refetch.
Vendors & tools
what implements thisServerless event-driven workflows + cron + retries.
Trigger.dev
alternateSimilar; better for AI workflows + long-running tasks.
BullMQ
alternateSelf-hosted Redis-based. Strong on Node servers; awkward on serverless.
Where it lives
code references- lib/inngest/client.ts
- lib/inngest/functions/
Secrets Management
Secrets live in Vercel Environment Variables (per-env: dev/preview/prod), GitHub Actions secrets for CI. NEVER committed. Rotation: documented per secret, with a runbook.
How it flows
step by step- 01step
Vercel env vars: STRIPE_SECRET_KEY, CLERK_SECRET_KEY, DATABASE_URL — separately per environment.
- 02step
Local dev: .env.local (gitignored) loaded by Next.js automatically.
- 03step
Pull: vercel env pull .env.local refreshes local from Vercel.
- 04step
Rotation: change at vendor → update Vercel + re-deploy → confirm green → revoke old.
Cases & edge cases
watch for theseNever log secrets — even partially. Pre-commit hook scans for likely tokens.
Database URL with the pool host (PgBouncer) for serverless; with the direct host for migrations.
Webhook signing secrets: NEVER reuse across environments (test endpoints get probed).
Checklist
ship readiness- must
Pre-commit secret scan (e.g. trufflehog)
- must
Per-environment env vars in Vercel
- should
Rotation runbook per critical secret
Apple Pencil draws with pressure. Fingers still scroll. Saved per pillar.