all posts

The best Google Cloud Run alternatives in 2026

Ajay Kumar··9 min read

Cloud Run is one of the better-designed things Google ships. You give it a container that listens on $PORT, it runs it, it scales to zero, and you stop thinking about nodes. For a stateless HTTP service that does its work between the request arriving and the response leaving, it is close to ideal and I would not talk anyone out of it.

The reason people search for alternatives is almost never "Cloud Run is bad". It is that their service quietly stopped being a request. A background job starts after the response is sent. A WebSocket needs to stay open for an hour. A build pipeline needs a disk. An agent needs to hold a shell session. Cloud Run's model — CPU allocated around a request, instances that can vanish, no durable local disk — becomes something you fight rather than something you use.

I build PandaStack, which is one of the options below. I'll be specific about where it fits and where it plainly doesn't, because moving hosting platforms for the wrong reason costs more than staying.

First, name the reason you're leaving

Every alternative below is better than Cloud Run at exactly one or two things and worse at others. Pick based on which of these you're actually hitting:

  • CPU throttling outside a request. Cloud Run's default billing mode throttles CPU when no request is in flight, which silently breaks anything doing work after the response — queue consumers, cache warmers, telemetry flushes, goroutines that were fine on a VM. The always-allocated setting fixes the behaviour and changes your bill.
  • Cold starts you cannot amortise. Scale-to-zero means the first request after idle pays for the container image starting your runtime. For a JVM or a fat Python image that is seconds, and min-instances is just paying for warm capacity with extra steps.
  • The image pipeline is the actual work. If your deploy is: build image, push to Artifact Registry, update service, wait — you are maintaining a CI system to ship a Node app. Some teams want that. Many discovered they didn't.
  • You need state. Local disk is ephemeral, in-memory caches are per-instance, and sticky anything is not a supported concept. Every stateful need becomes another GCP product with its own bill and IAM policy.
  • The bill stopped tracking the work. vCPU-second and GiB-second billing is fair for spiky traffic and unkind to a service that is up all day doing very little.

The alternatives, by what they fix

Fly.io Machines — when you want the VM back

Fly Machines are fast-starting Firecracker VMs you control directly: start one, stop it, keep a volume attached, run it in a specific region. That is the closest thing to "Cloud Run but I own the lifecycle". You get persistent volumes, long-lived processes, and no request-shaped CPU model. The cost is that you are now the orchestrator — the platform will happily let you leave a machine running in a region you forgot about, and you will write more infrastructure code than Cloud Run ever asked for.

Railway and Render — when the image pipeline was the problem

Both deploy from a git repository, detect your framework, build it, and run it as a long-lived process behind a URL. If what pushed you off Cloud Run was maintaining a Dockerfile and a registry for a Rails or Express app, this is the shortest path back to shipping. You give up the aggressive scale-to-zero economics — instances mostly stay up — and you give up fine-grained control over the runtime.

Northflank and Koyeb — when you liked containers, not GCP

These keep the container model and the build pipeline but wrap it in a product that also gives you databases, jobs, and preview environments without four more consoles. Choose these when your objection is to the surrounding GCP surface — IAM, VPC connectors, Cloud SQL proxies — rather than to containers themselves.

App Runner, ECS Fargate, Azure Container Apps — when you're really moving clouds

Structurally similar to Cloud Run, so a migration is mostly config translation. Worth it if the rest of your stack lives on AWS or Azure and cross-cloud egress is the real cost. Not worth it if you expect a different execution model, because you will get the same one with different names.

PandaStack — when you want scale-to-zero without the request-shaped runtime

PandaStack runs each app in its own Firecracker microVM, deployed from a git repo with no Dockerfile. Because it is a VM rather than a request handler, a background worker, a WebSocket, or a cron job inside the app keeps running normally — there is no CPU throttling between requests to design around. Apps still scale to zero when idle and restore from a memory snapshot rather than cold-booting a runtime, and billing is per active vCPU-hour plus working-set memory, metered by the second, so an idle-but-up service costs close to nothing in CPU.

The honest limitation: PandaStack builds from source, not from a container image. If you already have a hardened image pipeline and a registry you trust, that is a real thing to give up, and one of the container platforms above is the better move. It also isn't the answer if you need GPUs or a global anycast edge.

# Deploy from a repo instead of a registry — no Dockerfile, no image push
pandastack app create --name api \
  --git-url https://github.com/acme/api \
  --git-branch main \
  --start-command 'node server.js' \
  --env NODE_ENV=production

# Every push to main redeploys; the old VM is torn down after the new one is healthy
pandastack app deploy <app-id> --follow

The migration checks that actually bite

Whichever direction you go, these are the things that break on the first deploy after a Cloud Run service moves somewhere else:

  1. Bind to 0.0.0.0 and read $PORT. This is the single most common "the logs say it started but nothing reaches it" cause on every platform, including Cloud Run itself.
  2. Find the work that assumed request-scoped CPU. If you set CPU-always-allocated to fix a bug once, that bug is background work — on a long-lived VM it now runs continuously, which is usually what you wanted but changes your resource sizing.
  3. Re-check concurrency. Cloud Run's per-instance concurrency setting hid a lot of thread-safety and connection-pool sizing questions. A long-lived process with a different concurrency profile will expose them.
  4. Replace IAM-based service-to-service auth. Cloud Run's identity tokens are convenient and non-portable. Anything calling your service with a Google-signed token needs a real auth mechanism before you cut over.
  5. Price egress, not just compute. Traffic leaving GCP to your new host during a gradual migration is billed on both sides, and dual-running is where migration budgets actually go.
If your service uses Cloud SQL through the built-in connector, that connection is the migration. Plan the database move first — a service that has moved but still dials back into GCP for every query is slower and more expensive than either end state.

Choosing, in one paragraph

If the container pipeline is fine and you only want a different cloud, take App Runner or Container Apps. If you want the VM and its lifecycle back, take Fly Machines. If Dockerfiles were the tax you resented, take a git-driven platform — Railway, Render, or PandaStack — and pick between them on whether you need long-running in-process work and scale-to-zero at the same time, which is the case where a microVM per app earns its keep. And if none of those describe your problem, the correct answer is genuinely to stay on Cloud Run.

Frequently asked questions

Is Cloud Run actually expensive?

It depends entirely on your duty cycle. For bursty traffic with long idle stretches, per-second vCPU and memory billing with true scale-to-zero is one of the cheapest models available, and most alternatives will cost more. It gets expensive in two situations: a service that is effectively always warm — where you are paying request-shaped rates for VM-shaped uptime — and a service running with CPU always allocated and a high minimum instance count, which is a reserved fleet wearing a serverless costume. Model your real request distribution over a week before assuming a move saves money.

Can I keep scale-to-zero if I move off Cloud Run?

On some platforms, yes, but check what happens on the wake path. Scale-to-zero is only useful if waking is fast, and the wake cost differs enormously: cold-booting a container image means starting your runtime and re-importing everything, while restoring a memory snapshot brings the process back roughly where it left off. Platforms that scale to zero by simply deleting your instance and rebuilding it later are technically offering the feature and practically offering a 30-second first request. Ask specifically about the wake path, not the sleep behaviour.

What breaks when I move a Cloud Run service to a long-lived VM?

Usually the assumptions that were free under request-scoped execution. In-memory caches now persist across requests, which is often a feature and occasionally a stale-data bug. Background tasks that were being throttled now run continuously and use real CPU. Connection pools that were sized per short-lived instance are now shared for hours and can exhaust the database's connection limit. Anything relying on an instance disappearing to clean up state — temp files, lock files, accumulated memory — needs an explicit cleanup path, because the process no longer restarts every few minutes.

Do I need a Dockerfile on the alternatives?

It splits cleanly. Container-first platforms — App Runner, ECS, Container Apps, Northflank, Koyeb — want an image, which means you keep your build pipeline and your registry. Git-driven platforms — Railway, Render, PandaStack — detect the project from its manifest files and build it for you, which removes the pipeline but also removes your control over the exact runtime image. If reproducibility across CI and production matters to you for compliance reasons, keep the Dockerfile; if it was pure overhead for a single Node service, drop it.

How do I test an alternative without a risky cutover?

Deploy the same commit to the new platform, point a subdomain at it, and mirror a slice of real traffic — or run your existing integration suite against it — for a week while Cloud Run keeps serving production. Watch three things: p99 latency including the wake path from idle, memory at steady state after several hours of uptime, and the total bill for the shadow deployment. Almost every unpleasant surprise in a hosting migration shows up in one of those three numbers within a few days, and none of them are visible from a single test request.

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.