Skip to content

Maintenance mode

Tiered write-freeze across backend, web, and workers — for Supabase region cutover and other maintenance windows.

4 min read

Connect your agent today

Draft from chat, review in your calendar, and publish only what you approve.

Start for $0

Overview

MAINTENANCE_MODE controls a **tiered** maintenance flag shared by the **API** (/backend), **web** (/web), and **BullMQ workers** (/orchestrator). Use it to stop database writes during a Supabase region cutover or other short ops window without taking down public marketing pages, docs, or blog content.
ModeAPIWeb UIWorkers
offNormalNormalNormal
bannerNormalOptional notice on public layoutsNormal
freeze_writesBlock mutations (503)Redirect auth/app routes to /maintenanceExit on startup (no job consumption)

Example templates:

Environment variables

VariableWherePurpose
MAINTENANCE_MODEBackend, web (server), workersoff, banner, or freeze_writes
MAINTENANCE_RETRY_AFTER_SECONDSBackend onlyRetry-After header on blocked API mutations (default 3600)
MAINTENANCE_BYPASS_SECRETBackend onlyOptional operator header X-Maintenance-Bypass for smoke tests during freeze_writes

On the web app, MAINTENANCE_MODE is server-only (not a VITE_* variable). Set it in web/.env.production.local.

Workers read the same keys through backend/config/GlobalConfig.ts (orchestrator imports backend config). Keep worker env aligned with the API.

What stays live during freeze_writes

Public SEO and CMS reads

  • Marketing pages under (public)/, docs, legal, pricing, blog, channels, tools, and similar routes
  • API GET, HEAD, and OPTIONS — including public CMS catalog routes (/company/*, /blog-system/*, /listings/*)

Operational endpoints

  • /health and /sitemap.xml
  • Stripe webhooks under /webhooks/ (small billing writes during a short window are acceptable; Stripe retries on 503)

Frozen surfaces

  • API mutations (auth, public API writes, MCP POST, uploads, and anonymous public writes)
  • Web auth and app routes — sign-in, account, editor, admin, OAuth approve, join-org, CLI device pages → /maintenance
  • BullMQ workers — process exits immediately without consuming queues

Operator bypass (optional)

When MAINTENANCE_BYPASS_SECRET is set on the API, send the same value in the X-Maintenance-Bypass request header to allow a single mutation during freeze_writes (for example a smoke-test POST). Do not share the secret publicly.

Cutover timeline (region migration)

Use with Supabase backup. Typical sequence:

Enable write-freeze on all services

Set MAINTENANCE_MODE=freeze_writes on the Vercel backend and web projects and on every Railway worker service (or recreate self-host API, web, and worker containers). Redeploy.

Verify: public blog returns 200; /sign-in redirects to /maintenance; a test POST to the API returns 503 with Retry-After.

Run a fresh pre-cutover backup

With writes frozen, run Layer 2 and Layer 3 again using a -pre-cutover suffix (see Supabase backup docs).

Restore, migrate Storage, and cut over env

Follow Cutover freeze runbook. Update Supabase URLs and keys in production env only after restore and Storage migration succeed.

Smoke test and resume

Run pnpm prod-backup:smoke (see Supabase backup — smoke test), then finish the printed manual checks (Google login, scheduled post, provider OAuth). Set MAINTENANCE_MODE=off on API, web, and workers; redeploy and resume worker processes.

Example (production cutover)

Backend (backend/.env.production.local):

MAINTENANCE_MODE=freeze_writes
MAINTENANCE_RETRY_AFTER_SECONDS=3600
MAINTENANCE_BYPASS_SECRET=your-operator-secret

Web server env (web/.env.production.local — sync to Vercel, no VITE_ prefix):

MAINTENANCE_MODE=freeze_writes

Workers (orchestrator/.env.production.local — same values as API):

MAINTENANCE_MODE=freeze_writes
MAINTENANCE_RETRY_AFTER_SECONDS=3600
MAINTENANCE_BYPASS_SECRET=your-operator-secret

Self-host Compose: set the same keys in infra/self-host/.env (API and workers load the full file; the web service receives MAINTENANCE_MODE at runtime). Recreate containers after changes.

Search documentation
Find a docs page
Discord Support