# Going Frameworkless on Cloudflare, and Why You Still Reach for Vercel, Netlify, and Square

You can ship a real app on Cloudflare with no framework and almost no build step. Here is when that wins, where it bites, and how to split work across Vercel, Netlify, and Square without getting locked in.

Author: J.A. Watte
Published: June 26, 2026
Source: https://jwatte.com/blog/blog-cloudflare-frameworkless-vendor-lockin/

---

Most of the web tells you to start a new project by picking a framework. Next.js or SvelteKit, file-based routing, a build graph, a few hundred dependencies, and you are off. There is a quieter path that has gotten genuinely good in 2026, and on Cloudflare it is now the recommended one: serve your files straight off the edge, write one small function for the dynamic parts, and skip the framework entirely. I ship real things this way because the mental model is small, the bill is close to zero, and there is far less to break.

Frameworkless does not mean primitive, and it does not mean you should run your whole company on it. This post is the honest version: what frameworkless on Cloudflare actually is, where it wins, where it bites, and why you would still reach for Vercel, Netlify, or Square on purpose. The thread running through all of it is lock-in, which is the cost nobody quotes you up front.

## What "frameworkless" means on Cloudflare now

Cloudflare's own guidance changed. Their docs now say plainly that if you are starting a new project you should use Workers, not Pages, because Workers picked up native static-asset serving and all the new investment is going there. That one shift is what makes frameworkless practical, because it collapses into three moving parts.

- **The CDN serves your files.** You point an `assets` directory at your built HTML, CSS, JS, and images, and Cloudflare serves them from its edge network. Requests that match a file are served as files, with no code running and no charge. A purely static site needs no Worker script at all.
- **One `fetch` handler is your backend.** For the dynamic parts, an API, auth, a form handler, you write a single Worker function that branches on the URL. Handle `/api/*` with your logic, and for everything else hand the request back to the CDN with `env.ASSETS.fetch(request)`. You can flip `run_worker_first` to a list of route patterns so only those paths run code first.
- **A config flag handles SPA routing.** Set `not_found_handling` to `single-page-application` and any unmatched path returns your `index.html` with a 200, which is the catch-all a client-side router needs. No server framework required.

If you want a touch more developer experience without a framework, you add one tiny library. [Hono](https://github.com/honojs/hono) is the popular choice: about 31k GitHub stars, zero dependencies, and its `hono/tiny` preset is under 12kB. It gives you clean routing and middleware, including built-in JWT, Bearer, and Basic auth, and because it is built on web standards the same handler runs on Workers, Deno, Bun, Node, and more. For interactivity without a bundler, HTMX and Alpine drop in through a script tag and let the Worker return HTML fragments. That is the entire stack.

## Where frameworkless wins

- **Little or no build step.** A static site ships with no Worker and no bundler at all. Even a full app with vanilla JS or Hono needs minimal tooling. You edit, you deploy, and you skip the upgrade treadmill where a framework major version breaks your build on a Tuesday.
- **No cold start.** Workers run in V8 isolates, not containers or virtual machines. Cloudflare measures an isolate starting roughly 100 times faster than a Node process on a container, using an order of magnitude less memory. You stop designing around warm-up entirely.
- **The cost is close to nothing.** Static-asset requests are free and unlimited on both plans. The free plan covers 100,000 dynamic requests a day with 10ms of CPU per request, and the paid plan is a flat $5 a month that includes 10 million requests and 30 million CPU-milliseconds. You pay for CPU time, not wall-clock time, so an API that mostly waits on a database stays cheap.
- **Fewer dependencies, fewer CVEs.** Vanilla JS plus a zero-dependency library is a tiny dependency tree next to a meta-framework's hundreds of transitive packages. That is less to audit, fewer `npm audit` findings, and a smaller supply-chain surface, which matters more every year.
- **It is portable and easy to reason about.** The whole model is "files served by a CDN, plus one function." Because Hono and Workers speak the standard `Request` and `Response`, the core logic moves to another runtime with little change. A new engineer understands the request flow in an afternoon.

## Where it bites

None of this is free of sharp edges, and the honest pitch names them.

- **No file-based routing.** You get one `fetch` handler, not the filesystem conventions of Next.js. You define routes yourself, by hand or with Hono's router, and a large app needs discipline to stay organized.
- **No built-in SSR, data loading, or server components.** There is no loader-and-action layer, no streaming SSR scaffolding, no React Server Components out of the box. Cloudflare can render on the server, but the conventions are yours to build. You template HTML in the Worker and wire your own data fetching.
- **No built-in image optimization or auth scaffolding.** Meta-frameworks bundle these. Frameworkless does not. Cloudflare offers image resizing as a separate product, and Hono gives you auth middleware, but wiring sessions, providers, and a media pipeline is on you.
- **You rebuild developer experience.** Fewer turnkey templates, more upfront decisions, and client-side state management that is fully manual. That is liberating for a small team and a real drag for a large one that depends on shared conventions to onboard people.
- **The free plan caps CPU at 10ms.** Waiting on I/O does not count, but heavy synchronous compute, big rendering, crypto, or parsing, can blow past it. The paid plan raises the ceiling to as much as five minutes, and genuinely heavy jobs belong in Cloudflare Containers, not an isolate.

The rule of thumb: a framework earns its dependencies and build step when you need heavy SSR or streaming, SEO-critical pages with complicated per-route data, rich interconnected client state, or strong conventions for a big team. For lean APIs, static sites, internal tools, and most small-business builds, frameworkless is less code and less to maintain. The pragmatic middle is Workers static assets plus Hono, which keeps the cheap platform primitives and restores just enough routing and middleware to feel productive. If you want the full tour of the data, AI, and security services that sit behind all this, I wrote that up in [the Cloudflare developer platform, explained like you're going to ship on it](/blog/cloudflare-developer-platform/).

## Why you would still reach for Vercel, Netlify, and Square

Going all-in on one platform is how you wake up locked in. The healthier instinct is to know what each vendor is genuinely best at and use it for exactly that.

**Vercel** is the premium Next.js experience. Incremental static regeneration, streaming server rendering, a preview URL for every pull request, the v0 UI generator, and Fluid compute, which bills only active CPU and charges nothing for the time a function spends waiting on I/O. If your team lives in Next.js and ships content-heavy, SEO-critical pages, that developer experience is worth paying for. The Pro plan is $20 per seat per month with a $20 usage credit included, and the Hobby tier is free.

**Netlify** is JAMstack simplicity. Connect a repo, set a build command, get deploy previews, and lean on niceties like Forms, which now capture submissions for free with no backend, build plugins, and Deno-based edge functions. As of its April 2026 pricing change, Netlify runs on a credit model: a free tier at 300 credits a month with one concurrent build, a $9 Personal tier, and a Pro tier at a flat $20 a month with unlimited seats and three concurrent builds. For a marketing site or a small app where you want to think about infrastructure as little as possible, it is hard to beat.

**Square** is not a web host at all, and that is the point. It is a payments and commerce backend: the Payments, Checkout, Orders, Catalog, and Inventory APIs, the Web Payments SDK that tokenizes a card in the browser so you stay out of most of PCI scope, and physical point-of-sale that shares the same catalog as your online store. You host your site wherever you like and let Square move the money. There is no monthly fee on the base plan, and you pay per transaction, currently around 2.6% plus 15 cents in person and 2.9% plus 30 cents for online API payments. The developer sandbox is free, so you can build and test a full checkout without spending a cent.

Used this way, three vendors each do one thing well. The trouble starts when one of them quietly owns something it should not.

## The lock-in nobody quotes you

Every one of these platforms creates lock-in. The skill is knowing where, and keeping it out of your core.

- **Cloudflare's deepest lock is its stateful primitives.** Your Worker code is portable web-standard JavaScript, but Durable Objects, Workflows, Vectorize, and D1 are reached through Cloudflare's bindings model and have no drop-in equivalent elsewhere. If your core domain logic lives inside Durable Objects, you cannot lift and shift it, you re-architect it. Cloudflare keeps extending these, including an MIT-licensed Dynamic Workflows library in May 2026, but it is doubling down on its own model rather than an open standard. That is the trade for the integration and the price.
- **Vercel's lock was historically Next-only features**, ISR and image optimization plus a build output structure other hosts had to reverse-engineer. That has eased a lot: Next.js 16.2 shipped a stable public Deployment Adapter API co-developed by Vercel, Cloudflare, Netlify, AWS Amplify, and Google Cloud, and Vercel's own adapter uses the same public contract with no private hooks. The OpenNext project re-implements the rest on AWS and Cloudflare. Escaping Vercel is now a known procedure rather than a rewrite.
- **Netlify locks you in through conveniences**: Forms, the `_redirects` and `_headers` configuration DSL, the Blobs storage API, and edge-function routing semantics. The function code ports because it is web-standard Deno, but the routing config and the form handling do not. It is a modest migration, not a free one.
- **Square's lock is structural and the most painful.** Card tokens that Square generates are confined to Square. Generally you cannot carry them to a new processor without re-collecting customers' card data and re-entering PCI scope, and your catalog and customer records live in Square's schema. Switching payment providers is a real project with real downtime risk, which is exactly why you wrap it early.

## A better way to balance it

The goal is not to avoid these platforms. It is to use each one's best feature while keeping an exit. A few habits do almost all of the work.

- **Keep your core on web standards.** Write your handlers against the standard `Request` and `Response`. The cross-runtime work here is real now: WinterTC, formerly WinterCG, is standardizing the common runtime surface so the same handler runs on Node, Deno, Bun, and Workers. A handler that is a pure function from request to response can be hosted by anyone.
- **Make the deploy target a config choice.** Tools like Hono's adapters, Nitro's presets, and Astro's adapters let you change providers by swapping an adapter instead of rewriting. Build one Hono app and run it on Cloudflare, then on Node, then on Deno Deploy, changing only the adapter.
- **Keep your durable data in portable stores.** Hold your system of record in your own Postgres, on Neon or Supabase, and your files in S3-compatible storage. Cloudflare R2 speaks the S3 API and charges zero egress, so you get the cheap bandwidth and keep the ability to move. Use a proprietary primitive like Durable Objects for what it is uniquely good at, ephemeral coordination, not as the database your business depends on.
- **Wrap payments behind your own interface.** Define a small `PaymentProvider` interface in your code, `createCharge`, `refund`, `saveCard`, and implement Square behind it so nothing else imports the Square SDK directly. You cannot fully escape token lock, but you can shrink the blast radius and keep a second processor a day's work away instead of a quarter's.
- **Manage it all as code.** Terraform, or its open-source fork OpenTofu, lets you codify Workers, buckets, DNS, and the rest so a parallel stack on another provider is an edit, not a week of clicking dashboards. The Cloudflare provider has been stable since its v5 release and is actively maintained.

That points at a simple decision framework. Go all-in full-stack Cloudflare when you want cheap global edge state and zero egress and you are willing to accept proprietary primitives for your core, which is a fine trade for a lot of products. Split work out to Vercel or Netlify when their framework and developer experience clearly outweigh the lock-in, and keep your data portable while you do. And isolate Square behind your own adapter no matter where you host, every time. The practical reference shape is a portable Hono or web-standard core, your own Postgres, R2 for files, Square wrapped behind an interface, all wired together with OpenTofu. No single vendor's proprietary feature gets to own your core domain, so you always keep an exit.

That is the same idea behind everything I build and the whole argument of [The $97 Launch](https://the97dollarlaunch.com/): spend your money and your hours on the product, not the plumbing, and never let the plumbing trap you. When I start a new Cloudflare build, I do not hand-write the config. The [Single Site Gen tool](/tools/single-site-gen/) generates the whole production-ready prompt, the Worker-versus-static shape, the storage bindings, a locked-down CSP, and the robots posture, so the boring parts are done correctly from the first commit.

## Related reading

- [The Cloudflare developer platform](/blog/cloudflare-developer-platform/), the full tour of Workers, D1, R2, Durable Objects, and the rest
- [What $200k AI jobs actually ask for](/blog/blog-ai-ml-github-projects-200k-jobs/), the skills side of this same edge-and-portability story
- [Netlify WAF vs Cloudflare double-CDN](/blog/blog-netlify-waf-vs-cloudflare-double-cdn/), what happens when two platforms overlap
- [SSG deployment hardening](/blog/blog-ssg-deployment-hardening/), locking down a static deploy
- [Single Site Gen](/tools/single-site-gen/), generate a Cloudflare-ready build prompt with the production patterns baked in
- [Where should a small business host its website and apps](/blog/blog-smb-web-platform-choice/), this same decision at small-business scale, part of the Practical AI Stack for Small Business series

## Fact-check notes and sources

All figures verified against the vendors' own docs and pricing pages in June 2026. Limits and prices on these platforms change often, so confirm any load-bearing number on the live page before you build on it.

- "Start with Workers, not Pages": [Cloudflare Workers best practices](https://developers.cloudflare.com/workers/best-practices/workers-best-practices/). Static assets, `run_worker_first`, SPA fallback, and the `ASSETS` binding: [Workers static assets docs](https://developers.cloudflare.com/workers/static-assets/) and the [Pages-to-Workers migration guide](https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/).
- Isolate startup (~100x faster than a Node container): [how Workers works](https://developers.cloudflare.com/workers/reference/how-workers-works/). Free plan (100k req/day, 10ms CPU) and Paid plan ($5/mo, 10M req, 30M CPU-ms, up to 5 min CPU): [Workers pricing](https://developers.cloudflare.com/workers/platform/pricing/) and [limits](https://developers.cloudflare.com/workers/platform/limits/).
- Hono (zero dependencies, `hono/tiny` under 12kB, web-standard, multi-runtime): [Hono repo](https://github.com/honojs/hono) and [Hono on Cloudflare Workers](https://hono.dev/docs/getting-started/cloudflare-workers).
- Vercel Pro ($20/seat + $20 credit), Fluid compute (active-CPU billing, $0 for I/O wait): [Vercel functions usage and pricing](https://vercel.com/docs/functions/usage-and-pricing) and [Vercel pricing](https://vercel.com/pricing).
- Netlify April 2026 credit-based pricing (Free 300 credits / 1 build, Personal $9, Pro $20 flat with unlimited seats / 3 builds, Forms now free): [Netlify pricing](https://www.netlify.com/pricing/) and the [April 2026 pricing changelog](https://www.netlify.com/changelog/2026-04-14-pricing-updates-april-2026/).
- Square fees (in-person 2.6% + 15¢, online API 2.9% + 30¢) and Web Payments SDK tokenization: [Square payments pricing](https://developer.squareup.com/docs/payments-pricing) and [Web Payments SDK overview](https://developer.squareup.com/docs/web-payments/overview).
- Lock-in and portability: Next.js 16.2 Deployment Adapter API co-developed across platforms, [Next.js across platforms](https://nextjs.org/blog/nextjs-across-platforms); [OpenNext](https://blog.logrocket.com/opennext-next-js-portability/); R2 zero-egress pricing, [R2 pricing](https://developers.cloudflare.com/r2/pricing/); WinterTC cross-runtime standardization, [InfoWorld on WinterTC](https://www.infoworld.com/article/4133640/wintertc-write-once-run-anywhere-for-real-this-time.html); Cloudflare Dynamic Workflows (MIT, May 2026), [changelog](https://developers.cloudflare.com/changelog/post/2026-05-01-dynamic-workflows/); Hono adapters, [adapter helper](https://hono.dev/docs/helpers/adapter).

*This post is informational, not a paid endorsement, and I have no affiliation with Cloudflare, Vercel, Netlify, or Square. Product names, limits, and prices are current as of mid-2026 and change; verify on each vendor's site before building on them.*


---

Canonical HTML: https://jwatte.com/blog/blog-cloudflare-frameworkless-vendor-lockin/
RSS: https://jwatte.com/feed.xml
JSON Feed: https://jwatte.com/feed.json
Hero image: https://jwatte.com/images/blog-cloudflare-frameworkless-vendor-lockin.webp
