Cloud Run functions execution environment

Cloud Run functions run in a fully-managed serverless environment where Google handles infrastructure, operating systems, and runtime environments. Each function runs in its own isolated secure execution context, scales automatically, and has a lifecycle independent from other functions.

Runtimes

Cloud Run functions supports multiple language runtimes. Each contains a standard set of system packages, as well as the tools and libraries needed for that language. You'll need the Runtime ID value if you're deploying functions from the command line or through Terraform.

Security and maintenance updates are made available to all Cloud Run functions and Cloud Run functions (1st gen) execution environments. These updates are applied automatically or manually, depending on the environment and how you've configured it. For more information about execution environment updates, see Secure your Cloud Run function.

Runtime images are hosted in every region where Artifact Registry is available. You can customize the runtime image path by replacing the first portion of the URI with your region of choice:

REGION-docker.pkg.dev/serverless-runtimes/STACK/runtimes/RUNTIME_ID

Replace:

  • REGION with the preferred region, for example us-central1
  • STACK with the preferred operating system stack, for example google-22-full
  • RUNTIME_ID with the runtime ID used by your function, for example python310

For example, the latest Node.js 20 base image using the google-22-full stack, hosted in us-central1 would be referenced with this URL: us-central1-docker.pkg.dev/serverless-runtimes/google-22-full/runtimes/nodejs22

Node.js

Runtime Generation Runtime ID Stacks Runtime base image
Node.js 22 Run functions nodejs22 google-22-full google-22-full/nodejs22
Node.js 20 1st gen, Run functions nodejs20 google-22-full google-22-full/nodejs20
Node.js 18 1st gen, Run functions nodejs18 google-22-full google-22-full/nodejs18
Node.js 16 1st gen, Run functions nodejs16 google-18-full google-18-full/nodejs16
Node.js 14 1st gen, Run functions nodejs14 google-18-full google-18-full/nodejs14
Node.js 12 1st gen, Run functions nodejs12 google-18-full google-18-full/nodejs12
Node.js 10 1st gen, Run functions nodejs10 google-18-full google-18-full/nodejs10
Node.js 8 1st gen, Run functions nodejs8 Decommissioned Decommissioned
Node.js 6 1st gen, Run functions nodejs6 Decommissioned Decommissioned

Python

Runtime Generation Runtime ID Stacks Runtime base image
Python 3.12 1st gen, Run functions python312 google-22-full google-22-full/python312
Python 3.11 1st gen, Run functions python311 google-22-full google-22-full/python311
Python 3.10 1st gen, Run functions python310 google-22-full google-22-full/python310
Python 3.9 1st gen, Run functions python39 google-18-full google-18-full/python39
Python 3.8 1st gen, Run functions python38 google-18-full google-18-full/python38
Python 3.7 1st gen, Run functions python37 google-18-full google-18-full/python37

Go

Runtime Generation Runtime ID Stacks Runtime base image
Go 1.23
(Preview only)
Run functions go123 google-22-full google-22-full/go123
Go 1.22 Run functions go122 google-22-full google-22-full/go122
Go 1.21 Run functions go121 google-22-full google-22-full/go121
Go 1.20 Run functions go120 google-22-full google-22-full/go120
Go 1.19 1st gen, Run functions go119 google-22-full google-22-full/go119
Go 1.18 1st gen, Run functions go118 google-22-full google-22-full/go120
Go 1.16 1st gen, Run functions go116 google-18-full google-18-full/go116
Go 1.13 1st gen, Run functions go113 google-18-full google-18-full/go113
Go 1.11 1st gen, Run functions go111 Decommissioned Decommissioned

Java

Runtime Generation Runtime ID Stacks Runtime base image
Java 21 Run functions java21 google-22-full google-22-full/java21
Java 17 1st gen, Run functions java17 google-22-full google-22-full/java17
Java 11 1st gen, Run functions java11 google-18-full google-18-full/java11

Ruby

Runtime Generation Runtime ID Stacks Runtime base image
Ruby 3.3 1st gen, Run functions ruby33 google-22-full google-22-full/ruby33
Ruby 3.2 1st gen, Run functions ruby32 google-22-full google-22-full/ruby32
Ruby 3.0 1st gen, Run functions ruby30 google-18-full google-18-full/ruby30
Ruby 2.7 1st gen, Run functions ruby27 google-18-full google-18-full/ruby27
Ruby 2.6 1st gen, Run functions ruby26 google-18-full google-18-full/ruby26

PHP

Runtime Generation Runtime ID Stacks Runtime base image
PHP 8.3 Run functions php83 google-22-full google-22-full/php83
PHP 8.2 1st gen, Run functions php82 google-22-full google-22-full/php82
PHP 8.1 1st gen, Run functions php81 google-18-full google-18-full/php81
PHP 7.4 1st gen, Run functions php74 google-18-full google-18-full/php74

.NET Core

Runtime Generation Runtime ID Stacks Runtime base image
.NET Core 8 Run functions dotnet8 google-22-full google-22-full/dotnet8
.NET Core 6 1st gen, Run functions dotnet6 google-22-full google-22-full/dotnet6
.NET Core 3 1st gen, Run functions dotnet3 google-18-full google-18-full/dotnet3

Auto-scaling behavior

Cloud Run functions implements the serverless paradigm, in which you run your code without worrying about the underlying infrastructure, such as servers or virtual machines. Once deployed, your functions are automatically managed and scaled.

Cloud Run functions handles incoming requests by assigning them to instances of your function. Depending on the volume of requests, as well as the number of existing function instances, Cloud Run functions may assign a request to an existing instance or create a new one.

In cases where inbound request volume exceeds the number of existing instances, Cloud Run functions may start multiple new instances to handle requests. This automatic scaling behavior allows Cloud Run functions to handle many requests in parallel, each using a different instance of your function.

In some cases, unbounded scaling might be undesirable. To address this, Cloud Run functions allows you to configure a maximum number of instances that can coexist at any given time for a particular function.

Statelessness

To enable automatic management and scaling of your functions, functions must be stateless—one function invocation must not rely on in-memory state set by a previous invocation. Invocations might be handled by different function instances, which do not share global variables, memory, file systems, or other state.

If you need to share state across function invocations, your function should use a service such as Memorystore, Datastore, Firestore, or Cloud Storage to persist data. See Google Cloud databases and Google Cloud storage products for more information about database and storage options provided by Google Cloud.

Concurrency

Cloud Run functions

Cloud Run functions supports handling multiple concurrent requests on a single function instance. This can be helpful in preventing cold starts since an already warmed instance can process multiple requests simultaneously, thereby reducing overall latency. For details, see Concurrency.

Cloud Run functions (1st gen)

In Cloud Run functions (1st gen), each instance of a function handles only one concurrent request at a time. This means that while your code is processing one request, there is no possibility of a second request being routed to the same instance. Thus the original request can use the full amount of resources (memory and CPU) that you allocate.

Because concurrent requests in Cloud Run functions (1st gen) are processed by different function instances, they do not share variables or local memory. See Statelessness and Function instance lifespan for more information.

Cold starts

A new function instance is started in two cases:

  • When you deploy your function.

  • When a new function instance is automatically created to scale up to the load, or occasionally to replace an existing instance.

Starting a new function instance involves loading the runtime and your code. Requests that include function instance startup, called cold starts, can be slower than requests routed to existing function instances. If your function receives steady load, however, then the number of cold starts is typically negligible unless your function frequently crashes and requires restarting of the function environment.

If your function code throws an uncaught exception or crashes the current process, the function instance might be restarted. This can lead to more cold starts, resulting in higher latency, so we recommend catching exceptions and otherwise avoiding termination of the current process. See Reporting errors for a discussion of how to handle and report errors in Cloud Run functions.

If your function is latency-sensitive, consider setting a minimum number of instances to avoid cold starts.

Function instance lifespan

Function instances are typically resilient and reused by subsequent function invocations, unless the number of instances is being scaled down due to lack of ongoing traffic or your function crashes. This means that when one function execution ends, another function invocation can be handled by the same function instance.

Function scope versus global scope

A single function invocation results in execution of only the body of the function declared as the entry point. The global scope of your function source code is only executed on cold starts, and not on instances that have already been initialized.

Node.js

const functions = require('@google-cloud/functions-framework');

// TODO(developer): Define your own computations
const {lightComputation, heavyComputation} = require('./computations');

// Global (instance-wide) scope
// This computation runs once (at instance cold-start)
const instanceVar = heavyComputation();

/**
 * HTTP function that declares a variable.
 *
 * @param {Object} req request context.
 * @param {Object} res response context.
 */
functions.http('scopeDemo', (req, res) => {
  // Per-function scope
  // This computation runs every time this function is called
  const functionVar = lightComputation();

  res.send(`Per instance: ${instanceVar}, per function: ${functionVar}`);
});

Python

import time

import functions_framework


# Placeholder
def heavy_computation():
    return time.time()


# Placeholder
def light_computation():
    return time.time()


# Global (instance-wide) scope
# This computation runs at instance cold-start
instance_var = heavy_computation()


@functions_framework.http
def scope_demo(request):
    """
    HTTP Cloud Function that declares a variable.
    Args:
        request (flask.Request): The request object.
        <http://flask.pocoo.org/docs/1.0/api/#flask.Request>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <http://flask.pocoo.org/docs/1.0/api/#flask.Flask.make_response>.
    """

    # Per-function scope
    # This computation runs every time this function is called
    function_var = light_computation()
    return f"Instance: {instance_var}; function: {function_var}"

Go


// h is in the global (instance-wide) scope.
var h string

// init runs during package initialization. So, this will only run during an
// an instance's cold start.
func init() {
	h = heavyComputation()
	functions.HTTP("ScopeDemo", ScopeDemo)
}

// ScopeDemo is an example of using globally and locally
// scoped variables in a function.
func ScopeDemo(w http.ResponseWriter, r *http.Request) {
	l := lightComputation()
	fmt.Fprintf(w, "Global: %q, Local: %q", h, l)
}

Java


import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

public class Scopes implements HttpFunction {
  // Global (instance-wide) scope
  // This computation runs at instance cold-start.
  // Warning: Class variables used in functions code must be thread-safe.
  private static final int INSTANCE_VAR = heavyComputation();

  @Override
  public void service(HttpRequest request, HttpResponse response)
      throws IOException {
    // Per-function scope
    // This computation runs every time this function is called
    int functionVar = lightComputation();

    var writer = new PrintWriter(response.getWriter());
    writer.printf("Instance: %s; function: %s", INSTANCE_VAR, functionVar);
  }

  private static int lightComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).sum();
  }

  private static int heavyComputation() {
    int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    return Arrays.stream(numbers).reduce((t, x) -> t * x).getAsInt();
  }
}

Ruby

# Global (instance-wide) scope.
# This block runs on cold start, before any function is invoked.
#
# Note: It is usually best to run global initialization in an on_startup block
# instead at the top level of the Ruby file. This is because top-level code
# could be executed to verify the function during deployment, whereas an
# on_startup block is run only when an actual function instance is starting up.
FunctionsFramework.on_startup do
  instance_data = perform_heavy_computation

  # To pass data into function invocations, the best practice is to set a
  # key-value pair using the Ruby Function Framework's built-in "set_global"
  # method. Functions can call the "global" method to retrieve the data by key.
  # (You can also use Ruby global variables or "toplevel" local variables, but
  # they can make it difficult to isolate global data for testing.)
  set_global :my_instance_data, instance_data
end

FunctionsFramework.http "tips_scopes" do |_request|
  # Per-function scope.
  # This method is called every time this function is called.
  invocation_data = perform_light_computation

  # Retrieve the data computed by the on_startup block.
  instance_data = global :my_instance_data

  "instance: #{instance_data}; function: #{invocation_data}"
end

You can use global variables as a performance optimization, but you must not rely on state set in the global scope by previous function invocations - see Statelessness for more information.

You can assume that for each function instance, the global scope has been executed exactly once before your function code is invoked. However, you must not depend on the total number of or timing of global scope executions, as they might vary depending on auto-scaling activity.

Function execution timeline

A function has access to its allocated resources (memory and CPU) only for the duration of function execution. Code run outside of the execution period is not guaranteed to execute, and it can be stopped at any time. Therefore, you should always signal the end of your function execution correctly and avoid running any code beyond it. See HTTP Functions, Background Functions, and CloudEvent Functions for guidance.

Function execution is also subject to the timeout duration of the function. See Function timeout for more information.

Take into account the execution timeline when initializing your application. Background tasks should not be created in global scope during initialization, as they would execute outside of the duration of a request.

Execution guarantees

Your functions are typically invoked once for each incoming event. However, Cloud Run functions does not guarantee a single invocation in all cases because of differences in error scenarios.

The maximum or minimum number of times your function could be invoked for a single event depends on the type of your function:

  • HTTP functions are invoked at most once. This is because of the synchronous nature of HTTP calls, and it means that any error that occurs during function invocation will be returned without retrying. The caller of an HTTP function is expected to handle errors and retry if needed.

  • Event-driven functions are invoked at least once. This is because of the asynchronous nature of events, in which there is no caller that waits for the response. The system might, in rare circumstances, invoke an event-driven function more than once in order to ensure delivery of the event. If an event-driven function invocation fails with an error, the function won't be invoked again unless retries on failure are enabled for that function.

To make sure that your function behaves correctly on retried execution attempts, you should make it idempotent by implementing it so that the desired results (and side effects) are produced even if an event is delivered multiple times. In the case of HTTP functions, this also means returning the desired value even if the caller retries calls to the HTTP function endpoint. See Retrying Event-Driven Functions for more information on how to make your function idempotent.

Memory and file system

Each function has a certain amount of memory allocated for its use. You can configure the amount of memory at deployment - see Memory limits for more information.

The function execution environment includes an in-memory file system that contains the source files and directories deployed with your function (see Structuring source code). The directory containing your source files is read-only, but the rest of the file system is writeable (except for files used by the operating system). Use of the file system counts towards a function's memory usage.

Your function can interact with the file system using standard methods in each programming language.

Network

Your function can access the public internet using standard methods in each programming language, whether through built-in libraries offered by the runtime or third-party libraries you include as dependencies.

Try to reuse network connections across function invocations, as described in Optimizing Networking. However, note that a connection that remains unused for 10 minutes might be closed by the system, and further attempts to use a closed connection will result in a "connection reset" error. Your code should either use a library that handles closed connections well, or handle them explicitly if using low-level networking constructs.

Function isolation

Every deployed function is isolated from all other functions—even those deployed from the same source file. In particular, they do not share memory, global variables, file systems, or other state.

To share data across deployed functions, you can use services such as Memorystore, Datastore, Firestore, or Cloud Storage. Alternatively, you can invoke one function from another using their appropriate triggers and passing along the necessary data. For example, make an HTTP request to the endpoint of an HTTP function or publish a message to a Pub/Sub topic to trigger a Pub/Sub function.