deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Vercel Hobby limits pushed a travel directory to Cloudflare, and its 650-line config had to be rebuilt

A travel directory outgrew Vercel's free Hobby plan, and the move to Cloudflare Workers revealed its 650-line vercel.json was less a settings file than an undocumented program the platform had been silently interpreting.

Vercel Hobby limits pushed a travel directory to Cloudflare, and its 650-line config had to be rebuilt

A developer running a mid-sized travel directory has documented moving the site off Vercel's free Hobby plan onto Cloudflare Workers, after a deployment-storage warning and a mismatch with the plan's terms made staying untenable. Writing on dev.to under the handle tedagentic, the author describes what looked like a routine settings job and turned into a reverse-engineering exercise.

Why free hosting stopped working

The site — roughly 800 prerendered pages, 190 accumulated redirect rules and a small backing database — had spent its entire life on the Hobby tier. According to the post, two things ended that. First came an email reporting 75 percent of deployment storage used. Second, the site earns affiliate commission while Hobby is restricted to non-commercial use, so in the author's own admission it never legitimately qualified for the plan. Paying $20 a month for the Pro tier didn't make sense at the site's stage. Cloudflare's free tier serves static files at no charge, and its worker allowance of 100,000 requests a day sits comfortably above the site's average of 16,000.

The settings file that wasn't

The repository's vercel.json runs past 650 lines of redirects, headers and rewrites. Cloudflare has no equivalent rule list and does not read the file, so every behavior it encoded had to be reproduced by a small worker written from scratch — around 120 lines that import the original vercel.json so the file remains the single source of truth. The worker follows what the author determined was Vercel's order of operations: redirects evaluated first with first-match-wins and query strings preserved, then a same-origin proxy to the database API, then static files, then an app-shell 200 response for extensionless paths, with the file's headers applied to every response. Its core compiles Vercel path patterns such as /guides/:city into regular expressions with named capture groups.

Measuring the old host instead of reading documentation

No document specifies exactly what Vercel does with that file, so the author kept the old deployment reachable at its own URL and treated it as the specification, comparing responses across every sitemap URL and 202 redirect cases. That comparison caught a redirect loop: an early worker version matched paths case-insensitively, so a rule that sends a mixed-case URL to its lowercase form began redirecting to itself — Vercel actually matches case-sensitively, a behavior nothing in the file states. Other findings included Cloudflare stripping /index.html and .html suffixes with a 307 temporary redirect where the site uses permanent 308s, which search engines treat differently, so the worker converts them; Vercel appending a charset declaration to text responses that Cloudflare omits; and robots.txt, sitemap.xml and favicon.ico needing exclusion from the app-shell fallback so a missing file wouldn't return a 200 full of HTML. After the fixes, all 610 sitemap pages matched on status, title, canonical URL, robots tag and main heading, every redirect matched except one deliberate improvement, and a headless browser confirmed that pages fetching from the database rendered correctly. The author credits Claude Code with the hands-on work, approved step by step.

The switch, and what actually broke

Cutover was a four-line script — DNS was already on Cloudflare — that removed two records and attached the hostnames to the worker. Old records were backed up first, the Vercel project was kept with builds disabled, and rollback would take minutes. The only real failure was mundane: automated builds died at asset upload with error 10013 because the deploy token was a leftover from a different site without the right permissions. A fresh token fixed it, and since failed builds leave the last good version in place, the live site was never at risk.

A dashboard number, misunderstood

The storage alert carries a second lesson. After reading the dashboard's 8.81 GB figure, the author deleted 90 old deployments and set one-week retention; the number didn't move. A theory followed — a rolling 30-day count of builds, roughly 56 MB across 158 of them — and a monitoring tool was built on that guess. A day later the dashboard read about 230 MB, undermining the explanation, and the author still cannot say which change produced the drop.

Why it matters

This is a concrete case of free-tier ceilings and commercial-use terms quietly ending "free" hosting for any site that grows, but the transferable part is the method: build the replacement alongside the live site, keep the old platform running as a reference, and prove parity by measuring actual responses. The deeper warning is that every implicit platform behavior — matching semantics, status codes, response headers, even dashboard figures — is code you depend on but have never read, and its only full specification is the running system itself.

  • #vercel
  • #cloudflare-workers
  • #web-hosting
  • #migration
  • #serverless