You can run your Cloud Functions locally with the Functions Framework, which is the official emulator.

Here’s a simple helloWorld function in Node.js:

// index.js
exports.helloWorld = (req, res) => {
  let message = req.query.message || req.body.message || 'Hello World!';
  res.status(200).send(message);
};

To run this locally, you’ll need to install the Functions Framework and then start it:

# Install the Functions Framework
npm install @google-cloud/functions-framework

# Start the emulator
npx functions-framework --target=helloWorld

Now, your function is accessible at http://localhost:8080. You can send a request to it using curl:

curl localhost:8080
# Output: Hello World!

curl "localhost:8080?message=Hello%20Local!"
# Output: Hello Local!

curl -X POST -H "Content-Type: application/json" -d '{"message": "Hello POST!"}' localhost:8080
# Output: Hello POST!

The Functions Framework emulates the environment your function will run in on Google Cloud. This means it handles request parsing, response formatting, and even simulates certain Cloud services if you configure it to. For example, to emulate an HTTP function triggered by a Pub/Sub message, you can pass the --signature-type=event flag and send a JSON payload that mimics a Pub/Sub message.

npx functions-framework --target=helloPubSub --signature-type=event

And send a sample Pub/Sub message:

curl -X POST -H "Content-Type: application/json" \
  -d '{
        "message": {
          "data": "SGVsbG8gU3Vwc3ViIQ==",
          "messageId": "1234567890",
          "publishTime": "2023-10-27T10:00:00.000Z"
        }
      }' \
  localhost:8080

The --target flag specifies the exported function name in your code, and --signature-type tells the framework whether your function expects an HTTP request or an event payload. For HTTP functions, it defaults to http. For event-driven functions (like Pub/Sub, Storage, etc.), you’ll use event.

The framework also supports other languages like Python and Go. For Python, you’d install functions-framework via pip and run it like functions-framework --target=my_function --signature-type=event.

You can configure environment variables for your function using the --env-vars-file flag, pointing to a YAML file. This is crucial for testing interactions with other services that rely on environment-specific configurations.

# env.yaml
DATABASE_URL: "http://localhost:5432"
API_KEY: "local-test-key"
npx functions-framework --target=myDatabaseFunction --env-vars-file=env.yaml

This allows you to test your function’s logic and its dependencies without needing to deploy to the cloud for every small change. It speeds up the development cycle significantly by catching errors early and providing a rapid feedback loop.

A common pattern is to use this local emulation within your CI/CD pipeline to run unit and integration tests against your function before it’s deployed to production. This ensures that your function behaves as expected in a controlled environment before it encounters the complexities of the actual cloud infrastructure.

The Functions Framework doesn’t perfectly replicate every aspect of the Cloud Functions environment. For instance, it doesn’t natively emulate IAM permissions or the exact latency of network calls to other Google Cloud services. For deeper integration testing, you might need to use emulators for services like Firestore or Pub/Sub that can be run alongside the Functions Framework.

When testing event-driven functions, the event signature type means your function receives a structured payload representing the event. For example, a Pub/Sub event payload includes a message object, which itself contains data (base64 encoded) and attributes. You’ll need to decode the data field in your function logic if you’re expecting plain text or JSON.

Want structured learning?

Take the full Cloud-functions course →