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.

Runtimes

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.

Node.js

Runtime Generation Environment Runtime ID Runtime image
Node.js 20 1st gen, 2nd gen Ubuntu 22.04 nodejs20 gcr.io/gae-runtimes/buildpacks/nodejs20/run
Node.js 18 1st gen, 2nd gen Ubuntu 22.04 nodejs18 gcr.io/gae-runtimes/buildpacks/nodejs18/run
Node.js 16 1st gen, 2nd gen Ubuntu 18.04 nodejs16 gcr.io/gae-runtimes/buildpacks/nodejs18/run
Node.js 14 1st gen, 2nd gen Ubuntu 18.04 nodejs14 gcr.io/gae-runtimes/buildpacks/nodejs14/run
Node.js 12 1st gen, 2nd gen Ubuntu 18.04 nodejs12 gcr.io/gae-runtimes/buildpacks/nodejs12s/run
Node.js 10 1st gen, 2nd gen Ubuntu 18.04 nodejs10 gcr.io/gae-runtimes/buildpacks/nodejs10/run
Node.js 8 1st gen, 2nd gen Ubuntu 18.04 nodejs8 gcr.io/gae-runtimes/buildpacks/nodejs8/run
Node.js 6 1st gen, 2nd gen Ubuntu 18.04 nodejs6 gcr.io/gae-runtimes/buildpacks/nodejs6/run

Python

Runtime Generation Environment Runtime ID Runtime image
Python 3.12 1st gen, 2nd gen Ubuntu 22.04 python312 gcr.io/gae-runtimes/buildpacks/python312/run
Python 3.11 1st gen, 2nd gen Ubuntu 22.04 python311 gcr.io/gae-runtimes/buildpacks/python311/run
Python 3.10 1st gen, 2nd gen Ubuntu 22.04 python310 gcr.io/gae-runtimes/buildpacks/python310/run
Python 3.9 1st gen, 2nd gen Ubuntu 18.04 python39 gcr.io/gae-runtimes/buildpacks/python39/run
Python 3.8 1st gen, 2nd gen Ubuntu 18.04 python38 gcr.io/gae-runtimes/buildpacks/python38/run
Python 3.7 1st gen Ubuntu 18.04 python37 gcr.io/gae-runtimes/buildpacks/python37/run

Go

Runtime Generation Environment Runtime ID Runtime image
Go 1.22 2nd gen Ubuntu 22.04 go122 gcr.io/gae-runtimes/buildpacks/go122/run
Go 1.21 1st gen, 2nd gen Ubuntu 22.04 go121 gcr.io/gae-runtimes/buildpacks/go121/run
Go 1.20 1st gen, 2nd gen Ubuntu 22.04 go120 gcr.io/gae-runtimes/buildpacks/go120/run
Go 1.19 1st gen, 2nd gen Ubuntu 22.04 go119 gcr.io/gae-runtimes/buildpacks/go119/run
Go 1.18 1st gen, 2nd gen Ubuntu 22.04 go118 gcr.io/gae-runtimes/buildpacks/go118/run
Go 1.16 1st gen, 2nd gen Ubuntu 18.04 go116 gcr.io/gae-runtimes/buildpacks/go116/run
Go 1.13 1st gen, 2nd gen Ubuntu 18.04 go113 gcr.io/gae-runtimes/buildpacks/go113/run
Go 1.12 1st gen, 2nd gen Ubuntu 18.04 go112 gcr.io/gae-runtimes/buildpacks/go112/run
Go 1.11 1st gen, 2nd gen Ubuntu 18.04 go111 gcr.io/gae-runtimes/buildpacks/go111/run

Java

Runtime Generation Environment Runtime ID Runtime image
Java 21 2nd gen Ubuntu 22.04 java21 gcr.io/gae-runtimes/buildpacks/java21/run
Java 17 1st gen, 2nd gen Ubuntu 22.04 java17 gcr.io/gae-runtimes/buildpacks/java17/run
Java 11 1st gen, 2nd gen Ubuntu 18.04 java11 gcr.io/gae-runtimes/buildpacks/java11/run

Ruby

Runtime Generation Environment Runtime ID Runtime image
Ruby 3.2 1st gen, 2nd gen Ubuntu 22.04 ruby32 gcr.io/gae-runtimes/buildpacks/ruby32/run
Ruby 3.0 1st gen, 2nd gen Ubuntu 18.04 ruby30 gcr.io/gae-runtimes/buildpacks/ruby30/run
Ruby 2.7 1st gen, 2nd gen Ubuntu 18.04 ruby27 gcr.io/gae-runtimes/buildpacks/ruby27/run
Ruby 2.6 1st gen, 2nd gen Ubuntu 18.04 ruby26 gcr.io/gae-runtimes/buildpacks/ruby26/run

PHP

Runtime Environment Generation Runtime ID Runtime image
PHP 8.3 2nd gen Ubuntu 22.04 php83 gcr.io/gae-runtimes/buildpacks/php83/run
PHP 8.2 1st gen, 2nd gen Ubuntu 22.04 php82 gcr.io/gae-runtimes/buildpacks/php82/run
PHP 8.1 1st gen, 2nd gen Ubuntu 18.04 php81 gcr.io/gae-runtimes/buildpacks/php81/run
PHP 7.4 1st gen, 2nd gen Ubuntu 18.04 php74 gcr.io/gae-runtimes/buildpacks/php74/run

.NET Core

Runtime Generation Environment Runtime ID Runtime image
.NET Core 8 2nd gen Ubuntu 22.04 dotnet8 gcr.io/gae-runtimes/buildpacks/dotnet8/run
.NET Core 6 1st gen, 2nd gen Ubuntu 22.04 dotnet6 gcr.io/gae-runtimes/buildpacks/dotnet6/run
.NET Core 3 1st gen, 2nd gen Ubuntu 18.04 dotnet3 gcr.io/gae-runtimes/buildpacks/dotnet3/run

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.

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

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

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.