all posts

The best Cloudflare Workers alternatives in 2026

Ajay Kumar··8 min read

Cloudflare Workers are a genuinely different piece of engineering: a V8 isolate rather than a container, cold starts measured in single-digit milliseconds, and a network that puts your code near everyone. When the workload fits, nothing else is close on latency or price.

The reason people go looking for alternatives is almost never that Workers are slow. It's that the isolate model has a specific shape, and their workload isn't that shape. Here's how to tell which case you're in, and where each one goes. I build PandaStack, which is one destination for exactly one of these cases.

The four constraints that send people away

1. CPU time per request

Workers cap CPU time per invocation. Wall-clock time waiting on a subrequest is generally fine; actual computation is what's metered. Image processing, PDF generation, cryptographic work, large parsing jobs, or anything running a model will hit this ceiling, and the failure is a terminated request rather than a slow one.

If you're compute-bound, you don't want a different edge platform — most have similar limits for the same physical reasons. You want a machine.

2. Node APIs and native modules

An isolate is not Node. Compatibility flags cover a growing subset of the Node API, but native modules — anything compiled, from image codecs to certain crypto libraries — cannot run at all, because there's no place to load a shared object.

This is a hard boundary rather than a performance trade-off. If your dependency tree contains a native module you can't replace with a pure-JS or WASM equivalent, the isolate model is closed to you.

3. Database connections

Traditional database drivers open a long-lived TCP connection and hold it. That's a poor match for a runtime with thousands of short-lived isolates, and the ecosystem's answer has been HTTP-based drivers and connection poolers. That works well — until you need a feature only the wire protocol exposes, like LISTEN/NOTIFY, session-level advisory locks, or COPY.

4. Long-lived state and connections

WebSocket servers, background workers, in-memory caches shared across requests, and long-running jobs all assume a process that outlives a request. Durable Objects address a real part of this and are excellent for coordination, but they're a programming model you adopt, not a place to run your existing server.

A useful test: if your handler could be described as 'read the request, call some services, return a response, forget everything', you are edge-shaped and should stay. If any sentence describing your app contains 'and then, later', you probably want a process.

Two things to try before migrating anything

Some Workers limits are real walls and some are just the first thing you hit. Before assuming you need a different platform, check whether the work can move off the request path entirely — a queue plus a consumer turns a request that exceeds the CPU budget into an acknowledgement and a job, and that pattern fits the isolate model perfectly. A surprising share of planned migrations get cancelled at this step.

The second is caching. Workers sit in front of a cache that most teams under-use, and an expensive computation that runs once per unique input rather than once per request often stops being expensive at all. Neither of these helps if a native module is your blocker — that is a genuine wall — but both are worth an afternoon before committing to a platform change measured in weeks.

Where each case goes

  • Still edge-shaped, want a different vendor: Deno Deploy, Fastly Compute, Vercel or Netlify edge functions, AWS Lambda@Edge. Similar constraints, different ergonomics and pricing — a lateral move, so be sure it fixes your actual problem.
  • Need Node proper but still request-scoped: AWS Lambda, Google Cloud Run, Vercel's Node runtime. Full Node, native modules, longer durations, higher cold starts. Cloud Run in particular is a sensible middle ground — a real container, scale-to-zero, request-scoped billing.
  • Compute-bound or holding connections: a container PaaS (Render, Railway, Fly.io, Koyeb) or a VM. One long-lived process, no per-request ceiling, no compatibility questions.
  • Executing code you didn't write: microVM platforms — Fly Machines, PandaStack (mine). Each workload gets its own kernel rather than an isolate sharing a runtime, and a machine restores from a snapshot in roughly 179ms at p50, so per-request isolation stays affordable. This is the case where I'd argue for my own category and not otherwise.

The answer that's usually right: don't move everything

Most apps that outgrow Workers outgrow them in one specific place. The routing, auth checks, redirects, caching, and A/B logic are perfectly edge-shaped and benefit enormously from running close to users. It's the image resize, the report generation, or the WebSocket that doesn't fit.

Keep the Worker as the front door and give the heavy part somewhere to live. You keep the latency benefit for the 95% of requests that never need the origin, and the awkward 5% stops being a fight with the runtime.

// Worker stays as the edge router; the compute-bound path goes to an origin
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    // Edge-shaped: cached, close to the user, sub-millisecond
    if (url.pathname.startsWith("/api/config")) {
      return new Response(env.CONFIG, { headers: { "cache-control": "max-age=60" } });
    }

    // Compute-bound: hand off to a process that has no CPU-time ceiling
    if (url.pathname.startsWith("/api/render")) {
      return fetch(env.ORIGIN + url.pathname, request);
    }

    return env.ASSETS.fetch(request);
  },
};

The short version

Hitting the CPU ceiling: you need a machine, not a different edge. Blocked by a native module: same answer, and no compatibility flag will save you. Fighting the database driver: try an HTTP driver or a pooler before migrating. Needing a long-lived process: a container PaaS. Running untrusted code: microVMs. And in most cases, keep the Worker at the front and move only the part that never belonged there.

Frequently asked questions

What are the main limits of Cloudflare Workers?

Four, and they are structural rather than tunable. CPU time per invocation is capped, so compute-heavy work like image processing, PDF generation, or model inference gets terminated rather than merely slowed. The runtime is a V8 isolate rather than Node, so native compiled modules cannot run at all and Node API coverage depends on compatibility flags. Traditional TCP database drivers are a poor fit, pushing you toward HTTP drivers or poolers and away from wire-protocol features like LISTEN/NOTIFY. And there is no long-lived process, so WebSocket servers, background workers, and caches shared across requests need Durable Objects or a different platform.

What should I use instead of Workers for CPU-heavy work?

A long-lived process on a container platform or a virtual machine, not another edge runtime. Edge platforms cap per-request CPU for the same physical reason — thousands of tenants share a machine and no one gets to monopolise it — so moving from one to another usually reproduces the problem with a different error message. A container PaaS or a microVM gives you a process with no per-request ceiling, full Node or Python, native modules, and the ability to keep expensive setup in memory between requests. Keep the edge function as a router in front of it and you lose almost none of the latency benefit.

Can I use a normal Postgres driver from Cloudflare Workers?

Not the classic long-lived TCP client, because an isolate has no persistent process to hold the connection and thousands of short-lived isolates would exhaust the database's connection limit anyway. The practical options are an HTTP-based driver, a connection pooler that fronts the database, or Cloudflare's own TCP socket support with a driver built for it. All work well for ordinary queries. What you lose is anything relying on session state over the wire protocol — LISTEN/NOTIFY, session-level advisory locks, COPY streaming, prepared statements held across requests — and if your application depends on those, a conventional server is the simpler answer.

Is Deno Deploy a good Cloudflare Workers alternative?

It is a lateral move rather than an escape. Deno Deploy has broader standard-library coverage and a more Node-like feel for some workloads, and if the ergonomics are your complaint it is a reasonable switch. But it shares the fundamental shape: an isolate-style runtime, per-request resource limits, and no long-lived process. If you are leaving Workers because of CPU limits, native modules, or the need to hold connections, you will meet the same walls there. Match the destination to the constraint that pushed you out, or you will do the migration twice.

Should I keep an edge function in front of my origin?

Usually yes, and it is the outcome most teams land on. Routing, authentication checks, redirects, header rewriting, caching, and A/B assignment are genuinely edge-shaped and benefit from running close to users, and they typically cover the large majority of requests without ever touching your origin. Only the workload that broke the model — the image resize, the long report, the socket — needs to move. Splitting that way preserves the latency and bandwidth advantages for most traffic while giving the awkward part a home where it is ordinary rather than a fight with the runtime.

Keep reading

Run code in a microVM in one API call.

49ms p50 cold start. Fork, snapshot, and scale to zero.

Start free
Written by Ajay Kumar, Founder, PandaStack.