Local Functions Development

Cloud Run functions supports several methods of running your functions outside of the target deployment environment. This is particularly useful for iterative development, and for situations where you want to test your function before deploying.

The ability to run your functions without deploying them can simplify local testing, compliance with data locality restrictions, and multicloud deployments:

  • Data locality restrictions: Test your function locally without accessing production data, to avoid violating your organization's data locality rules.

  • Multicloud deployments: Multicloud function deployments are an established pattern to mitigate downtime risk in reliability-critical environments. Deploying functions to environments other than Cloud Run functions itself reduces the risk of your application experiencing unplanned downtime.

Develop functions locally using Functions Framework

You can develop and test functions locally using Functions Framework. Developing a function locally can help you test your code without having to rebuild your function container. This can save time and make it easier to test your function.

Cloud Run uses the open-source Functions Framework libraries to wrap your deployed functions in a persistent HTTP application.

The Functions Framework can also run on any other platform that supports the language itself, including your local machine, on-premises servers, and Compute Engine.

Install dependencies

In your function's directory, install the Functions Framework library for your language:

Node.js

npm install --save-dev @google-cloud/functions-framework

Python

pip3 install functions-framework

Go

go install github.com/GoogleCloudPlatform/functions-framework-go/funcframework

Java

Maven

If you're using Maven, add the following to your pom.xml file:

<dependency>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>functions-framework-api</artifactId>
  <version>1.1.0</version>
  <scope>provided</scope>
</dependency>

Gradle

If you're using Gradle, add the following to your build.gradle file:

dependencies {
  // Every function needs this dependency to get the Functions Framework API.
  compileOnly 'com.google.cloud.functions:functions-framework-api:1.1.0'

  // To run function locally using Functions Framework's local invoker
  invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.3.1'
}

See the Java Functions Framework library for more information.

C#

The following commands use .NET Templates to create a new .NET function codebase with the .NET Functions Framework library as a dependency:

# HTTP functions
dotnet new gcf-http

# CloudEvent functions
dotnet new gcf-event

Ruby

In Ruby the Functions Framework must be added to your function's dependencies in order to deploy it to Cloud Run:

bundle add functions_framework

PHP

composer require google/cloud-functions-framework

Configure the Functions Framework

Before running a function using the Functions Framework, you'll first need to specify both the type and the name of the function you want to run. These attributes can be specified as either command-line interface (CLI) flag or as environment variables.

Supported function types

The Functions Framework supports both types of functions supported by Cloud Run functions. All language runtimes support both the http and cloudevent signature types.

Function type Signature type Description Supporting Runtimes
HTTP-triggered functions http Functions that receive and respond to HTTP requests. All runtimes
CloudEvent functions cloudevent Industry-standard event format. All runtimes

Specify which function to run

Before running a function with the Functions Framework, you must first specify which function within your code to run. For most languages, you can do this by specifying the target function's method name as shown in the following tables. Note that there are exceptions to this rule for the Java and .NET runtimes.

Per-language instructions

See the following table for a list of configuration options supported by each language.

Node.js

CLI Argument Environment Variable Description
--port PORT The port to listen for requests on. (Default: 8080)
--target FUNCTION_TARGET The name of the exported function to be invoked. (Default: function)
--signature-type FUNCTION_SIGNATURE_TYPE The signature type used by your function. Can be http (the default) or cloudevent.

Python

CLI Argument Environment Variable Description
--port PORT The port to listen for requests on. (Default: 8080)
--target FUNCTION_TARGET The name of the exported function to be invoked. (Default: function)
--signature-type FUNCTION_SIGNATURE_TYPE The signature type used by your function. Can be http (the default) or cloudevent.

Go

Environment Variable Description
PORT The port to listen for requests on. (Default: 8080)

Java

Argument Name Environment Variable Description
run.port PORT The port to listen for requests on. (Default: 8080)
run.functionTarget FUNCTION_TARGET The name of the exported function to be invoked. (Default: function)

C#

CLI Argument Environment Variable Description
--port PORT The port to listen for requests on. (Default: 8080)
--target (or only argument) FUNCTION_TARGET The classname of the function to be invoked. (Default: function)

Ruby

CLI Argument Environment Variable Description
--port PORT The port to listen for requests on. (Default: 8080)
--target FUNCTION_TARGET The name of the exported function to be invoked. (Default: function)

PHP

Environment Variable Description
FUNCTION_TARGET The name of the function to be invoked. (Default: function)
FUNCTION_SIGNATURE_TYPE The signature type used by your function. Can be http (the default) or cloudevent.

Follow these instructions to configure and run the Functions Framework:

Node.js

The Node.js Functions Framework lets you specify your function's name and signature type as command line arguments or environment variables.

You can also specify these values in the package.json buildfile by adding a start script with the required CLI arguments as shown in the example below.

"scripts": {
"start": "npx functions-framework --target=YOUR_FUNCTION_NAME [--signature-type=YOUR_SIGNATURE_TYPE]"
}

The same can be done using environment variables:

"scripts": {
"start": "FUNCTION_TARGET=YOUR_FUNCTION_NAME FUNCTION_SIGNATURE_TYPE=YOUR_SIGNATURE_TYPE npx functions-framework"
}

Replace YOUR_FUNCTION_NAME with the method name of your function, and YOUR_SIGNATURE_TYPE (if applicable) with the signature type of your function as shown in supported function types.

Python

The Python Functions Framework lets you specify your function's name and signature type as command line arguments or environment variables. Command-line arguments must be specified when you run the framework.

Go

The Go Functions Framework uses funcframework.RegisterHTTPFunctionContext to specify the function target and signature type.

Java

The Java Functions Framework accepts configuration data from three different sources, in the following priority order (most specific to least specific):

  • Command-line arguments
  • Buildfiles
  • Environment variables

Command-line arguments

Maven

You can specify the function you want to run by adding the following command-line interface (CLI) flag to your mvn commands:

-Drun.functionTarget=YOUR_FUNCTION_NAME

You can also specify the target port by adding the following CLI flag in a similar manner:

-Drun.port=12345

Gradle

Gradle's CLI flags are nearly identical to Maven's. The only change Gradle makes is to swap the leading -D in each flag for a -P as shown in the following example:

# Maven version

-Drun.functionTarget=...

# Gradle version

-Prun.functionTarget=...

Buildfiles

You can also specify the function you want to run in your project's buildfile. While Maven and Gradle have similar CLI flags, their buildfile clauses differ significantly.

Maven

Maven buildfiles are named pom.xml. Add the following clause to this file to specify a target function:

<plugin>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>function-maven-plugin</artifactId>
  <version>0.11.0</version>
  <configuration>
    <functionTarget>functions.HelloWorld</functionTarget>
  </configuration>
</plugin>

Replace <functionTarget> with the class name of your function. For example, a function in package functions with class name HelloCloudFunctions would have a class name of functions.HelloCloudFunctions. This is relative to the parent build file - either pom.xml or build.gradle.

Gradle

Gradle buildfiles are named build.gradle. Add the following clause to this file to specify a target function:

// Register a "runFunction" task to run the function locally
tasks.register("runFunction", JavaExec) {
  main = 'com.google.cloud.functions.invoker.runner.Invoker'
  classpath(configurations.invoker)
  inputs.files(configurations.runtimeClasspath, sourceSets.main.output)
  args(
    '--target', project.findProperty('run.functionTarget') ?: '',
    '--port', project.findProperty('run.port') ?: 8080
  )
  doFirst {
    args('--classpath', files(configurations.runtimeClasspath, sourceSets.main.output).asPath)
  }
}

C#

If you create your project using dotnet new and one of the templates specified earlier, the .NET Functions Framework will automatically detect your function.

If your project contains multiple functions, see the Running the Framework section for information on how to run a specific function.

Ruby

The Ruby Functions Framework lets you specify your function's name and signature type as command line arguments or environment variables. Command-line arguments must be specified when you run the framework.

PHP

The PHP Functions Framework allows you to specify environment variables as command line arguments.

You can also specify these values in the composer.json buildfile by adding a start script as shown in the example below.

"scripts": {
 "start": [
     "Composer\\Config::disableProcessTimeout",
     "FUNCTION_TARGET=YOUR_FUNCTION_NAME php -S localhost:${PORT:-8080} vendor/bin/router.php"
].
}

Replace YOUR_FUNCTION_NAME with the name of your function, and YOUR_SIGNATURE_TYPE (if applicable; it is not included in the example shown here).

Run your function

Use the following command to run your function with the Functions Framework. By default, your function will be accessible at localhost:8080 unless you explicitly specify a PORT value.

Node.js

npm start

Python

Using command line arguments:

functions-framework --target=YOUR_FUNCTION_NAME

Using environment variables:

FUNCTION_TARGET=YOUR_FUNCTION_NAME functions-framework

Replace YOUR_FUNCTION_NAME with your function's method name.

Go

First create a cmd/main.go file as described on the Functions Framework for Go site.

cd cmd
go build
./cmd

Using environment variables:

cd cmd
go build
PORT=8080 ./cmd

Java

Maven

Use the following command to run a function specified in pom.xml:

mvn function:run

Use the following command to run a function specified in a command-line argument:

mvn function:run -Drun.functionTarget=YOUR_FUNCTION_NAME

Use the following command to run a function specified as an environment variable:

FUNCTION_TARGET=YOUR_FUNCTION_NAME mvn function:run

Replace YOUR_FUNCTION_NAME with your function's classname.

Gradle

Use the following command to run a function specified in build.gradle:

./gradlew runFunction

Use the following command to run a function specified in a command-line argument:

./gradlew runFunction -Prun.functionTarget=YOUR_FUNCTION_NAME

Use the following command to run a function specified as an environment variable:

FUNCTION_TARGET=YOUR_FUNCTION_NAME ./gradlew runFunction

Replace YOUR_FUNCTION_NAME with your function's classname.

C#

Use the following command to run your function when exactly one function is present in the current .NET project. Note that this is the default structure for template-created projects.

dotnet run

If your .NET project contains multiple functions, use the following command to run a specific function. Replace YOUR_FUNCTION_CLASSNAME with your function's classname, including the namespace.

dotnet run YOUR_FUNCTION_CLASSNAME

If you want to run multiple functions simultaneously, you'll need to run multiple Functions Framework instances. To avoid conflicts between running framework instances, each instance should use a different PORT value. The following command shows how to run a function with a PORT value of 8080.

Using command line arguments:

dotnet run --target YOUR_FUNCTION_CLASSNAME --port 8080

Using environment variables:

FUNCTION_TARGET=YOUR_FUNCTION_CLASSNAME PORT=8080 dotnet run

Ruby

Using command line arguments:

bundle exec functions-framework-ruby --target YOUR_FUNCTION_NAME

Using environment variables:

FUNCTION_TARGET=YOUR_FUNCTION_NAME bundle exec functions-framework-ruby

Replace YOUR_FUNCTION_NAME with your function's method name.

PHP

export FUNCTION_TARGET=YOUR_FUNCTION_NAME
php -S localhost:8080 vendor/bin/router.php

Replace YOUR_FUNCTION_NAME with your function's name.

Call your locally running function

The exercises in this section assume that you've set up a locally running function on localhost using Functions Framework.

You can trigger locally-running functions by sending them HTTP requests routed using a local serving process.

HTTP functions

When you test your HTTP function from your development environment, it normally listens for requests on localhost:8080. This interface is only accessible from the machine or VM your function is running on; requests sent from any other system can't reach it. For this reason, you must issue the HTTP request from the same system that your function is running on. In the following examples, if your function is listening on a port other than 8080, replace the 8080 in the example with the port number for your function.

Testing HTTP functions with Cloud Shell

If you're using Cloud Shell to build and test your function, start your function locally in the Cloud Shell terminal window, then issue the HTTP trigger request from a browser or curl instance as follows:

Browser

Click the Web Preview Button icon on your Cloud Shell toolbar and choose port 8080 or Change port to pick a different port. This opens a browser window on the correct system and issues a GET request to the indicated port.

Curl

To control the format of your HTTP request or to see the unformatted reply, use curl:

  1. Click the + icon on the Cloud Shell menu bar to open a new terminal window on the same system your function is running on.
  2. From within that window, run the curl command to trigger your function. For example:

    curl localhost:8080
    

Testing HTTP functions on your desktop server

If you're building and running your function on your local desktop system, first start your function locally, then issue your HTTP trigger request from a browser or curl instance as follows:

Browser

Open a new browser window or tab and type http://localhost:8080 into the browser address bar. This opens a browser window to localhost:8080 on your desktop server to trigger your function.

Curl

Open a new terminal window on your local desktop, then run the curl command in that window to trigger your function. For example:

 curl localhost:8080

This runs the specified curl command to trigger your function and displays the unformatted response.

CloudEvent functions

You can send sample events to CloudEvent functions using curl. The following curl requests show how to send sample Pub/Sub and Cloud Storage events to a CloudEvent function running at localhost:8080.

Pub/Sub

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.pubsub.topic.v1.messagePublished" \
  -H "ce-source: //pubsub.googleapis.com/projects/MY-PROJECT/topics/MY-TOPIC" \
  -d '{
        "message": {
          "data": "d29ybGQ=",
          "attributes": {
             "attr1":"attr1-value"
          }
        },
        "subscription": "projects/MY-PROJECT/subscriptions/MY-SUB"
      }'
    

Cloud Storage

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.storage.object.v1.finalized" \
  -H "ce-source: //storage.googleapis.com/projects/_/buckets/MY-BUCKET-NAME" \
  -H "ce-subject: objects/MY_FILE.txt" \
  -d '{
        "bucket": "MY_BUCKET",
        "contentType": "text/plain",
        "kind": "storage#object",
        "md5Hash": "...",
        "metageneration": "1",
        "name": "MY_FILE.txt",
        "size": "352",
        "storageClass": "MULTI_REGIONAL",
        "timeCreated": "2020-04-23T07:38:57.230Z",
        "timeStorageClassUpdated": "2020-04-23T07:38:57.230Z",
        "updated": "2020-04-23T07:38:57.230Z"
      }'