Develop, test & deploy on Cloud Run
Before an app goes live on Cloud Run there is a short arc: decide whether it fits, turn source into a running container, honor the runtime contract, pick an execution environment, reach your data, and test it locally. This page walks that arc. The runtime states a container passes through (starting, idle, shutting down) are on Cloud Run container lifecycle.
Is your app a good fit for Cloud Run?
- Serves requests, streams, or events over HTTP, HTTP/2, WebSockets, or gRPC - or runs to completion as a job.
- Needs no local persistent disk - a local ephemeral (in-memory) or network file system is enough.
- Is built to run as multiple instances simultaneously (stateless, horizontally scalable).
- Needs at most 8 CPU and 32 GiB memory per instance.
- Is containerized, or written in Go, Java, Node.js, Python, or .NET (so it can be containerized for you), or you can otherwise containerize it.
An app is a good fit only if it meets every criterion. The 8 CPU / 32 GiB ceiling and the no persistent local disk rule are the two that most often disqualify an otherwise-portable app.
From source to a running service
Two paths get your code to a running service, and both end at a container Cloud Run runs:
- Container path - you build and package the image yourself (any language), push it to Artifact Registry, then deploy. This is the deploy loop on the section overview.
- Source-based path - skip the Dockerfile. Deploy your source and let Cloud Run build the image for you with Buildpacks.
Source-based deploy supports Go, Node.js, Python, Java, .NET Core, and Ruby. If a Dockerfile is present it is used; if not, Buildpacks packages your app and its dependencies into a container image.
You never have to write a Dockerfile. gcloud run deploy --source (or the equivalent in Cloud Code) hands your source to Buildpacks, which produces the image and deploys it in one step.
Container runtime contract
Whatever language or base image you use, the container must honor Cloud Run's runtime contract. Executables must be compiled for Linux 64-bit; images may be Docker Image Manifest V2 (schema 1 or 2) or OCI format.
- Listen for requests on the correct port - default 8080, configurable via
$PORT. - Send a response within the request timeout (max 1 hour), including container startup time, or the request ends with a 504.
- Do not implement TLS yourself.
- Exit with code 0 on success, a non-zero exit code on failure.
- Do not listen on a port or start a web server - jobs do not serve requests.
Never implement transport-layer security in your container. Cloud Run terminates TLS for HTTPS and gRPC, then proxies plain HTTP/1 or gRPC to your container. For HTTP/2, handle requests in HTTP/2 cleartext (h2c).
Execution environments
Cloud Run runs services and jobs in one of two execution environments. Services default to first generation and can be switched; jobs always use second generation and cannot be changed.
| First generation | Second generation | |
|---|---|---|
| Default for | Services (changeable) | Jobs (cannot be changed) |
| Cold start | Faster - shorter cold starts | Slower cold starts |
| Linux compatibility | Emulates most, but not all, system calls | Full Linux - all syscalls, namespaces, cgroups |
| Network file system | Not supported | Supported (required for NFS / Filestore) |
| CPU & network | Standard | Faster CPU, faster network under packet loss |
| Best when | Scale out fast, spiky or infrequent traffic, < 512 MiB memory | Steady traffic, CPU-intensive work, NFS needed, or gen-1 syscall gaps |
To mount a network file system (Filestore, or Cloud Storage via Cloud Storage FUSE) on a service, you must deploy it in the second generation environment. Jobs already run on gen 2.
File system and data storage access
Every container gets a writable in-memory file system. Writes consume the instance's allocated memory and do not persist past the instance - treat it as a per-request cache or scratch space, not storage.
For durable data:
- Standard file semantics - use Filestore or another self-managed network file system, which needs the second generation environment. Cloud Storage FUSE mounts a bucket as a file system.
- No file system needed (simplest) - use cloud data storage client libraries to talk directly to Firestore, Cloud SQL, Spanner, Cloud Storage, Memorystore, and BigQuery.
- Writable, backed by the instance's allocated memory.
- Not persisted - data is gone when the instance stops.
- Default 512 MiB memory per instance (writes count against it); configurable up to 32 GiB.
Local development and testing
Run and test the container on your machine before deploying. Three options:
Cloud Code
Cloud Code is a set of IDE plugins for building, deploying, and integrating apps with Google Cloud.
- Plugins for VS Code, IntelliJ, and Cloud Shell.
- Create and deploy Kubernetes and Cloud Run apps from sample templates.
- Run and debug locally in a Cloud Run emulator (configure CPU/memory, env vars, Cloud SQL connections).
- Log streaming and viewing.
Local testing options
| Cloud Code | gcloud CLI | Docker | |
|---|---|---|---|
| How | Cloud Run emulator inside your IDE | Local dev environment that emulates Cloud Run | docker run the image locally |
| Builds with | The emulator | Dockerfile if present, else Buildpacks | Your Dockerfile |
| Auto-rebuild on change | Yes | Yes | No |
| Test URL | URL shown in IDE output | http://localhost:8080/ | http://localhost:<PORT>/ |
| Best for | IDE-integrated run + debug | CLI workflow | You already use Docker |
Recap
- Resource ceiling: 8 CPU, 32 GiB memory per instance.
- Default port: 8080 (configurable via
$PORT). - Request timeout: up to 1 hour, else a 504.
- Job result: exit 0 = success, non-zero = failure.
- Network file system (Filestore / Cloud Storage FUSE) requires the second generation environment.
Build the image yourself when you need a specific base image or full control of the build. Choose source-based (--source, Buildpacks) when you want Cloud Run to build and deploy from source in one step - supported for Go, Node.js, Python, Java, .NET Core, and Ruby.