Hacker News new | ask | show | jobs
by nahsuhn 59 days ago
Author here. I wrote this in late March after a billing dispute and sat on it. Then the breach disclosure landed and I kept seeing the same pattern: opt-in safety, "shared responsibility" framing, architecture that doesn't protect customers unless they explicitly ask.

The billing story: my functions defaulted to wall-clock billing, not CPU billing. A dead socket cost me $1,243 over 8 days. The breach story: env vars defaulted to unencrypted. One compromised employee exposed every secret that wasn't explicitly marked sensitive.

I'm not claiming these are the same severity. A breach is orders of magnitude worse. But they're the same architectural decision: the dangerous option is the default, the safe option is opt-in, and when the inevitable happens, the platform points to a doc explaining it was your responsibility.

I spent my weekend rotating keys out of caution. Vercel's email telling me to "take advantage of the sensitive environment variables feature" arrived at 10:02 PM last night while I was writing this post. Wild.

Happy to answer questions about the migration (Part 3). It was not painless.

1 comments

Re your migration post, I've been building Keshro, which auto-generates migration plans from source. Pointed it at the open-source Dub.co repo and asked for Vercel → Cloudflare Pages: https://keshro.com/migrations/public/87297a45-f148-403f-98cd... (view-only).

Dub is Next.js + PlanetScale so the Astro-specific landmines (middleware shadowing, astro:env/server, module-scope auth singletons) don't appear. The Workers-dependency audit, cron redesign for maxDuration:600 routes, and Edge Config → KV adapter did, because they're in Dub's source. Whether it would catch your exact Astro chain depends on whether the RAG has enough Astro-on-Workers patterns, which is the obvious next test.

What the plan probably wouldn't catch from your post: Lesson 6 (Hyperdrive's port 5432 vs the pooler port, the double-pooling trap), Lesson 10 (module-scope setInterval bricking every route), and the three-coexisting-env-paths reality around config.ts being stuck in the client build graph. That class of landmine only surfaces in postmortems, not docs. Out of curiosity, anything you've discovered post-cutover that would be a 12th lesson if you had to write about the migration again today?

The post documented the cutover. What it doesn't document is the thirty-seven PRs after. Twelve touched the auth path. PR #183: replace pg with postgres.js. #186: remove module-scope env throws. #188: pass schema to drizzle adapter. #193: bridge runtime secrets to middleware. #196: remove module-scope setInterval. #205: retry getSession on cold start. Auth is always where the time goes.

Cloudflare has since unified on Workers and Pages is legacy. Moving from Pages to Workers took five PRs. None of them touched auth. That's the lesson hiding in the original eleven. Lock-in is the well-known failure mode. Lock-out is its quieter twin: the platform leaves you. The thing that survives is the ability to move.

Source-derivable risks are a real class to surface. Postmortem-class are harder, because they don't exist anywhere structured until someone burns a Saturday, and even then they get written down maybe a third of the time. Behind both is a third class: changelog-derivable risks. The platform sunsets the target you migrated to, and the plan ages on the shelf. Curious if Keshro tracks that. Feels like the harder version of what you're doing, and probably the more valuable one.

Saw the parallel-worktree execution model on the site. I've got my own hand-rolled version in my Claude Code rules. Different ends, same problem.

Sent you a gist with the twelve auth-stabilization commits. Line-by-line is more revealing than the post is.