Both HireOS and CodexGenAI use Next.js deployed on Vercel, with Cloudflare Workers handling the AI proxy layer. The split wasn't accidental — some workloads belong at the edge and others don't. This post documents the actual setup, the friction points that cost me time, and the things I wish I'd known before starting.
Why use Cloudflare Workers alongside Next.js at all
The obvious question: if Vercel already runs edge functions, why add Workers? A few reasons drove it.
The AI proxy path is latency-sensitive and benefits from running in a full V8 isolate with minimal cold-start overhead. It also handles secrets — provider keys, signing — that I wanted out of the main application origin entirely, so a compromise of the app surface doesn't expose the inference path. Keeping that concern in a separate, narrowly-scoped Worker shrinks the blast radius and keeps the Next.js deployment focused on rendering and app logic.
The deployment topology
The request flow, end to end: browser → Vercel (Next.js) → Cloudflare Worker (AI proxy) → AI provider, with Supabase serving auth, database, and storage alongside. The Next.js app handles UI, routing, and authenticated data access; the Worker is a thin, fast, secret-holding layer in front of the model providers. DNS/routing is configured so the Worker sits on its own route, callable from the app but isolated from it.
What runs on Vercel vs. what runs on Workers
The decision criteria I used, made explicit:
- Needs Node APIs or larger dependencies? → Vercel (Node runtime).
- Cold-start sensitive, secret-handling, simple I/O? → Worker.
- Renders UI or touches app data with the user's session? → Next.js on Vercel.
- Proxies a model call and nothing else? → Worker.
Concretely: rendering, auth flows, and Supabase reads/writes live in Next.js; the LLM call, key use, and response streaming live in the Worker.
Edge runtime gotchas: what doesn't work where you expect
This is where the time went. The edge is not Node, and the gaps aren't always obvious:
- Node built-ins are absent or shimmed —
fsdoesn't exist, and parts ofcryptodiffer; you use the Web Crypto API instead of Node'scrypto. - Vercel's edge runtime ≠ Cloudflare Workers — both are "edge," but their available APIs and limits differ, so code isn't always portable between them.
fetchsemantics and streaming differ subtly across runtimes; response streaming in particular needs testing in the exact runtime you'll deploy to, not just locally.
The lesson: pick the runtime per workload deliberately, and don't assume "edge" means one consistent environment.
Wrangler, local dev, and keeping environments in sync
Local development means running next dev and wrangler dev side by side, which is fiddly the first time. The things that matter: keep secrets in sync between Vercel env vars and Wrangler's secret store, point the app at the local Worker during dev, and stand up a staging Worker so you're not testing edge-only behaviour in production. Environment drift between the two platforms is a real source of "works locally, breaks deployed" bugs — make the config single-sourced where you can.
Performance: what actually moved the needle
The biggest wins were qualitative and worth stating even without exact figures: moving the proxy to the edge cut the time-to-first-token meaningfully versus routing model calls through a Node function, and streaming responses rather than buffering them changed the perceived latency far more than any raw throughput tuning. Caching repeated/identical prompts is the other obvious lever where applicable.
What I'd do differently
- Don't reach for Workers reflexively. For a smaller project without strict cold-start or secret-isolation needs, Vercel edge functions alone would have been simpler to operate.
- Single-source the config earlier — the env drift between two platforms cost more time than the architecture itself.
- Decide the runtime split on paper first. Most of my edge gotchas came from porting code that was never going to run cleanly on the edge.
FAQ
Do I need Cloudflare Workers if I'm on Vercel? Often no. Use them when you specifically want full-isolate performance, secret isolation from your app origin, or Cloudflare-specific features. Otherwise Vercel's own edge runtime is simpler.
What breaks when moving Next.js code to the edge?
Node built-ins (fs, parts of crypto), some dependencies, and assumptions about a long-lived runtime. Use Web APIs and test in the target runtime.