Skip to main content

Search the Dev Center

Search tutorials, templates, examples, and more.

Google Cloud Serverless Application

The Google Cloud Serverless Application template scaffolds a Pulumi project that deploys a Google Cloud Storage bucket configured for static website hosting and a Cloud Functions Gen 2 function for the application backend. The template ships with placeholder web and function content so the project deploys end to end out of the box.

Architecture diagram of the Google Cloud Serverless Application template Google Cloud Cloud Storage Cloud Functions

Before you deploy#

Cloud Functions Gen 2 functions are gated at the underlying Cloud Run service, so the public-invoker grant in this template is created with gcp.cloudrun.IamMember (roles/run.invoker). The identity running pulumi up needs to be able to set IAM policy on Cloud Run — typically roles/run.admin, or a custom role that includes run.services.setIamPolicy — in addition to the permissions needed to create the function and storage resources.

Before you begin#

For this walkthrough, you'll need:

Create a new project#

Create a new project from the template:

Terminal window
mkdir my-serverless-app; cd my-serverless-app
pulumi new serverless-gcp-typescript

The pulumi new command walks you through creating and configuring the new project and stack. A stack is an instance of a project, and you can have many of them (dev, staging, prod), each with its own configuration settings. Depending on the language, you may also be asked for your preferred package manager or toolchain.

This template’s settings include:

KeyDescriptionDefault
gcp:projectThe Google Cloud project to deploy into—
gcp:regionThe Google Cloud region to deploy intous-central1
sitePathThe path to the folder containing the websitewww
appPathThe path to the folder containing the functions to be deployedapp
indexDocumentThe file to use for top-level pagesindex.html
errorDocumentThe file to use for error pageserror.html
You can change values like these later with pulumi config set :
Terminal window
pulumi config set gcp:project <value>
pulumi config set gcp:region <value>
pulumi config set sitePath <value>
pulumi config set appPath <value>
pulumi config set indexDocument <value>
pulumi config set errorDocument <value>

For gcp:project, enter the ID of an existing Google Cloud project. gcloud config get-value project prints the one gcloud is using. Press Enter at the others to keep the defaults.

Review the code#

When setup completes, you’ll see a few files:

  • Pulumi.yaml contains the project name and the language it’s written in.
  • Pulumi.dev.yaml contains the dev stack’s settings, including the values you just entered.
  • index.ts contains the program code that declares your cloud resources.

Take a moment to open them up and have a look. Here’s what’s in index.ts:

index.ts
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as synced from "@pulumi/synced-folder";
// Import the program's configuration settings.
const config = new pulumi.Config();
const sitePath = config.get("sitePath") || "www";
const appPath = config.get("appPath") || "app";
const indexDocument = config.get("indexDocument") || "index.html";
const errorDocument = config.get("errorDocument") || "error.html";
// Create a storage bucket and configure it as a website.
const siteBucket = new gcp.storage.Bucket("site-bucket", {
location: "US",
website: {
mainPageSuffix: indexDocument,
notFoundPage: errorDocument,
},
});
// Create an IAM binding to allow public read access to the bucket.
const siteBucketIAMBinding = new gcp.storage.BucketIAMBinding("site-bucket-iam-binding", {
bucket: siteBucket.name,
role: "roles/storage.objectViewer",
members: ["allUsers"],
});
// Use a synced folder to manage the files of the website.
const syncedFolder = new synced.GoogleCloudFolder("synced-folder", {
path: sitePath,
bucketName: siteBucket.name,
});
// Create another storage bucket for the serverless app.
const appBucket = new gcp.storage.Bucket("app-bucket", {
location: "US",
});
// Upload the serverless app to the storage bucket.
const appArchive = new gcp.storage.BucketObject("app-archive", {
bucket: appBucket.name,
source: new pulumi.asset.FileArchive(appPath),
});
// Create a Cloud Function (Gen 2) that returns some data.
const dataFunction = new gcp.cloudfunctionsv2.Function("data-function", {
location: gcp.config.region || "us-central1",
buildConfig: {
runtime: "nodejs24",
entryPoint: "date",
source: {
storageSource: {
bucket: appBucket.name,
object: appArchive.name,
},
},
},
serviceConfig: {
availableMemory: "256M",
timeoutSeconds: 60,
},
});
// Allow public, unauthenticated invocations of the underlying Cloud Run service.
const invoker = new gcp.cloudrun.IamMember("data-function-invoker", {
location: dataFunction.location,
service: dataFunction.name,
role: "roles/run.invoker",
member: "allUsers",
});
// Create a JSON configuration file for the website.
const siteConfig = new gcp.storage.BucketObject("site-config", {
name: "config.json",
source: dataFunction.url.apply(url =>
new pulumi.asset.StringAsset(JSON.stringify({ api: url })),
),
contentType: "application/json",
bucket: siteBucket.name,
});
// Export the URLs of the website and serverless endpoint.
export const siteURL = pulumi.interpolate`https://storage.googleapis.com/${siteBucket.name}/index.html`;
export const apiURL = dataFunction.url;

Deploy the project#

First, be sure to enable the Cloud Functions, Cloud Build, Artifact Registry and Cloud Run APIs in your project:

Terminal window
gcloud services enable cloudfunctions.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com run.googleapis.com --project $(pulumi config get gcp:project)

Deploy with pulumi up. It starts with a preview of what it’s about to create and asks before it changes anything. Choose yes to deploy.

Terminal window
pulumi up

Pulumi adds a random suffix to most resource names, so the Cloud Function data-function becomes something like data-function-4f8a2c1. This is autonaming. It lets you deploy the same program to more than one stack, and lets Pulumi create a replacement before it deletes the old resource, without names colliding.

When it finishes, Pulumi prints the stack’s outputs, values it only knows once the resources exist:

siteURL

The HTTPS URL of the static website.

apiURL

The HTTPS URL of the serverless function endpoint.

Read one any time with pulumi stack output <name>, or pass it to another command. This opens the website in your browser:

Terminal window
open $(pulumi stack output siteURL)

The website gets the time from the function. Call the function from the terminal with curl; it prints the current time in milliseconds, like {"now": 1792591509000}:

Terminal window
curl -s $(pulumi stack output apiURL)
Need help?

If pulumi up reports failed to load application credentials, sign in again:

Terminal window
gcloud auth application-default login

Still stuck? Let us know.

Customize the project#

Projects created with this template expose the following configuration settings:

gcp:region

The Google Cloud region to deploy into. Defaults to us-central1.

sitePath

The path to the folder containing the files of the website. Defaults to www, which is the name (and relative path) of the folder included with the template.

appPath

The path to the folder containing the serverless functions to be deployed. Defaults to app, which is also included with the template.

indexDocument

The file to use for top-level pages. Defaults to index.html.

errorDocument

The file to use for error pages. Defaults to error.html.

All of these settings are optional and may be adjusted either by editing the stack configuration file directly (by default, Pulumi.dev.yaml) or by changing their values with pulumi config set.

For example, to deploy a website from another folder on your computer, replacing ../my-existing-website/build with the path to your site’s files:

Terminal window
pulumi config set sitePath ../my-existing-website/build
pulumi up

Moving the function to another region#

The region setting decides where the function runs. Change it to europe-west1 and deploy: Pulumi creates the function in the new region, then deletes the old one. gcloud functions list then shows it in europe-west1:

Terminal window
pulumi config set gcp:region europe-west1
pulumi up
gcloud functions list --project $(pulumi config get gcp:project)

Cleaning up#

You can cleanly destroy the stack and all of its infrastructure with pulumi destroy:

Terminal window
pulumi destroy

Learn more#

Related

The infrastructure as code platform for any cloud.