PandaStack vs Google Cloud Run: Honest Head-to-Head
I'm Ajay. I built PandaStack, a Firecracker microVM platform, so the honest way to open this is to say where it ends: for most of what people deploy to Cloud Run, Cloud Run is the right answer and you should use it. A vendor comparison that concludes the vendor wins everything is worth what you paid for it. This is the narrower version — what each platform is, where the boundary between them actually sits, and the specific workload shapes where a microVM beats a managed container.
What each thing actually is
Cloud Run: a managed container platform with the whole of GCP behind it
Cloud Run takes a container image — or your source, in which case it builds one — and runs it on Google's infrastructure. It handles placement, request routing, TLS, autoscaling including down to zero, and revision-based rollout. Instances are request-scoped by default, with an always-on option, and Cloud Run Jobs cover the run-to-completion shape where nothing serves HTTP at all.
The important part isn't the runtime, though — it's the gravitational field around it. Cloud Run sits inside GCP: IAM, Artifact Registry, Cloud Build, Cloud SQL, Pub/Sub, VPC connectors, Cloud Logging and Trace. If your company already has a GCP org and a security team who blessed all that, adopting Cloud Run is closer to enabling a feature than onboarding a vendor. That's an enormous advantage and I won't pretend otherwise.
PandaStack: microVMs, where the unit is a machine
PandaStack runs Firecracker microVMs on KVM. Each sandbox gets its own guest kernel behind hardware virtualization, its own network namespace and tap device, and a copy-on-write root filesystem. There's no warm pool of idle VMs — every create restores a pre-baked snapshot, which is what makes a fresh machine per unit of work reasonable rather than an act of desperation.
Three products sit on that substrate: a sandbox API for untrusted or model-generated code, git-driven app hosting with scale-to-zero, and managed Postgres that can branch and do point-in-time restore. The through-line is that the primitive is a machine, not a request — you create one, keep it, exec into it repeatedly, snapshot it, fork it, and eventually kill it. Whether that sounds liberating or exhausting is most of the decision right there.
The isolation boundary, stated carefully
This is the real distinction, and also where a competitor is most tempted to overstate, so let me be precise. Cloud Run has historically run workloads inside Google's own sandboxing layer — gVisor is the widely documented lineage — and more recently offers execution environments with differing characteristics that you select per service. Google documents its isolation model and you should read that rather than mine. I won't make claims about the internals of Cloud Run's current sandbox: I don't operate it, and you shouldn't accept a competitor's characterisation of a security boundary anyway.
The safe, general point: on a managed container platform the isolation boundary is a platform decision you inherit. It is very likely a good one — Google's sandboxing work is serious engineering at a scale most of us will never see. But it's theirs. When you explain that boundary to a customer's security team, you're relaying a description rather than describing something you built. On a microVM platform each workload gets its own guest kernel behind hardware virtualization, and the boundary is an architectural property you can point at.
A container is a polite suggestion to the kernel. A sandboxed container is a polite suggestion with a very good lawyer. A microVM is a different kernel entirely, which is a much shorter conversation.
For first-party code you wrote, this distinction is mostly theatre and you shouldn't pay for it. For code an LLM produced ninety milliseconds ago, the boundary is the entire product requirement — and "we run it in a managed container platform" gets harder to defend the more sophisticated the person asking is.
Programming model and state
A request lifecycle vs a machine you hold
Cloud Run is request-shaped. Your container serves HTTP, or your job runs to completion, and the platform owns the lifecycle: when instances start, how many exist, when they go away. You don't get to hold a machine, and that's not an oversight — it's the deal. Giving up lifecycle control is what buys the autoscaling and the operational silence.
Deploying to it is about as pleasant as cloud CLIs get — both common shapes, from source and from a pre-built image. Note what the mental model contains: an image, a revision, a region, a traffic policy. No machine.
# Shape 1: deploy straight from source. Cloud Build produces the image,
# pushes it to Artifact Registry, and Cloud Run rolls out a new revision.
gcloud run deploy summarizer \
--source . \
--region us-central1 \
--allow-unauthenticated
# Shape 2: you own the build; Cloud Run just runs the artifact.
gcloud builds submit \
--tag us-central1-docker.pkg.dev/$PROJECT_ID/apps/summarizer:v3
gcloud run deploy summarizer \
--image us-central1-docker.pkg.dev/$PROJECT_ID/apps/summarizer:v3 \
--region us-central1 \
--set-env-vars "LOG_LEVEL=info" \
--min-instances 0 \
--no-allow-unauthenticated
# Run-to-completion work is a Job, not a service that happens to exit.
gcloud run jobs create nightly-report \
--image us-central1-docker.pkg.dev/$PROJECT_ID/apps/summarizer:v3 \
--region us-central1
gcloud run jobs execute nightly-report --region us-central1PandaStack's sandbox API inverts exactly that. The unit of work is a VM you create, drive, and destroy, and the interesting operations are the ones a request lifecycle can't express — repeated exec, file writes, snapshot, fork.
from pandastack import Sandbox
# A hardware-isolated microVM, restored from a baked snapshot.
# p50 ~179ms to create, p99 ~203ms. No warm pool, no image pull.
with Sandbox.create(template="code-interpreter", ttl_seconds=600) as sbx:
# The model's output goes INTO the guest. The host never runs it.
sbx.filesystem.write("/work/attempt.py", model_generated_code)
first = sbx.exec("cd /work && python3 attempt.py", timeout_seconds=60)
if first.exit_code != 0:
# Same machine, same state, second turn of the loop. This is the
# part a request-scoped instance cannot give you: the environment
# the failure happened in is still here to debug in.
sbx.filesystem.write("/work/attempt.py", repair(first.stderr))
second = sbx.exec("cd /work && python3 attempt.py", timeout_seconds=60)
print(second.exit_code, second.stdout[-500:])
artifact = sbx.filesystem.read("/work/out/report.md")
# Exiting the block kills the VM: processes, files, netns, gone together.
# ttl_seconds is the dead-man's switch for when your orchestrator crashes
# between create and kill, which it eventually will.Put those side by side and the decision mostly makes itself. If your workload is "a stateless HTTP service in a container," the first is the right shape and PandaStack would be a strictly worse way to run it. If it's "drive an environment through several turns and inspect what happened," the second describes something Cloud Run deliberately does not offer.
State, and the operations that need a machine to exist
Cloud Run instances are ephemeral by design. The correct pattern is to push state outward — Cloud SQL, Firestore, Cloud Storage — and treat the instance filesystem as scratch that may vanish between requests. That's the right default for services; statelessness is what makes the autoscaling safe.
PandaStack sandboxes can be persistent, carry a durable volume that outlives the VM, hibernate when idle, and be snapshotted and forked. Fork is worth dwelling on, because you can't bolt it onto a stateless model: it takes a warmed machine and produces a second with the same memory and disk state, copy-on-write. Same-host 400-750ms; cross-host 1.2-3.5s, because the memory has to travel.
What that buys is branch-and-explore. Warm one environment — repo cloned, dependencies installed, the agent seven steps into a task — then fork it five ways and run five candidate continuations from identical state, keeping the one that worked. On a request-scoped platform the equivalent is doing the setup five times, which is slow or expensive and usually both.
For a REST API that reads from a database and returns JSON, this matters not at all, and if you find yourself excited about fork for a CRUD service, please take a walk.
Cold starts: a design difference, not a scoreboard
Cloud Run scales to zero and cold-starts by starting a container from an image: fetch it, start it, initialise your runtime, run your startup path, become ready. How long that takes is dominated by your image and runtime — a slim Go binary and a Python service that imports half of PyPI at module scope are not the same event. Google publishes guidance and there are real levers; measure with your image rather than trusting any blog post, this one included.
PandaStack creates a VM by restoring a pre-baked Firecracker snapshot instead. The restore step is roughly 49ms; end-to-end create is p50 179ms, p99 203ms. Only a template's first-ever spawn pays a real boot, around 3 seconds; after that every create is a restore.
These are not the same operation at different speeds. Restoring a snapshot skips the whole process-startup phase — the guest is already booted, the runtime loaded, the imports done, the server listening, and restore just puts that state back. That's where most container cold-start time actually goes, and snapshot restore doesn't optimise it so much as decline to do it.
The cost is real, and Cloud Run doesn't ask it of you: the snapshot has to be baked and kept current. A snapshot is a frozen machine, so it also freezes your dependency set, your OS packages, and — a fun one we learned in production — the guest's clock. Every meaningful change means a re-bake. Cloud Run's model, where the artifact is just an image and startup is just startup, has genuinely lower overhead. If your create rate is low, that trade isn't worth making.
Ecosystem and ops reality, where Cloud Run wins outright
No hedging in this section, because hedging here is how a comparison post loses a reader permanently. Cloud Run is embedded in GCP, and that's worth more than any latency number on this page. IAM means your service identity, least-privilege policy, and audit trail are the ones your org already uses. VPC connectivity means private networking to resources that were never going to be public. Cloud SQL means a database your DBA has already run. Managed TLS and custom domains, a broad regional footprint, org policy, logging and tracing that already have dashboards pointed at them. Support contracts. Procurement that's already done. A security review that happened in 2023 and doesn't need to happen again this quarter.
A specialised platform cannot match that, and I won't claim PandaStack does. "Already approved, already integrated, already paid for" is a category of advantage you can't engineer past. If your workload fits Cloud Run's shape at all, the integration story alone is usually decisive.
Cost models, described structurally
Structurally rather than numerically — both sides move, and a stale price is worse than none. Verify Cloud Run's current pricing page before modelling anything.
Cloud Run's model is request and instance-time shaped: you're billed for what instances consume while they exist, and scale-to-zero means a service nobody calls should cost approximately nothing. PandaStack's is resource-time on a microVM — you pay for a machine while it's alive — with idle sleep and TTLs stopping "alive" from being permanent. Which is cheaper depends entirely on your duty cycle.
The trap is identical on both platforms: scale-to-zero is only cheap if the thing actually goes to zero. Uptime monitors, scanners, crawlers, health checks, a CI job pinging the URL, and the observability stack you installed to detect outages are collectively excellent at keeping a service warm around the clock. We built a traffic classifier for exactly this, after watching apps that should have been asleep stay awake all month serving robots. Look at what's hitting your idle service before you believe any savings estimate.
Side by side, and how to choose
Shapes, not specs. The Cloud Run column reflects public documentation at time of writing — verify against Google's current docs.
- Unit of isolation — Cloud Run: a container instance inside Google's managed sandboxing layer, with execution environments you select per service; Google documents the model, read it there. PandaStack: a Firecracker microVM with its own guest kernel behind KVM hardware virtualization, one per sandbox.
- Programming model — Cloud Run: your container serves HTTP, or a Job runs to completion; the platform owns lifecycle and you never hold a machine. PandaStack: you create a VM, exec into it repeatedly, write files, and destroy it explicitly.
- State — Cloud Run: instances are ephemeral by design; durable state belongs in Cloud SQL, Firestore, or Cloud Storage. PandaStack: sandboxes can be persistent, carry durable volumes, and hibernate with state intact.
- Cold start — Cloud Run: start a container from an image and initialise your runtime; dominated by image size and startup path, improvable with levers Google documents. PandaStack: restore a pre-baked snapshot — restore ~49ms, create p50 179ms / p99 203ms, ~3s only for a template's first-ever boot.
- Fork and snapshot — Cloud Run: not part of the model; revisions are versions of a deployment, not branches of a running machine. PandaStack: copy-on-write memory and disk fork of a live VM, 400-750ms same-host, 1.2-3.5s cross-host.
- Ecosystem integration — Cloud Run: deep and hard to beat — IAM, VPC, Cloud SQL, Artifact Registry, Cloud Build, Pub/Sub, Cloud Logging and Trace, org policy, existing contracts. PandaStack: a focused API surface and its own primitives; no pretending otherwise.
- Untrusted-code fit — Cloud Run: possible, but you inherit a boundary Google owns and documents; check your requirements against their security docs directly. PandaStack: the primary design target — hardware virtualization per execution, per-sandbox network namespace, a boundary you can point at in a review.
- Managed database story — Cloud Run: Cloud SQL and the rest of GCP's data estate, mature and well-integrated. PandaStack: managed Postgres on microVMs with branching and point-in-time restore, 30-90s to create. Narrower, but branchable.
- Ops burden — Cloud Run: low, lower still if your org already lives in GCP. PandaStack: low for sandboxes and git-driven apps, but snapshots must be baked and kept current — real work Cloud Run never asks of you.
Choose Cloud Run if
- Your workload is a stateless HTTP service or a run-to-completion job, running code you wrote and trust. That's the overwhelming majority of everything, and Cloud Run is excellent at it.
- You're already on GCP. IAM, VPC, Cloud SQL, existing alerting, and a security review you don't have to redo outweigh any architectural argument in this post.
- You need org-level governance — policy constraints, service perimeters, audit trails, a support contract, a procurement path that exists.
- Your traffic is spiky and request-shaped, and you want autoscaling including to zero without building it.
- You want the platform to own instance lifecycle. Not thinking about machines is the product, and it's a good product.
- Your regional footprint requirements are broad. A specialised platform will not match a hyperscaler's map.
Choose PandaStack if
- You're executing untrusted or model-generated code and the isolation boundary is a product requirement you have to defend, not an implementation detail you inherit.
- Your unit of work is a machine held across many turns — an agent that writes files, runs commands, reads the failure, and retries in the same environment.
- You need fork: branch a warmed environment into several parallel explorations from identical state, and keep the one that worked.
- You create environments constantly and per-create latency sits on a user-facing path, so skipping process startup actually shows up in your product.
- You want a stateful sandbox with a durable volume and idle hibernation, rather than pushing every byte of state outward because the runtime insists.
- You want a Postgres you can branch for a preview environment, with point-in-time restore, rather than a copy job.
For the case that looks most like Cloud Run's "deploy from source" — a web app from a git repo — PandaStack has a closer analogue:
# Git-driven app hosting: build in a microVM, blue-green flip, scale to zero.
pandastack apps create --name summarizer \
--git-url https://github.com/acme/summarizer \
--git-branch main \
--start-cmd 'node dist/server.js'
pandastack apps env set summarizer LOG_LEVEL info
pandastack apps deploy summarizer
# A managed Postgres, cloned into a branch for a preview environment.
pandastack db create --label prod
pandastack db clone db_prod --label preview-checkoutSame ergonomic promise Cloud Run makes — push code, get a URL — with a microVM underneath and a branchable database next to it. It is not a replacement for Cloud Run's integration surface. Different trade, not a superset.
Where a microVM is overkill
The failure mode I see most often is a team reaching for hardware isolation because it sounds more secure, without a threat model that requires it. If the code inside is code you wrote and reviewed, a microVM boundary is mostly protecting you from yourself.
- First-party stateless services. If nothing hostile ever runs inside, you're paying a complexity tax for a boundary you don't need.
- Deep GCP integration. VPC-private access to internal resources, workload identity federation, org policy enforcement — that's a GCP-shaped requirement and it deserves a GCP-shaped answer.
- Anything GPU. PandaStack has no GPU offering at all. If accelerators are in your requirements, we are not on your list and I'd rather say so plainly.
- Low create rates. If you spin up an environment a few times a day, the difference between a snapshot restore and a container start is invisible, and snapshot maintenance is pure overhead you didn't need to take on.
- Compliance programmes requiring a specific certified provider. Check that before the architecture; it's a shorter conversation and it often ends the discussion.
The most common healthy outcome isn't picking one. It's Cloud Run running the product — API, frontend, workers — and a microVM sandbox handling the slice where you execute code you didn't write. Those are different problems that happen to share a verb, and treating them as one is the fastest route to a bad architecture.
Frequently asked questions
Can I just run untrusted or AI-generated code on Cloud Run?
You can run code on Cloud Run, and Google documents its sandboxing and execution environments — read that documentation directly rather than trusting a competitor's summary, including mine. The structural point worth understanding is that on any managed container platform the isolation boundary is a platform decision you inherit and configure within, not one you design. If executing untrusted code is a core product requirement rather than an incidental one, write down exactly what boundary you need to be able to attest to, then check Google's current security documentation against that list. A microVM platform gives each execution its own guest kernel behind hardware virtualization, which is a different and easier thing to describe in a security review.
Is PandaStack faster than Cloud Run at cold starts?
They're doing different operations, so the comparison is less useful than it looks. PandaStack restores a pre-baked Firecracker snapshot — roughly 49ms for the restore step, p50 179ms and p99 203ms end to end — which works because the guest is already booted and your runtime is already loaded. Cloud Run starts a container from an image and initialises your runtime, and how long that takes depends heavily on your image and startup path; measure it yourself with Google's guidance rather than trusting a number from a blog. The real trade is that snapshots must be baked and kept current, which is ongoing work Cloud Run never asks of you.
Should I migrate my Cloud Run services to PandaStack?
For a stateless HTTP service running your own code, almost certainly not. Cloud Run is well-suited to that shape, and if you're already in GCP the integration story — IAM, VPC, Cloud SQL, logging, org policy, an existing contract — outweighs anything a specialised platform offers. The migration worth considering is narrower and usually additive: the specific slice of your system that executes untrusted or model-generated code, holds a stateful environment across many turns of an agent loop, or needs to fork a warmed machine. Most teams end up running both rather than replacing one with the other.
What does fork give me that Cloud Run revisions don't?
They solve unrelated problems. A Cloud Run revision is a version of a deployment — a new image and configuration you can shift traffic to. A fork is a copy of a running machine's live state, memory and disk, made copy-on-write: 400-750ms on the same host, 1.2-3.5s across hosts. That lets you warm an environment once — repo cloned, dependencies installed, an agent several steps into a task — then branch it into parallel explorations that all start from the identical state and keep the one that worked. Nothing in a stateless request-scoped model expresses that operation, because there's no persistent machine state to copy.
Does scale-to-zero actually save money on either platform?
Only if the thing genuinely reaches zero, and it very often doesn't. Uptime monitors, security scanners, search crawlers, health checks, CI jobs pinging a URL, and your own observability stack are collectively excellent at keeping a service warm around the clock, which converts your scale-to-zero service into an always-on one that you're still modelling as free. This happens on both platforms. Before you estimate savings on either, look at your actual idle-hours traffic and work out how much of it is a human. We ended up building traffic classification specifically because apps that should have been asleep were serving robots all month.
Keep reading
- Best Google Cloud Run alternatives in 2026 — The wider survey if this 1:1 didn't produce your answer.
- Firecracker vs Google Cloud Run — The same boundary question at the VMM level, without the product framing.
- Why bot traffic keeps your scale-to-zero service awake — The shared trap, and the traffic classification that fixes it.
- PandaStack sandboxes — The microVM primitive behind the code snippets above.
49ms p50 cold start. Fork, snapshot, and scale to zero.