BUG :Firebase App Hosting: NEXT_PUBLIC_ env vars UNDEFINED in Cloud Run runtime despite correct config

Hello everyone,

I’m hitting a wall with Firebase App Hosting for my Next.js (App Router) application, and I’ve exhausted all troubleshooting steps. I’m seeing a persistent issue where process.env.NEXT_PUBLIC_ environment variables are undefined at runtime in the deployed app, causing client-side crashes, even though they are correctly configured in apphosting.yaml.

Summary of the Problem:

  • My Next.js App Router app builds successfully on Firebase App Hosting.
  • However, when the app loads in the browser, I get a client-side error: "Firebase API Key is missing. Check your .env.local file and next.config.ts env property."
  • My server-side API routes that attempt to read these same NEXT_PUBLIC_ variables also find them undefined, leading to 500 errors.
  • The only way to get the app functional is by hardcoding the public Firebase client configuration directly into src/lib/firebase.ts.

Environment:

  • Next.js Version: 15.3.5 (as per build logs)
  • Firebase JS SDK: (Latest stable versions used)
  • Deployment Method: GitHub integration with Automatic Rollouts to master branch.

Detailed Troubleshooting Steps & Evidence (What I’ve Already Tried):

  1. apphosting.yaml Configuration:
  • I’ve meticulously configured my apphosting.yaml (renamed from apphosting.staging.yaml for clarity).

  • All NEXT_PUBLIC_ variables (e.g., NEXT_PUBLIC_FIREBASE_API_KEY, NEXT_PUBLIC_APP_URL) are defined under runConfig.env with **explicit `availability: [“BUILD”, “RUNTIME”].

  • Example snippet from apphosting.yaml:`YAMLrunConfig:

env:
- variable: NEXT_PUBLIC_FIREBASE_API_KEY
value: “YOUR_FIREBASE_WEB_API_KEY_HERE” # Placeholder for actual key
availability: [“BUILD”, “RUNTIME”]
# … all other NEXT_PUBLIC_ variables are similarly defined
# … and other private secrets also with availability: [“RUNTIME”]`

  1. next.config.ts Configuration:

    I’ve added an explicit env block in next.config.ts to instruct Next.js to inline these variables, as commonly suggested for NEXT_PUBLIC_ variables.

    Example snippet from next.config.ts : TypeScript// next.config.ts
    const nextConfig: NextConfig = {
    env: {
    NEXT_PUBLIC_FIREBASE_API_KEY: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
    // … all other NEXT_PUBLIC_ variables
    },
    // … rest of config
    };`

  2. Code Access & Guards (src/lib/firebase.ts):

  • My Firebase initialization is client-side ("use client" components, typeof window !== 'undefined' guards) and uses lazy, on-demand getters.
  • My code accesses variables directly via process.env.NEXT_PUBLIC_VARIABLE_NAME.
  1. Debugging process.env (Cloud Run Logs - CRITICAL EVIDENCE):
  • I created a simple API route (/api/firebase-client-config) that just logs and returns process.env.NEXT_PUBLIC_FIREBASE_API_KEY.
  • Cloud Run logs for this API route consistently show apiKey: undefined (and other NEXT_PUBLIC_ vars as undefined), even though the API route runs on the deployed server (Cloud Run instance).
  • This API route returns a 500 error because of these missing variables, which then causes the client-side error.
  1. Cloud Build Logs (Pre-Deployment - CRITICAL EVIDENCE):
  • Cloud Build logs show that the apphosting.yaml is read.
  • However, in the Final app hosting schema output of the “preparer” step, FIREBASE_WEBAPP_CONFIG (derived from my NEXT_PUBLIC_ variables) only shows availability: - BUILD, despite my YAML explicitly requesting ["BUILD", "RUNTIME"]. FIREBASE_CONFIG correctly shows ["BUILD", "RUNTIME"].
  1. **Deployed Cloud Run Service YAML (Final Manifest)
  • I extracted the actual Cloud Run Service YAML for my deployed service.
  • In the spec.template.spec.containers.env block, FIREBASE_WEBAPP_CONFIG and its individual NEXT_PUBLIC_ components are COMPLETELY ABSENT. Only FIREBASE_CONFIG is present.

The Core Problem:

It appears there is a bug in Firebase App Hosting’s current implementation for Next.js where it fails to consistently inject NEXT_PUBLIC_ (and other runConfig.env) environment variables into the process.env of the deployed Cloud Run container at runtime, despite being correctly configured in apphosting.yaml with availability: ["BUILD", "RUNTIME"].

Current Workaround:

My application is currently functional only because I have hardcoded the public Firebase client configuration directly into src/lib/firebase.ts. This is not a sustainable or secure long-term solution.

Has anyone else encountered this precise issue where NEXT_PUBLIC_ environment variables, correctly configured in apphosting.yaml with availability: ["BUILD", "RUNTIME"], are simply not present in process.env of the deployed Cloud Run container?

Any insights, workarounds, or confirmation of this bug would be immensely helpful. I’m looking for a way to get Firebase App Hosting to reliably inject these variables without hardcoding

1 Like

Did you do this for all secrets?
firebase apphosting:secrets:grantaccess NEXT_PUBLIC_XXX --backend

I’m
Running into the same problem. Around and around we go. My issue is with be genkit and stripe. Errors are that not finding the api keys, etc. So frustrating. And all the “fixes” Or workarounds mess up the functionality.

I have been running into the exact same problem; have implemented all the same steps (except hardcoding the variables).

When Publishing through Firebase Studio, the app publishes just fine and works. When publishing through Github (doing the same method and set up in Firebase to look at the release branch) the build passes but I get constant errors that the firebase config cannot be found. Same source code with no changes between the two deploys.

Seems like the only work-around right now is to keep publishing from Firebase Studio. I would however like to get deployments working from Github

Those Firebase configs are client-safe: Firebase security checklist

You should use Cloud Secret Manager to store and access secrets.

I am using Google Cloud Secrets and referencing them in my apphosting.yaml file like so:

# Settings for Backend (on Cloud Run).
# See https://firebase.google.com/docs/app-hosting/configure#cloud-run
runConfig:
  # Increase this value if you'd like to automatically spin up
  # more instances in response to increased traffic.
  minInstances: 0
  maxInstances: 100
  concurrency: 80
  cpu: 1
  memoryMiB: 512

  env:
    - variable: GEMINI_API_KEY
      secret: GEMINI_API_KEY
      availability:
        - BUILD
        - RUNTIME
    - variable: NEXT_PUBLIC_FIREBASE_API_KEY
      secret: NEXT_PUBLIC_FIREBASE_API_KEY
      availability:
        - BUILD
        - RUNTIME

I am facing the same issue. I have added the gemini_API_key everywhere in .env, apphosting.yaml, set it as a secret and assigned to the backend, tried injecting on the cloudrun instance and re-deploying, but failing to get the code working on production from a git-terminal deploying from firebase studio.

everything works in the local environment.. but production environment not working.

Also my problem is also exactly with genkit initialisation, the firestore worksfine. Even trying to forcefully passing at runtime, not seems to be working.

I’ve found the solution: it depends on the environment name set in the backend.

Sources can be found here at the Firebase blog and here in the Firebase AppHosting documentation

ie: if you have a development environment name for the Studio backend, you can use the apphosting.yaml which will always be the base config file, and you can override other variables with apphosting.development.yaml

Additionally, if you let Gemini create your apphosting.yaml file, be sure to check that the environment variables are declared in env: not environmentVariables: (like mine was)