Skip to main content
BlogDevOps

Cloud Run vs Cloud Functions: Which Google Serverless Platform Should You Use?

A practical comparison of Cloud Run and Cloud Functions from real production deployments — covering cold starts, pricing, concurrency, and when each platform wins.

Matthews Wong

Software Engineer

June 202510 min read
DevOps

In August 2024, Google folded Cloud Functions (2nd gen) into the Cloud Run umbrella and rebranded it as 'Cloud Run functions'. That naming change tells you something important: under the hood, they now share the same infrastructure. But the developer experience, pricing model, and right use cases still differ significantly. Here's the honest breakdown: Cloud Run suits REST APIs and background workers, while Cloud Run functions suit event-driven Pub/Sub processors and webhook handlers.

DimensionCloud RunCloud Run Functions
Deployment modelAny container, custom DockerfileManaged function handler, no Dockerfile
Best trigger typeArbitrary HTTP, multi-route APIsGCP events: Pub/Sub, GCS, Firestore, Scheduler
Concurrency per instanceUp to 80+, configurable to 10001 by default, configurable to 1000 for HTTP
Cold start1-3s for a lean container, 30s+ with heavy ML deps200-800ms for lightweight runtimes
Cost sweet spotHigh-frequency, sustained trafficLow-frequency, bursty traffic
PortabilitySame container runs on GKE, DigitalOcean, or local DockerGCP-managed runtime only

What Changed in 2024 and Why It Matters

Before the rebrand, Cloud Functions (2nd gen) already ran on Cloud Run internally. Google made this explicit by merging the two products under one brand. Cloud Run functions is now Google's FaaS offering — single-purpose HTTP or event-triggered functions with a managed execution environment. Cloud Run is the container-based platform for anything more complex: multi-route APIs, long-running jobs, WebSocket servers, or workloads that need custom base images. The key difference is no longer infrastructure — it's the deployment model and how you think about your code.

Cloud Run: Containers, Full Control

Cloud Run deploys any container that listens on a port. You bring your own Dockerfile, pick any language runtime, bundle dependencies, and define health check endpoints. One Cloud Run service can handle multiple routes — you can deploy an entire Express or FastAPI app as a single service. Cloud Run supports up to 80 concurrent requests per instance by default (configurable up to 1000), which dramatically reduces cold starts for bursty traffic compared to per-request function isolation. Startup time depends on your container size — a lean Node.js container starts in 1-3 seconds; a heavy Python container with ML deps might take 10-15 seconds.

Cloud Run Functions: Simpler, Event-Driven

Cloud Run functions (formerly Cloud Functions 2nd gen) is optimized for single-purpose, event-driven execution. You write a function handler in Node.js, Python, Go, Java, Ruby, or PHP — no Dockerfile required. Triggers include HTTP requests, Pub/Sub messages, Cloud Storage events, Firestore writes, and Cloud Scheduler. The platform manages the runtime, handles concurrency internally, and scales to zero when idle. For a Pub/Sub consumer processing 100 messages per day, Cloud Run functions is dramatically simpler than maintaining a Cloud Run service with a Pub/Sub push subscription.

From my experience: use Cloud Run functions for anything triggered by a Google Cloud event (Pub/Sub, GCS, Firestore, Scheduler) and Cloud Run for anything that receives arbitrary HTTP traffic. The deciding factor is not complexity — it's trigger type. A complex webhook processor is still a better fit for Cloud Run functions than a simple multi-route API on Cloud Run. The moment you need a custom base image or want to handle multiple routes efficiently, switch to Cloud Run.

Pricing: Where the Difference Actually Matters

Both platforms bill for CPU, memory, and requests processed. The free tier includes 180,000 vCPU-seconds, 360,000 GiB-seconds, and 2 million requests per month in us-central1. For low-traffic workloads, both platforms cost essentially nothing. The divergence appears at scale. Cloud Run's support for 80+ concurrent requests per instance means one instance handles a burst of traffic that would spawn 80 separate Cloud Run functions instances. If your function takes 200ms to execute and costs $0.000000231 per vCPU-second, 1 million requests per day costs roughly $5-10/month — often cheaper than maintaining a Cloud Run service at minimum scale.

Cold Start Comparison

Cold starts are the primary operational concern with any serverless platform. Cloud Run functions cold starts run 200-800ms for lightweight runtimes (Node.js, Python without heavy imports). Cloud Run cold starts depend entirely on your container — a minimal container adds 1-3 seconds; a container loading a TensorFlow model might take 30+ seconds. Cloud Run's concurrency model helps: once an instance is warm, it handles concurrent requests without spawning new instances. For traffic with predictable spikes, set Cloud Run's minimum instances to 1 to eliminate cold starts entirely (costs roughly $10-15/month for a minimal CPU allocation).

┌─────────────────────────────────────────────────────────┐
│              Google Cloud Serverless Platforms           │
├─────────────────────────┬───────────────────────────────┤
│      Cloud Run          │     Cloud Run Functions        │
│  (container-based)      │     (event-driven FaaS)        │
├─────────────────────────┼───────────────────────────────┤
│ • Any language/runtime  │ • Managed runtime (no Docker)  │
│ • Multi-route HTTP      │ • Single-purpose handler       │
│ • 80+ concurrent req    │ • Event triggers (Pub/Sub etc) │
│ • Custom base image     │ • Scale to zero by default     │
│ • Longer cold starts    │ • 200-800ms cold starts        │
└─────────────────────────┴───────────────────────────────┘

Concurrency: The Most Misunderstood Difference

Cloud Run instances handle multiple concurrent requests. Cloud Run functions, by default, handle one request per instance (though you can now configure concurrency up to 1000 for HTTP-triggered functions). For a function processing a 10-second Pub/Sub message, with default concurrency, 100 simultaneous messages spawn 100 instances. With Cloud Run and concurrency set to 100, one instance handles all of them. This matters enormously for cost and cold start frequency when processing high-volume event streams.

I made this mistake early on: I deployed a Cloud Run service for a webhook handler that received maybe 500 requests per day. The service sat at minimum 1 instance to avoid cold starts, costing me $12/month for essentially idle compute. A Cloud Run function would have handled those 500 requests for fractions of a cent with zero cold start cost because the infrequent traffic pattern perfectly matches the scale-to-zero model. Right-size to the traffic pattern: high-frequency sustained traffic favors Cloud Run with concurrency; low-frequency bursty traffic favors Cloud Run functions with scale-to-zero.

My Take: When to Choose Each

My rule of thumb: use Cloud Run for web APIs and scheduled background jobs, and Cloud Run functions for any GCP event integration (Pub/Sub, GCS triggers, Firestore onCreate hooks). If I were starting a new project today, I'd default to Cloud Run for APIs and reach for Cloud Run functions only for event-driven glue code. Cloud Run's container model is more portable — you can run the same container on DigitalOcean, GKE, or a local Docker setup, making local development and debugging significantly easier.

Migration Between the Two

Moving from Cloud Run functions to Cloud Run is straightforward: wrap your function handler in a simple HTTP server (Express for Node.js, Flask for Python), containerize it, and deploy to Cloud Run. The Pub/Sub trigger moves from a native function trigger to a Cloud Run push subscription. Moving from Cloud Run to Cloud Run functions is harder because Cloud Run functions enforce a single-entry-point model — you'd need to decompose a multi-route app into separate functions. Plan your architecture before committing to one model, especially if you expect the service to grow.

FAQ

Frequently Asked Questions

Short answers to what readers ask most about this topic.

What is the key difference between Cloud Run and Cloud Run functions after the 2024 rebrand?

After Google's 2024 rebrand, both products share the same underlying infrastructure, but differ in their deployment model. Cloud Run deploys containerised services that can handle multiple routes and custom runtimes via a Dockerfile, while Cloud Run functions (formerly Cloud Functions 2nd gen) is designed for single-purpose, event-driven handlers that require no Dockerfile. The deciding factor is not complexity but trigger type.

When should I choose Cloud Run functions over Cloud Run?

Use Cloud Run functions for anything triggered by a Google Cloud event — Pub/Sub messages, Cloud Storage events, Firestore writes, or Cloud Scheduler. Use Cloud Run for workloads that receive arbitrary HTTP traffic, need a custom base image, or must handle multiple routes efficiently. A complex webhook processor is still a better fit for Cloud Run functions than a simple multi-route API on Cloud Run.

How does concurrency affect cold starts and cost on each platform?

Cloud Run handles up to 80 concurrent requests per instance by default (configurable to 1000), so one warm instance absorbs traffic bursts without spawning new instances. Cloud Run functions default to one request per instance, meaning 100 simultaneous Pub/Sub messages spawn 100 separate instances. This difference has a large impact on both cold-start frequency and cost at high event volumes.

What is a common cost mistake to avoid with Cloud Run?

Keeping a Cloud Run service at minimum 1 instance to avoid cold starts can cost around $12/month for very low-traffic workloads like a webhook handler receiving ~500 requests per day. That same traffic would cost fractions of a cent on Cloud Run functions because the scale-to-zero model matches infrequent, bursty request patterns perfectly. Right-size to the traffic pattern: sustained high-frequency traffic suits Cloud Run; low-frequency bursty traffic suits Cloud Run functions.

How easy is it to migrate between Cloud Run and Cloud Run functions?

Migrating from Cloud Run functions to Cloud Run is straightforward: wrap the function handler in an HTTP server (Express for Node.js, Flask for Python), containerise it, and redeploy. Going the other direction is harder because Cloud Run functions enforce a single-entry-point model, requiring a multi-route app to be decomposed into separate functions. It is best to plan your architecture before committing to either model, especially if the service is expected to grow.