Cloud Run is a serverless platform that runs stateless containers, while App Engine is a Platform-as-a-Service (PaaS) that runs applications.

Let’s see Cloud Run in action. Imagine you have a Go application that serves a simple HTTP API.

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

func handler(w http.ResponseWriter, r *http.Request) {
	name := os.Getenv("TARGET")
	if name == "" {
		name = "World"
	}
	fmt.Fprintf(w, "Hello, %s!\n", name)
}

func main() {
	http.HandleFunc("/", handler)
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}
	log.Printf("Listening on port %s", port)
	if err := http.ListenAndServe(":"+port, nil); err != nil {
		log.Fatal(err)
	}
}

To deploy this to Cloud Run, you first containerize it. A Dockerfile might look like this:

# Use the official Golang runtime as a parent image
FROM golang:1.18 as builder

# Set the working directory in the container
WORKDIR /app

# Copy the Go module files and download dependencies
COPY go.mod go.sum ./
RUN go mod download

# Copy the source code
COPY *.go ./

# Build the Go app
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server .

# Use a minimal base image for the final stage
FROM alpine:latest

# Copy the built executable from the builder stage
COPY --from=builder /app/server /server

# Expose the port the application will listen on
EXPOSE 8080

# Command to run the executable
CMD ["/server"]

Then, you build the Docker image and push it to Google Container Registry (GCR) or Artifact Registry:

# Set your project ID and image name
PROJECT_ID="your-gcp-project-id"
IMAGE_NAME="my-go-api"

# Build the Docker image
docker build -t gcr.io/${PROJECT_ID}/${IMAGE_NAME}:latest .

# Push the Docker image to GCR
docker push gcr.io/${PROJECT_ID}/${IMAGE_NAME}:latest

Finally, you deploy this image to Cloud Run:

gcloud run deploy my-go-api \
  --image gcr.io/${PROJECT_ID}/${IMAGE_NAME}:latest \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --set-env-vars TARGET="Cloud Run"

Cloud Run will then provide you with a public URL. When you access this URL, you’ll see "Hello, Cloud Run!". The TARGET environment variable is set to "Cloud Run", and Cloud Run automatically assigns a PORT environment variable that your application listens on.

Now, let’s consider App Engine. App Engine is designed for applications written in specific languages (Go, Python, Java, Node.js, PHP, Ruby, .NET) and manages the underlying infrastructure for you. For the same Go application, you’d create an app.yaml file:

runtime: go118
entrypoint: go run main.go
env_variables:
  TARGET: "App Engine"

And deploy it using:

gcloud app deploy

App Engine also provides a URL, and hitting it would display "Hello, App Engine!".

The core difference lies in abstraction and flexibility. Cloud Run offers maximum flexibility by letting you containerize any language or binary, giving you fine-grained control over your environment. App Engine abstracts away more, offering a more opinionated PaaS experience that’s simpler for supported runtimes but less customizable. Cloud Run scales down to zero instances, meaning you pay nothing when your service isn’t receiving traffic. App Engine Standard also scales to zero, but App Engine Flexible does not, incurring costs even when idle.

What most people miss about Cloud Run is its ability to run any executable, not just web servers. You can deploy background workers, scheduled jobs, or even simple command-line tools as containers. Cloud Run executes the CMD or ENTRYPOINT of your container. If that command is a long-running process that doesn’t listen on a port (e.g., a batch job), Cloud Run will still run it, but it won’t be accessible via HTTP. You’d typically trigger these non-HTTP services using Cloud Scheduler or Cloud Tasks.

Choosing between them often comes down to your application’s needs. If you need maximum control, want to use a specific binary or language not directly supported by App Engine, or prefer the explicit container model, Cloud Run is likely your choice. If you’re building a standard web application within one of the supported runtimes and value a simpler deployment experience with less infrastructure management, App Engine is a strong contender.

The next step in understanding these services is exploring their networking and security features, such as VPC connectors for private access and IAM for fine-grained control.

Want structured learning?

Take the full Cloud-run course →