Serve dynamic content and host microservices with Cloud Run

PairCloud Run withFirebase Hosting to generate and serve yourdynamic content or build REST APIs as microservices.

UsingCloud Run, you candeploy an application packaged in a container image. Then, usingFirebase Hosting, you can direct HTTPS requests to trigger yourcontainerized app.

  • Cloud Run supportsseveral languages (including Go, Node.js, Python, and Java), giving you the flexibility to usethe programming language and framework of your choice.
  • Cloud Runautomatically and horizontally scales your container image to handle the received requests, then scales down whendemand decreases.
  • You onlypay for the CPU,memory, and networking consumed during request handling.

For example use cases and samples forCloud Run integrated withFirebase Hosting, visit ourserverless overview.


This guide shows you how to:

  1. Write a simple Hello World application
  2. Containerize an app and upload it toArtifact Registry
  3. Deploy the container image toCloud Run
  4. DirectHosting requests to your containerized app

Note that to improve the performance of serving dynamic content, you canoptionally tune yourcache settings.

Before you begin

Before usingCloud Run, you need to complete some initial tasks,including setting up aCloud Billing account, enabling theCloud RunAPI, and installing thegcloud command line tool.

Set up billing for your project

Cloud Run offersfree usage quota,but you still must have aCloud Billing account associated with your Firebase project to use or try outCloud Run.

If your Firebase project is on the Spark pricing plan, and you associate your Firebase project with aCloud Billing account, then your Firebase project is automatically upgraded to the Blaze pricing plan. Review theFirebase pricing page for a comparison of the Spark and Blaze plans. Also, make sure to reviewCloud Runpricing and itsquotas and limits.Note: Every Firebase project is also aGoogle Cloud project.
Visit
Understand Firebase Projectsto learn more about the Firebase andGoogle Cloud project relationship.

Enable the API and install the SDK

  1. Enable theCloud Run API in the Google APIs console:

    1. Open theCloud Run API page in the Google APIs console.

    2. When prompted, select your Firebase project.

    3. ClickEnable on theCloud Run API page.

  2. Install and initialize theCloud SDK.

  3. Check that thegcloud tool is configured for the correct project:

    gcloud config list

Step 1: Write the sample application

Note thatCloud Run supportsmany other languages in addition to the languages shown in the following sample.

Go

  1. Create a new directory namedhelloworld-go, then change directory intoit:

    mkdir helloworld-go
    cd helloworld-go
  2. Create a new file namedhelloworld.go, then add the following code:

    packagemainimport("fmt""log""net/http""os")funchandler(whttp.ResponseWriter,r*http.Request){log.Print("helloworld: received a request")target:=os.Getenv("TARGET")iftarget==""{target="World"}fmt.Fprintf(w,"Hello %s!\n",target)}funcmain(){log.Print("helloworld: starting server...")http.HandleFunc("/",handler)port:=os.Getenv("PORT")ifport==""{port="8080"}log.Printf("helloworld: listening on port %s",port)log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s",port),nil))}

    This code creates a basic web server that listens on the port defined bythePORT environment variable.

Your app is finished and ready to be containerized and uploaded toArtifact Registry.

Node.js

  1. Create a new directory namedhelloworld-nodejs, then change directoryinto it:

    mkdir helloworld-nodejs
    cd helloworld-nodejs
  2. Create apackage.json file with the following contents:

    {"name":"knative-serving-helloworld","version":"1.0.0","description":"Simple hello world sample in Node","main":"index.js","scripts":{"start":"node index.js"},"author":"","license":"Apache-2.0","dependencies":{"express":"^4.22.1"}}
  3. Create a new file namedindex.js, then add the following code:

    constexpress=require('express');constapp=express();app.get('/',(req,res)=>{console.log('Hello world received a request.');consttarget=process.env.TARGET||'World';res.send(`Hello${target}!\n`);});constport=process.env.PORT||8080;app.listen(port,()=>{console.log('Hello world listening on port',port);});

    This code creates a basic web server that listens on the port defined bythePORT environment variable.

Your app is finished and ready to be containerized and uploaded toArtifact Registry.

Python

  1. Create a new directory namedhelloworld-python, then change directoryinto it:

    mkdir helloworld-python
    cd helloworld-python
  2. Create a new file namedapp.py, then add the following code:

    importosfromflaskimportFlaskapp=Flask(__name__)@app.route('/')defhello_world():target=os.environ.get('TARGET','World')return'Hello{}!\n'.format(target)if__name__=="__main__":app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT',8080)))

    This code creates a basic web server that listens on the port defined bythePORT environment variable.

Your app is finished and ready to be containerized and uploaded toArtifact Registry.

Java

  1. InstallJava SE 8 or later JDK andCURL.

    Note that we only need to do this to create the new web project in thenext step. The Dockerfile, which is described later, will load alldependencies into the container.

  2. From the console, create a new empty web project using cURL thenunzip commands:

    curl https://start.spring.io/starter.zip \    -d dependencies=web \    -d name=helloworld \    -d artifactId=helloworld \    -o helloworld.zip
    unzip helloworld.zip

    This creates a SpringBoot project.

  3. Update theSpringBootApplication class insrc/main/java/com/example/helloworld/HelloworldApplication.java byadding a@RestController to handle the/ mapping and also add a@Value field to provide theTARGET environment variable:

    packagecom.example.helloworld;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;@SpringBootApplicationpublicclassHelloworldApplication{@Value("${TARGET:World}")Stringtarget;@RestControllerclassHelloworldController{@GetMapping("/")Stringhello(){return"Hello "+target+"!";}}publicstaticvoidmain(String[]args){SpringApplication.run(HelloworldApplication.class,args);}}

    This code creates a basic web server that listens on the port defined bythePORT environment variable.

Your app is finished and ready to be containerized and uploaded toArtifact Registry.

Step 2: Containerize an app and upload it toArtifact Registry

  1. Containerize the sample app by creating a new file namedDockerfile in thesame directory as the source files. Copy the following content into yourfile.

    Go

    #UsetheofficialGolangimagetocreateabuildartifact.#ThisisbasedonDebianandsetstheGOPATHto/go.FROMgolang:latestASbuilderARGTARGETOSARGTARGETARCH#Createandchangetotheappdirectory.WORKDIR/app#Copylocalcodetothecontainerimage.COPY../#Installdependenciesandtidyupthego.modandgo.sumfiles.RUNgomodtidy#Buildthebinary.#-mod=readonlyensuresimmutablego.modandgo.sumincontainerbuilds.RUNCGO_ENABLED=0GOOS=${TARGETOS}GOARCH=${TARGETARCH}gobuild-mod=readonly-v-oserver#UsetheofficialAlpineimageforaleanproductioncontainer.#https://hub.docker.com/_/alpine#https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-buildsFROMalpine:3RUNapkadd--no-cacheca-certificates#Copythebinarytotheproductionimagefromthebuilderstage.COPY--from=builder/app/server/server#Runthewebserviceoncontainerstartup.CMD["/server"]

    Node.js

    #UsetheofficiallightweightNode.js12image.#https://hub.docker.com/_/nodeFROMnode:12-slim#Createandchangetotheappdirectory.WORKDIR/usr/src/app#Copyapplicationdependencymanifeststothecontainerimage.#Awildcardisusedtoensurebothpackage.jsonANDpackage-lock.jsonarecopied.#Copyingthisseparatelypreventsre-runningnpminstalloneverycodechange.COPYpackage*.json./#Installproductiondependencies.RUNnpminstall--only=production#Copylocalcodetothecontainerimage.COPY../#Runthewebserviceoncontainerstartup.CMD["npm","start"]

    Python

    # Use the official lightweight Python image.# https://hub.docker.com/_/pythonFROMpython:3.7-slim# Allow statements and log messages to immediately appear in the Knative logsENVPYTHONUNBUFFEREDTrue# Copy local code to the container image.ENVAPP_HOME/appWORKDIR$APP_HOMECOPY../# Install production dependencies.RUNpipinstallFlaskgunicorn# Run the web service on container startup. Here we use the gunicorn# webserver, with one worker process and 8 threads.# For environments with multiple CPU cores, increase the number of workers# to be equal to the cores available.CMDexecgunicorn--bind:$PORT--workers1--threads8--timeout0app:app

    Java

    #Usetheofficialmaven/Java8imagetocreateabuildartifact:https://hub.docker.com/_/mavenFROMmaven:3.5-jdk-8-alpineASbuilder#Copylocalcodetothecontainerimage.WORKDIR/appCOPYpom.xml.COPYsrc./src#Buildareleaseartifact.RUNmvnpackage-DskipTests#UsetheOfficialOpenJDKimageforaleanproductionstageofourmulti-stagebuild.#https://hub.docker.com/_/openjdk#https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-buildsFROMopenjdk:8-jre-alpine#Copythejartotheproductionimagefromthebuilderstage.COPY--from=builder/app/target/helloworld-*.jar/helloworld.jar#Runthewebserviceoncontainerstartup.CMD["java","-Djava.security.egd=file:/dev/./urandom","-jar","/helloworld.jar"]

  2. Build your container image usingCloud Build by running the followingcommand from the directory containing your Dockerfile:

    gcloud builds submit --tag gcr.io/PROJECT_ID/helloworld

    Upon success, you will see a SUCCESS message containing the image name
    (gcr.io/PROJECT_ID/helloworld).

The container image is now stored inArtifact Registry and can be re-used ifdesired.

Note that, instead ofCloud Build, you can use a locally installed versionof Docker tobuild your container locally.

Step 3: Deploy the container image toCloud Run

AllowedCloud Run regions

For the best performance, colocate yourCloud Run service withHosting using the following regions:

  • us-west1
  • us-central1
  • us-east1
  • europe-west1
  • asia-east1

Rewrites toCloud Run fromHosting are supported in thefollowing regions:

  • asia-east1
  • asia-east2
  • asia-northeast1
  • asia-northeast2
  • asia-northeast3
  • asia-south1
  • asia-south2
  • asia-southeast1
  • asia-southeast2
  • australia-southeast1
  • australia-southeast2
  • europe-central2
  • europe-north1
  • europe-southwest1
  • europe-west1
  • europe-west12
  • europe-west2
  • europe-west3
  • europe-west4
  • europe-west6
  • europe-west8
  • europe-west9
  • me-central1
  • me-west1
  • northamerica-northeast1
  • northamerica-northeast2
  • southamerica-east1
  • southamerica-west1
  • us-central1
  • us-east1
  • us-east4
  • us-east5
  • us-south1
  • us-west1
  • us-west2
  • us-west3
  • us-west4
  • us-west1
  • us-central1
  • us-east1
  • europe-west1
  • asia-east1

  1. Deploy using the following command:

    gcloud run deploy --image gcr.io/PROJECT_ID/helloworld

  2. When prompted:

    Important: Remember the region and the service name so that you can usethese values when defining theregion andserviceID, respectively, inthefirebase.json rewrite rule later.
  3. Wait a few moments for the deploy to complete. On success, the command linedisplays the service URL. For example:https://helloworld-RANDOM_HASH-us-central1.a.run.app

  4. Visit your deployed container by opening the service URL in a web browser.

Note: Consider applying amaximum instance limit to prevent unexpected scaling of theCloud Run service.

The next step walks you through how to access this containerized appfrom aFirebase Hosting URL so that it can generate dynamic content for yourFirebase-hosted site.

Step 4: Direct hosting requests to your containerized app

Withrewrite rules, you can direct requeststhat match specific patterns to a single destination.

The following example shows how to direct all requests from the page/helloworld on yourHosting site to trigger the startup and running ofyourhelloworld container instance.

  1. Make sure that:

    For detailed instructions about installing the CLI and initializingHosting, see theGet Started guide forHosting.

  2. Open yourfirebase.json file.

  3. Add the followingrewrite configuration under thehosting section:

    "hosting":{// ...// Add the "rewrites" attribute within "hosting""rewrites":[{"source":"/helloworld","run":{"serviceId":"helloworld",// "service name" (from when youdeployed the container image)"region":"us-central1",// optional (if omitted, default is us-central1)"pinTag":true// optional (see note below)}}]}
  4. Deploy your hosting configuration to your site by running the followingcommand from the root of your project directory:

    firebase deploy --only hosting

HowpinTag works within therun block

With this feature, you can ensure that the revision of yourCloud Runservice for generating your site's dynamic content is kept in sync with yourstaticHosting resources andHosting config. Also, this feature allowsyou to preview your rewrites toCloud Run onHosting previewchannels.

If you add"pinTag": true to arun block of thehosting.rewritesconfig, your staticHosting resources and configuration will be pinned tothe most recent revision of theCloud Run service, at the time ofdeploy. If you roll back a version of your site, the revision of the "pinned"Cloud Run service is also rolled back.

This feature relies onCloud Run tags,which have a limit of 1000 tags per service and 2000 tags per region. Thismeans that after hundreds of deploys, the oldest versions of a site may stopworking.

Your container is now reachable via the following URLs:

  • Your Firebase subdomains:
    PROJECT_ID.web.app/ andPROJECT_ID.firebaseapp.com/

  • Any connectedcustom domains:
    CUSTOM_DOMAIN/

Note:Firebase Hosting is subject to a 60-second request timeout. If yourapp requires more than 60 seconds to run, you'll receive an HTTPS status code504 (request timeout). To support dynamic content that requires longercompute time, consider using anApp Engine flexible environment.

Visit theHosting configuration page formore details about rewrite rules. You canalso learn about thepriority order of responsesfor variousHosting configurations.

Test locally

During development, you can run and test your container image locally. Fordetailed instructions, visit theCloud Run documentation.

Next steps

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-05 UTC.