GCP's serverless story has three doors: Cloud Run, Cloud Functions (now Cloud Run Functions under the hood), and App Engine. From the docs they look like overlapping options. In practice each has a narrow sweet spot, and picking wrong means re-platforming a year later.
Cloud Run — the default for almost everything
Cloud Run runs any container that listens on a port. It's the right answer for ~80% of new workloads:
- HTTP services, APIs, internal tools
- Background workers triggered by Pub/Sub or Cloud Tasks
- Cron-scheduled jobs (via Cloud Run Jobs)
It scales to zero, scales out to thousands, and you keep full control over the runtime. The default unless something else is clearly better.
Cloud Functions — only for true one-shot triggers
Cloud Functions makes sense when:
- The function is genuinely small (a single handler, no shared deps)
- It's triggered by a GCP event source (Storage object created, Firestore write, Pub/Sub message) and that's its whole purpose
- You don't want to think about a Dockerfile
For anything that grows past a single file or needs custom build steps, you'll be happier on Cloud Run from day one.
App Engine — only for existing workloads, not new ones
App Engine Standard still has a place if you're already on it. For new projects in 2025, there's almost no reason to pick it — Cloud Run gives you more flexibility and similar pricing.
App Engine Flexible is even more clearly superseded by Cloud Run.
The decision in one sentence
Default to Cloud Run. Reach for Cloud Functions only when the entire unit of work is a single event handler. Don't start on App Engine in 2025.
If you're already on App Engine and it works, don't migrate just for the sake of it. But when the next service comes up, build it on Cloud Run.
