Made Open

Vercel Deployment (madeopen.com marketing site)

This guide documents how the public marketing site at madeopen.com is deployed to Vercel. It is not a user-facing self-hosting guide — Made Open users run their own hub and their own web instance on their own infrastructure (see deployment-docker.md). This document exists so the operator can reproduce the Vercel project setup if it ever needs to be recreated.

Scope: apps/web only. The hub, NATS, Meilisearch, Redis, and the rest of the stack are not deployed to Vercel (Vercel serverless can't host a stateful Fastify backend).


Prerequisites

  • A Vercel account with access to deploy the repo.
  • DNS control over madeopen.com.
  • (Optional) A Supabase project if you want the operator to be able to sign in and preview the full site while COMING_SOON_MODE is on. The middleware falls through gracefully without Supabase, so you can skip this for the initial coming-soon-only deploy.

What's already in the repo

  • vercel.json at the repo root pins the framework, install command, build command, output directory, and a git diff guard for the ignoreCommand.
  • apps/web/src/middleware.ts implements the COMING_SOON_MODE gate that rewrites unauthenticated traffic to /coming-soon (landed in commit aec70de).
  • apps/web/src/app/coming-soon/page.tsx is the minimal landing page (outside the (public) layout so it doesn't inherit the marketing navbar).
  • apps/web/.env.example documents the flag.
  1. Vercel dashboard → Add New → Project → Import Git Repository → pick drdropout/made-open.
  2. Framework Preset: auto-detected Next.js (confirm).
  3. Root Directory: leave as . (repo root). vercel.json handles pathing.
  4. Build & Development Settings: leave untouched — they are driven by vercel.json.
  5. Node.js Version: 20.x (matches ci.yml). Set in Project Settings → General → Node.js Version.
  6. Hit Deploy. First build may fail if env vars aren't set (Phase 2). That's expected.

Phase 2 — Environment variables

Set these in Project Settings → Environment Variables. Vercel cannot read vercel.json for secrets; this is manual.

VariableValueEnvironmentsRequired?
COMING_SOON_MODE1Production, Preview, DevelopmentYes
NEXT_PUBLIC_SUPABASE_URLhttps://<ref>.supabase.coProduction, PreviewOptional — needed if the operator wants to sign in and preview the full site
NEXT_PUBLIC_SUPABASE_ANON_KEYMatching anon keyProduction, PreviewSame
NEXT_PUBLIC_HUB_URLLeave unsetNot needed until the hub is live

COMING_SOON_MODE must be set on all three environments. Vercel creates public preview URLs for every PR; without the gate on Preview, a leaked URL would expose the full in-progress site.

After setting variables, redeploy from Deployments → latest → Redeploy.

Phase 3 — Attach madeopen.com

  1. Project Settings → Domains → add madeopen.com and www.madeopen.com.
  2. At the DNS registrar for madeopen.com:
    • Apex (madeopen.com): A record → 76.76.21.21
    • www: CNAMEcname.vercel-dns.com
  3. In Vercel, configure www.madeopen.com → redirect to madeopen.com (one click on the domain detail page).
  4. Wait for DNS propagation (usually minutes). Vercel issues the Let's Encrypt certificate automatically once propagation completes.

Verification

After Phase 3:

# Coming Soon gate
curl -s https://madeopen.com/            | grep -c "Coming soon"   # > 0
curl -s https://madeopen.com/features    | grep -c "Coming soon"   # > 0
curl -s https://madeopen.com/admin       | grep -c "Coming soon"   # > 0

# Login escape hatch
curl -s https://madeopen.com/auth/login  | grep -c "Coming soon"   # 0
curl -s https://madeopen.com/auth/login  | grep -ci "sign in"      # > 0

# TLS + HTTPS redirect
curl -I http://madeopen.com/                # 308 → https
curl -I https://www.madeopen.com/           # 308 → apex

And open a preview URL from a PR branch — confirm it also renders Coming Soon.

Going fully live

No code changes. No redeploy-with-code required.

  1. Project Settings → Environment Variables → Production → set COMING_SOON_MODE to 0 (or delete it).
  2. Deployments → latest → Redeploy.
  3. The middleware gate falls through, the normal (public) routes serve their real content, and madeopen.com/ renders the full marketing page.

Keep COMING_SOON_MODE=1 on the Preview environment if you want PR previews to stay gated even after production is live.

Troubleshooting

Build fails with "Cannot find module '@made-open/shared'": Turbo didn't build the shared package first. Confirm buildCommand in vercel.json is pnpm turbo run build --filter=@made-open/web (with the filter). The turbo.json dependsOn: ["^build"] clause does the ordering.

Build fails on pnpm install --frozen-lockfile: pnpm-lock.yaml is out of sync with a package.json. Run pnpm install locally, commit the lockfile, push.

Pages render blank / 500 in production: Usually Supabase env vars mismatch. The middleware falls through silently when both are unset, but if one is set and the other isn't, createServerClient throws. Either set both or unset both.

Middleware rewrites don't fire: Check COMING_SOON_MODE is exactly "1" (string). Any other value including "true" is treated as off.

/coming-soon itself redirects to Coming Soon in a loop: Won't happen — the middleware explicitly allowlists /coming-soon and /auth/*. If it does, someone broke the allowlist logic; check isComingSoonAllowed in apps/web/src/middleware.ts.

  • Docker deployment guide — for users self-hosting the full stack
  • Release signing runbook — for the update-system signing ceremony
  • apps/web/src/middleware.ts — the COMING_SOON_MODE gate implementation
  • apps/web/src/app/coming-soon/page.tsx — the landing page