Firebase Cloud Functions v2 uses environment variables via .env files and parameterized configuration with defineString() and defineSecret() instead of the deprecated functions.config(). Store non-sensitive values in .env files inside the functions directory and secrets in Cloud Secret Manager using defineSecret(). Access them directly in your function code. Deploy with firebase deploy --only functions and the CLI will prompt for any missing parameters.
Managing Environment Variables and Secrets in Firebase Cloud Functions
Cloud Functions often need external configuration like API keys, feature flags, and service URLs. This tutorial covers the three configuration methods available in v2 functions: .env files for simple environment variables, parameterized configuration with defineString/defineInt for validated parameters, and defineSecret for sensitive values stored in Cloud Secret Manager. You will also learn how to migrate from the deprecated functions.config() API.
Prerequisites
- A Firebase project on the Blaze plan with Cloud Functions initialized
- Firebase CLI version 11.14.0 or later installed
- A functions directory initialized with firebase init functions
- Basic knowledge of Cloud Functions and TypeScript
Step-by-step guide
Create a .env file for environment variables
Create a .env file for environment variables
Create a .env file inside your functions/ directory. Variables defined here are available as process.env.VARIABLE_NAME in your function code. You can also create environment-specific files like .env.production and .env.local. The .env file applies to all environments, while .env.local applies only to the emulator.
1# functions/.env — applies to all deployed environments2STRIPE_WEBHOOK_URL=https://api.stripe.com/v1/webhooks3APP_NAME=MyFirebaseApp4MAX_RETRIES=356# functions/.env.local — emulator only, overrides .env7STRIPE_WEBHOOK_URL=http://localhost:4242/webhook8APP_NAME=MyFirebaseApp-DevExpected result: The .env file exists in your functions/ directory and variables are accessible via process.env.
Use defineString and defineInt for parameterized config
Use defineString and defineInt for parameterized config
Parameterized configuration lets you define typed, validated configuration values that the Firebase CLI prompts for during deployment if not set. Import defineString and defineInt from firebase-functions/params. These values are resolved at deploy time and are available as function-level constants.
1import { defineString, defineInt } from "firebase-functions/params";2import { onRequest } from "firebase-functions/v2/https";34// Define parameters — CLI prompts if not set5const stripeWebhookUrl = defineString("STRIPE_WEBHOOK_URL", {6 description: "The Stripe webhook endpoint URL",7 default: "https://api.stripe.com/v1/webhooks",8});910const maxRetries = defineInt("MAX_RETRIES", {11 description: "Maximum retry attempts for failed operations",12 default: 3,13});1415export const processPayment = onRequest(async (req, res) => {16 const url = stripeWebhookUrl.value();17 const retries = maxRetries.value();1819 res.json({ webhook: url, maxRetries: retries });20});Expected result: The CLI prompts for any undefined parameters during firebase deploy, and values are accessible via .value() in your code.
Store secrets with defineSecret and Cloud Secret Manager
Store secrets with defineSecret and Cloud Secret Manager
For sensitive values like API keys, use defineSecret() which stores secrets in Google Cloud Secret Manager and injects them at runtime. Secrets are encrypted at rest and in transit. You must list the secret in the function's options so it is available at runtime.
1import { defineSecret } from "firebase-functions/params";2import { onRequest } from "firebase-functions/v2/https";34const stripeApiKey = defineSecret("STRIPE_API_KEY");5const openaiKey = defineSecret("OPENAI_API_KEY");67export const createCharge = onRequest(8 { secrets: [stripeApiKey, openaiKey] },9 async (req, res) => {10 // Secrets are available via .value() at runtime11 const stripe = require("stripe")(stripeApiKey.value());12 const charge = await stripe.charges.create({13 amount: 1000,14 currency: "usd",15 source: req.body.token,16 });1718 res.json({ chargeId: charge.id });19 }20);Expected result: Secrets are stored encrypted in Cloud Secret Manager and injected into the function at runtime.
Migrate from deprecated functions.config()
Migrate from deprecated functions.config()
The legacy functions.config() API (set via firebase functions:config:set) is deprecated and will be decommissioned in March 2027. Migrate by exporting your existing config to a .env file, then replacing all functions.config().service.key references with process.env.SERVICE_KEY or defineString/defineSecret equivalents.
1# Step 1: Export existing config to .env format2firebase functions:config:export3# This creates a .env file with your existing config values45# Step 2: Replace in code6# BEFORE (deprecated):7# const apiKey = functions.config().stripe.key;89# AFTER (v2 — choose one approach):10# Option A: process.env11# const apiKey = process.env.STRIPE_KEY;1213# Option B: defineSecret (recommended for secrets)14# const apiKey = defineSecret("STRIPE_KEY");15# Then access with apiKey.value() inside the functionExpected result: All functions.config() references are replaced with .env variables or defineSecret, and the .env file contains your migrated values.
Access config in the emulator
Access config in the emulator
When running the Firebase Emulator Suite, .env and .env.local files are automatically loaded. Secrets defined with defineSecret() are also prompted or can be set in .env.local for local development. This means your functions work the same locally as in production.
1# functions/.env.local — emulator-only overrides2STRIPE_API_KEY=sk_test_fake_key_for_local_dev3OPENAI_API_KEY=sk-test-fake-key45# Start the emulator6firebase emulators:start --only functions78# Your functions will use the .env.local valuesExpected result: Functions running in the emulator use values from .env.local, while deployed functions use .env and Cloud Secret Manager.
Complete working example
1import * as admin from "firebase-admin";2import { defineString, defineInt, defineSecret } from "firebase-functions/params";3import { onRequest } from "firebase-functions/v2/https";4import { onDocumentCreated } from "firebase-functions/v2/firestore";5import { logger } from "firebase-functions";67admin.initializeApp();89// Environment variables (from .env file)10const appName = defineString("APP_NAME", {11 description: "Application display name",12 default: "MyApp",13});1415const maxRetries = defineInt("MAX_RETRIES", {16 description: "Max retry attempts",17 default: 3,18});1920// Secrets (stored in Cloud Secret Manager)21const stripeKey = defineSecret("STRIPE_API_KEY");22const sendgridKey = defineSecret("SENDGRID_API_KEY");2324// HTTP function using config and secrets25export const healthCheck = onRequest(26 { secrets: [stripeKey] },27 async (req, res) => {28 res.json({29 app: appName.value(),30 maxRetries: maxRetries.value(),31 stripeConfigured: !!stripeKey.value(),32 });33 }34);3536// Firestore trigger using secrets37export const onOrderCreated = onDocumentCreated(38 {39 document: "orders/{orderId}",40 secrets: [sendgridKey],41 },42 async (event) => {43 if (!event.data) return;44 const order = event.data.data();4546 logger.info(`New order in ${appName.value()}: ${event.params.orderId}`);4748 // Use sendgridKey.value() to send confirmation email49 logger.info("SendGrid configured:", !!sendgridKey.value());50 }51);Common mistakes when accessing Config Variables in Firebase Cloud Functions
Why it's a problem: Putting API keys and passwords in .env files instead of using defineSecret()
How to avoid: The .env file is deployed with your function code and is not encrypted. Use defineSecret() for any sensitive value — it stores secrets in Google Cloud Secret Manager with encryption at rest.
Why it's a problem: Forgetting to list secrets in the function's options object
How to avoid: Secrets must be explicitly listed in the secrets array of the function options: onRequest({ secrets: [mySecret] }, handler). Without this, the secret is not available at runtime.
Why it's a problem: Still using the deprecated functions.config() API in new functions
How to avoid: Run firebase functions:config:export to migrate existing config to .env format. Use defineString/defineInt for non-sensitive values and defineSecret for sensitive ones.
Best practices
- Use defineSecret() for all sensitive values like API keys, passwords, and tokens — never store them in .env files
- Keep .env.local for emulator-only development values and add it to .gitignore
- Add descriptions and defaults to defineString/defineInt parameters for self-documenting configuration
- Run firebase functions:config:export to migrate from the deprecated functions.config() before the March 2027 decommission
- Use environment-specific .env files (.env.production, .env.staging) for multi-environment setups
- Never commit .env files containing real credentials to version control — add them to .gitignore
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Show me how to use environment variables and secrets in Firebase Cloud Functions v2 with TypeScript. I need to store an API key securely using defineSecret and a regular config value using defineString. Include the .env file setup and how to access values in the function.
Set up Firebase Cloud Functions v2 configuration with defineString for APP_NAME, defineInt for MAX_RETRIES in a .env file, and defineSecret for STRIPE_API_KEY stored in Cloud Secret Manager. Show the complete TypeScript code with proper secret injection in function options.
Frequently asked questions
Is functions.config() still supported?
It is deprecated and will be fully decommissioned in March 2027. You should migrate to .env files and defineString/defineSecret now. Run firebase functions:config:export to generate a .env file from your existing config.
Where are secrets stored when I use defineSecret()?
Secrets are stored in Google Cloud Secret Manager, which encrypts them at rest and in transit. They are injected into your function's runtime environment only when the function executes.
Can I use process.env directly instead of defineString?
Yes. Variables in your .env file are available via process.env.VARIABLE_NAME. defineString adds deploy-time validation, CLI prompts for missing values, and type safety, but process.env works for simple cases.
How do I set different config values for staging and production?
Create separate .env files like .env.staging and .env.production. Use Firebase project aliases in .firebaserc and deploy to the correct project. The CLI automatically loads the matching .env file based on the active project.
Do .env variables work in the Firebase Emulator?
Yes. The emulator loads .env and .env.local files automatically. Values in .env.local take priority over .env, making it ideal for local development overrides.
Is there a cost for using Cloud Secret Manager with defineSecret?
Cloud Secret Manager offers 6 active secret versions free per month with 10,000 free access operations. For most Firebase projects, this is more than sufficient and costs nothing extra.
Can I use defineSecret in Firestore trigger functions?
Yes. Pass the secret in the function options object: onDocumentCreated({ document: 'path/{id}', secrets: [mySecret] }, handler). The secret is then available via mySecret.value() inside the handler.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation