Deploy multiple environments from a codebase

It's common to have multiple environments deployed from the same codebase, each with slightly different configuration. For example, you might want to assign less CPU and RAM to your staging environment, or you might want to make sure your production environment keeps at least 1 instance active and ready to serve requests. You might also want to specify different environment variables and secrets depending on the environment and resources you want to use.

This guide describes how to deploy a production and staging environment, each to a separate Firebase project. Following the same principles, you can deploy to other different kinds of environments. To learn more about environments, check out the Overview of environments and General best practices for setting up Firebase projects.

Prerequisites

  • Your application code is already stored in GitHub.
  • You have already created a distinct project for each of your environments—for example my-production-firebase-project and my-staging-firebase-project. Make sure to to tag your production Firebase project with the "production" environment type.
  • In each project, you've created an App Hosting backend, with the live branch set to the GitHub branch you want to deploy (such as main). See Get started with App Hosting for more information.

Step 0: Create a default configuration in apphosting.yaml

App Hosting supports a configuration file called apphosting.yaml to manage runtime settings (CPU, concurrency, memory limits, etc.) and environment variables for your app. It also supports references to secrets managed with Cloud Secret Manager, making it safe to check into source control. For more information, see Configure a backend.

To get started, create an apphosting.yaml file in your app's root directory. This is the fallback configuration file that is used when an environment-specific configuration file isn't found. The values stored in apphosting.yaml should be defaults that are safe to use for all environments.

The next sections explain how to override default values in apphosting.yaml for specific environments. This example flow creates a staging environment.

Step 1: Set Environment name

Each App Hosting backend has an Environment name setting. This field is used to map your backend to an environment-specific configuration file, and can be changed at any time. You can only set one environment name per backend.

To set your backend's environment name,

  1. In the Firebase console, select your staging project (in this example, my-staging-firebase-project).
  2. Select App Hosting from the left nav.
  3. Click View dashboard on your chosen backend.
  4. In the Settings tab, select Deployment.
  5. Under Environment name, enter the name of your environment. You can name the environment whatever you like. In this example, it's staging.
  6. Click Save.

When an App Hosting rollout is triggered for your backend (either on git push or manually through the console), App Hosting will check for an apphosting.ENVIRONMENT_NAME.yaml file before falling back to apphosting.yaml.

Step 2: Create your environment-specific apphosting.yaml file

For your environment-specific configuration, create a file with the name apphosting.ENVIRONMENT_NAME.yaml in order to specify environment-specific overrides. This file has the same format as the default apphosting.yaml and must be located in your app's root directory alongside apphosting.yaml.

At build time, App Hosting merges these two files, with priority given to values in the environment-specific YAML file over the base apphosting.yaml file.

In this example, you'll create a file named apphosting.staging.yaml in the app's root directory:


runConfig:
  cpu: 1
  memoryMiB: 512
  concurrency: 5

env:
  -   variable: API_URL
    value: api.staging.service.com
    availability:
      -   BUILD

  -   variable: DATABASE_URL
    secret: secretStagingDatabaseURL

Suppose you already had an apphosting.yaml that looked like:

runConfig:
  cpu: 3
  memoryMiB: 1024
  maxInstances: 4
  minInstances: 0
  concurrency: 100

env:
  -   variable: API_URL
    value: api.service.com
    availability:
      -   BUILD
      -   RUNTIME

  -   variable: STORAGE_BUCKET
    value: mybucket.firebasestorage.app
    availability:
      -   RUNTIME

  -   variable: API_KEY
    secret: secretIDforAPI

The final merged output, which you can inspect in your Cloud Build logs, would look like this:

runConfig:
  cpu: 1
  memoryMiB: 512
  maxInstances: 4
  minInstances: 0
  concurrency: 5

env:
  -   variable: API_URL
    value: api.staging.service.com
    availability:
      -   BUILD

  -   variable: STORAGE_BUCKET
    value: mybucket.firebasestorage.app
    availability:
      -   RUNTIME

  -   variable: API_KEY
    secret: secretIDforAPI

  -   variable: DATABASE_URL
    secret: secretStagingDatabaseURL

Note that certain runConfig values such as CPU have been overwritten as well as any overlapping environment variables.

Step 3: Deploy your codebase

Once you are finished editing your environment specific apphosting.ENVIRONMENT_NAME.yaml file, push your file to GitHub:

$ git add apphosting.<ENVIRONMENT_NAME>.yaml
$ git commit -m "Added environment specific yaml file"
$ git push

Any backends tagged with this environment name will use the specific override values you have specified in its corresponding YAML file, and fall back to apphosting.yaml when a value isn't found. For backends without an associated environment name, you can continue to use apphosting.yaml.

Next steps