Building and Deploying Serverless Functions on Google Cloud with Python

Overview

Serverless functions allow you to run code in the cloud without managing the underlying infrastructure.

(now part of
Cloud Run Functions
) scale automatically based on demand, including scaling to zero when not in use. This model enables developers to focus purely on business logic while the cloud provider handles provisioning and runtime maintenance. This guide explores building these functions using the
Functions Framework
, managing them through Infrastructure as Code (IaC) with
Pulumi
, and navigating technical trade-offs.

Prerequisites

To follow this guide, you should have a basic understanding of

and
HTTP
request handling. Familiarity with
Google Cloud Platform
(GCP) and terminal-based package management is recommended. You will need a GCP account with billing enabled to deploy resources.

Key Libraries & Tools

  • Functions Framework: A Google-provided open-source library that lets you run your functions locally to simulate the cloud environment.
  • Pulumi: An infrastructure-as-code tool that uses standard programming languages to define cloud resources.
  • uv: A high-performance Python package installer and resolver used to manage project dependencies.
  • Flask: The underlying web framework used by Google Cloud Functions to handle routing.
Building and Deploying Serverless Functions on Google Cloud with Python
Serverless on Google Cloud: What You Can and Can’t Do

Code Walkthrough

1. Local Development

You can create a function by defining a simple Python routine. The

allows you to serve this locally for testing.

import functions_framework

@functions_framework.http
def hello_world(request):
    return "Hello, Serverless!"

Run this locally using the command: functions-framework --target hello_world --port 8080. This provides an immediate feedback loop before cloud deployment.

2. Infrastructure as Code with Pulumi

To deploy, use

to define the necessary infrastructure. You must create a storage bucket to hold the source code artifact and then define the function resource itself.

import pulumi
import pulumi_gcp as gcp

# Create a bucket for the code
bucket = gcp.storage.Bucket("function-bucket")

# Define the cloud function
cloud_fn = gcp.cloudfunctionsv2.Function("my-function",
    build_config=gcp.cloudfunctionsv2.FunctionBuildConfigArgs(
        runtime="python311",
        entry_point="hello_world",
    ),
    service_config=gcp.cloudfunctionsv2.FunctionServiceConfigArgs(
        max_instance_count=10,
        available_memory="256M",
        timeout_seconds=60,
    ))

3. Simulating Sub-routes

Since

typically only expose a single entry point, you can use an internal
Flask
app to handle complex routing within that single function.

from flask import Flask, request

internal_app = Flask(__name__)

@internal_app.route("/user/<id>")
def get_user(id):
    return {"user_id": id}

@functions_framework.http
def entry_point(request):
    with internal_app.test_request_context(path=request.path, method=request.method):
        return internal_app.dispatch_request()

Syntax Notes

When using

, you define resources as Python objects. Note the service_config block, which dictates how the cloud provider allocates resources.
Google Cloud Functions
specifically look for a requirements.txt file for dependency resolution; if you use
uv
, you must export your lockfile to this format during the build process.

Practical Examples

Serverless functions excel at event-driven tasks. Common use cases include processing an invoice whenever a PDF is uploaded to a storage bucket, sending a welcome email via an

trigger during user registration, or performing data validation on a
Pub/Sub
message stream.

Tips & Gotchas

  • Cold Starts: If a function hasn't been called recently, the first request may be slow as the provider spins up a new container instance. Keep dependencies light to minimize this delay.
  • Security: Never hardcode API keys. Use
    Google Cloud Secret Manager
    to store sensitive values and inject them as environment variables into your function.
  • Access Control: Be careful with the allUsers invoker role; it makes your function public, which could lead to unexpected costs if abused by third parties.
4 min read