We don't wait for updates. We create them.
That sounds like marketing copy, but in our case it's the literal engineering workflow. When a tool we depend on doesn't do what we need yet, we read the source, find the gap, write the fix, and send a pull request. Sometimes two.
Today we shipped two official contributions to vinext, Cloudflare's new Next.js build tool — back-to-back, in the span of a single working day — and in the process unblocked our entire admin portal for every client we've ever built a site for.
Here's what happened, why it matters to you, and what you're about to get out of it.
The short version (for everyone)
We're rebuilding the admin portal that all of our clients use to manage their websites. The new version runs on Cloudflare's global network — meaning the dashboard loads from whichever datacenter is closest to you, not from a single server in one US region. For clients, that translates to:
- Pages that load almost instantly, even on mobile
- Lower hosting costs that we don't need to pass on
- Better uptime — Cloudflare's network has over 300 locations worldwide
- Built-in security — DDoS protection, bot filtering, and encrypted connections at the edge
To get there we need a tool called vinext — Cloudflare's brand new way of running Next.js (the framework our admin portal is built with) on their platform. It's fast. It's experimental. And when we started testing it, it had two showstopper bugs that would have blocked our entire migration.
Most companies in this position would wait. We rolled up our sleeves.
The two fixes we shipped upstream
Fix #1 — Getting Clerk recognized (PR #803)
Clerk is the tool we use to handle user accounts, login, and permissions across all our client portals. vinext's automated compatibility checker flagged Clerk as "not supported" — with a warning telling users it wouldn't work.
We didn't believe it. We read both sides of the code (vinext's middleware runtime, Clerk's middleware implementation) and found that every API Clerk actually needed was already there. The "not supported" label was based on an assumption, not a test.
We built a real app, connected it to the real Clerk API, and verified end-to-end:
- Public routes returned 200 with Clerk's auth status
- Protected routes correctly redirected unauthenticated users
- Clerk's sign-in flow rendered and worked
- Authenticated sessions passed through middleware correctly
We opened a PR with the runtime evidence. Cloudflare reviewed and merged it, and the status moved from "unsupported" to "partial" in vinext 0.0.41.
That got us unblocked — but "partial" isn't "fully supported." We kept digging.
Fix #2 — The stale-snapshot bug (PR #812)
The remaining gap was subtle. Clerk needs to read request headers during middleware, then rewrite them, and have those rewrites visible to the page render that comes after. On vinext, the rewrite wasn't sticking. Clerk would set an auth header during middleware, but by the time the page rendered, the header was gone — as if middleware had never run.
The page would then throw: "auth() was called but Clerk can't detect usage of clerkMiddleware()" — even though clerkMiddleware was absolutely running.
We traced it through vinext's request lifecycle and found the cause in one function: applyMiddlewareRequestHeaders(). When middleware read the headers first (which Clerk does internally), vinext cached a sealed, read-only snapshot. When middleware then rewrote the headers, vinext replaced the underlying data — but never invalidated the cached snapshot. Every subsequent read returned the pre-rewrite version.
The fix is 18 lines: invalidate the cached snapshot the moment the underlying headers change. We added two regression tests — one unit test that drives the function directly, one end-to-end integration test that reproduces the Clerk pattern — and verified both fail on the current release and pass with the fix applied.
Then we ran the full vinext verification matrix:
| Check | Result | |---|---| | Unit tests | 2813 / 2813 pass | | Integration tests | 1252 / 1252 pass | | Lint + format + types | 0 warnings, 0 errors | | End-to-end (app router) | 302 / 302 pass | | End-to-end (Cloudflare Workers) | 37 / 37 pass |
Plus a full runtime verification against a live production Clerk instance: auth states return correctly, all expected headers reach the server components, signed-in users see their real user data.
The PR was reviewed and approved. With that merge, Clerk is now fully supported on vinext, not just "partial" — which means our entire admin portal can ship on Cloudflare's platform.
Why you care even if you don't care about the technical details
Every website we build for a client gets managed through our admin portal. That's where you'd go to update your business hours, upload new photos, respond to reviews, check your analytics, see incoming leads — the whole thing.
Right now that portal runs on a slightly older deployment platform. It works great. But the new Cloudflare-native platform is meaningfully faster and meaningfully cheaper to run. That matters because:
-
Faster means better. When you open your admin portal to post a new blog or update a service price, the dashboard responds quickly from wherever you are — because the app runs on Cloudflare's global network instead of a single server in one region. Less waiting. Fewer spinners. No "I'll do it later" because the tool is annoying to use.
-
Cheaper means sustainable. Lower infrastructure costs mean we can keep our prices the same while building more features, and we don't have to pass surprise bills to you when traffic spikes.
-
More secure means fewer headaches. Edge-level DDoS protection, bot filtering, and automatic SSL everywhere are included in the platform — not bolted on after the fact.
-
It scales automatically. Whether you get 50 visitors a month or 50,000 a day, the portal performs the same. No capacity planning. No outages when one client has a busy month.
None of that matters if the platform can't run our auth stack. That's why these two fixes were blockers — and why we wrote them ourselves instead of waiting.
The technical detail (for the engineers reading this)
If you're building on Next.js + Cloudflare and you want the specifics:
- vinext reimplements the Next.js API against Vite + Rolldown and ships Workers-native output. It's significantly faster than opennext's webpack-based build (roughly 4× faster builds in our own measurements) and the output bundle is about 57% smaller gzipped for the app we tested.
- The middleware headers bug affects any library that follows the pattern of
headers() → NextResponse.next({ request: { headers } }). Clerk is the obvious one, but this pattern is also used by authentication libraries, logging/tracing middleware, feature flagging systems, and custom header injection. If you hit a "headers seem to revert after middleware" bug, this was the cause. - PR #812 fixes the cached read-only snapshot in
applyMiddlewareRequestHeaders(). Specifically: when middleware replacesctx.headers(or, for cookie mutations,ctx.cookies), the fix now clearsctx.readonlyHeaders,ctx.readonlyCookies, andctx.mutableCookiesso the nextheaders()/cookies()call rebuilds the sealed view from the post-override state. - Compatibility status: with both PRs merged, Clerk's full auth flow works — middleware protection, sign-in redirects, API proxy, client-side hooks, and server-side
auth()/currentUser()calls from RSC.
Why vinext over opennext
If you're evaluating Cloudflare Workers deployment for a Next.js app, the short version is:
| | opennext | vinext | |---|---|---| | Build speed | webpack-based, slower | Vite + Rolldown, noticeably faster | | Client bundle size | larger | ~57% smaller gzipped (our measurements) | | RSC handling | works, compatibility shim layer | native Vite RSC integration | | Status | stable, widely used | experimental but rapidly maturing | | Our admin portal | works today | will run once our PRs ship in the next release |
opennext is the safe choice. vinext is the one we're betting on for the admin portal because it's going to get faster and cheaper and closer to the edge over the next year, and the delta matters when it's the tool hundreds of people are using every day to run their business.
Why we do this
At Shorebird Management we try not to accept "it's not supported yet" as a final answer. If the thing we need to do is technically possible and the blocker is someone else's open-source project, we'll open the PR ourselves. We landed both of these fixes in a single day — not because we wanted to be contributors, but because our clients need the result.
If you're building on Next.js and Cloudflare and running into the edges of what these tools can do today, get in touch. We've spent enough time in this stack to know exactly where the traps are and how to work around or fix them.
We don't wait for updates. We create them — because the faster, cheaper, better-secured version of your admin portal is what you're paying us for.
