Cloud Functions execution environment

Cloud 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.


Cloud 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 1st and 2nd 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 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 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:


Runtime Generation Environment Runtime ID Runtime image
Node.js 22 (preview only) 2nd gen Ubuntu 22.04 nodejs22
Node.js 20 1st gen, 2nd gen Ubuntu 22.04 nodejs20
Node.js 18 1st gen, 2nd gen Ubuntu 22.04 nodejs18
Node.js 16 1st gen, 2nd gen Ubuntu 18.04 nodejs16
Node.js 14 1st gen, 2nd gen Ubuntu 18.04 nodejs14
Node.js 12 1st gen, 2nd gen Ubuntu 18.04 nodejs12
Node.js 10 1st gen, 2nd gen Ubuntu 18.04 nodejs10
Node.js 8 1st gen, 2nd gen Ubuntu 18.04 nodejs8 Decommissioned
Node.js 6 1st gen, 2nd gen Ubuntu 18.04 nodejs6 Decommissioned


Runtime Generation Environment Runtime ID Runtime image
Python 3.12 1st gen, 2nd gen Ubuntu 22.04 python312
Python 3.11 1st gen, 2nd gen Ubuntu 22.04 python311
Python 3.10 1st gen, 2nd gen Ubuntu 22.04 python310
Python 3.9 1st gen, 2nd gen Ubuntu 18.04 python39
Python 3.8 1st gen, 2nd gen Ubuntu 18.04 python38
Python 3.7 1st gen Ubuntu 18.04 python37


Runtime Generation Environment Runtime ID Runtime image
Go 1.22 2nd gen Ubuntu 22.04 go122
Go 1.21 1st gen, 2nd gen Ubuntu 22.04 go121
Go 1.20 1st gen, 2nd gen Ubuntu 22.04 go120
Go 1.19 1st gen, 2nd gen Ubuntu 22.04 go119
Go 1.18 1st gen, 2nd gen Ubuntu 22.04 go118
Go 1.16 1st gen, 2nd gen Ubuntu 18.04 go116
Go 1.13 1st gen, 2nd gen Ubuntu 18.04 go113
Go 1.11 1st gen, 2nd gen Ubuntu 18.04 go111 Decommissioned


Runtime Generation Environment Runtime ID Runtime image
Java 21 2nd gen Ubuntu 22.04 java21
Java 17 1st gen, 2nd gen Ubuntu 22.04 java17
Java 11 1st gen, 2nd gen Ubuntu 18.04 java11


Runtime Generation Environment Runtime ID Runtime image
Ruby 3.3 (preview only) 1st gen, 2nd gen Ubuntu 22.04 ruby33
Ruby 3.2 1st gen, 2nd gen Ubuntu 22.04 ruby32
Ruby 3.0 1st gen, 2nd gen Ubuntu 18.04 ruby30
Ruby 2.7 1st gen, 2nd gen Ubuntu 18.04 ruby27
Ruby 2.6 1st gen, 2nd gen Ubuntu 18.04 ruby26


Runtime Environment Generation Runtime ID Runtime image
PHP 8.3 2nd gen Ubuntu 22.04 php83
PHP 8.2 1st gen, 2nd gen Ubuntu 22.04 php82
PHP 8.1 1st gen, 2nd gen Ubuntu 18.04 php81
PHP 7.4 1st gen, 2nd gen Ubuntu 18.04 php74

.NET Core

Runtime Generation Environment Runtime ID Runtime image
.NET Core 8 2nd gen Ubuntu 22.04 dotnet8
.NET Core 6 1st gen, 2nd gen Ubuntu 22.04 dotnet6
.NET Core 3 1st gen, 2nd gen Ubuntu 18.04 dotnet3

Auto-scaling behavior

Cloud 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 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 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 Functions may start multiple new instances to handle requests. This automatic scaling behavior allows Cloud 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 Functions allows you to configure a maximum number of instances that can coexist at any given time for a particular function.


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.


Cloud Functions (2nd gen)

Cloud Functions (2nd gen) 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 Functions (1st gen)

In Cloud 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 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 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.


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}`);


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()

def scope_demo(request):
    HTTP Cloud Function that declares a variable.
        request (flask.Request): The request object.
        The response text, or any set of values that can be turned into a
        Response object using `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}"


// 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)


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();

  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 };

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


# 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

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}"

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 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 will not 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.


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.