Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Access Config Variables in Firebase Cloud Functions

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.

What you'll learn

  • How to use .env files for configuration in Cloud Functions v2
  • How to use defineString() and defineInt() for parameterized config
  • How to store and access secrets with defineSecret() and Cloud Secret Manager
  • Why functions.config() is deprecated and how to migrate away from it
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read10-15 minFirebase Blaze plan, Cloud Functions v2, firebase-functions 4.x+, Node.js 18/20/22March 2026RapidDev Engineering Team
TL;DR

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

1

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.

typescript
1# functions/.env applies to all deployed environments
2STRIPE_WEBHOOK_URL=https://api.stripe.com/v1/webhooks
3APP_NAME=MyFirebaseApp
4MAX_RETRIES=3
5
6# functions/.env.local emulator only, overrides .env
7STRIPE_WEBHOOK_URL=http://localhost:4242/webhook
8APP_NAME=MyFirebaseApp-Dev

Expected result: The .env file exists in your functions/ directory and variables are accessible via process.env.

2

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.

typescript
1import { defineString, defineInt } from "firebase-functions/params";
2import { onRequest } from "firebase-functions/v2/https";
3
4// Define parameters — CLI prompts if not set
5const stripeWebhookUrl = defineString("STRIPE_WEBHOOK_URL", {
6 description: "The Stripe webhook endpoint URL",
7 default: "https://api.stripe.com/v1/webhooks",
8});
9
10const maxRetries = defineInt("MAX_RETRIES", {
11 description: "Maximum retry attempts for failed operations",
12 default: 3,
13});
14
15export const processPayment = onRequest(async (req, res) => {
16 const url = stripeWebhookUrl.value();
17 const retries = maxRetries.value();
18
19 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.

3

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.

typescript
1import { defineSecret } from "firebase-functions/params";
2import { onRequest } from "firebase-functions/v2/https";
3
4const stripeApiKey = defineSecret("STRIPE_API_KEY");
5const openaiKey = defineSecret("OPENAI_API_KEY");
6
7export const createCharge = onRequest(
8 { secrets: [stripeApiKey, openaiKey] },
9 async (req, res) => {
10 // Secrets are available via .value() at runtime
11 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 });
17
18 res.json({ chargeId: charge.id });
19 }
20);

Expected result: Secrets are stored encrypted in Cloud Secret Manager and injected into the function at runtime.

4

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.

typescript
1# Step 1: Export existing config to .env format
2firebase functions:config:export
3# This creates a .env file with your existing config values
4
5# Step 2: Replace in code
6# BEFORE (deprecated):
7# const apiKey = functions.config().stripe.key;
8
9# AFTER (v2 choose one approach):
10# Option A: process.env
11# const apiKey = process.env.STRIPE_KEY;
12
13# Option B: defineSecret (recommended for secrets)
14# const apiKey = defineSecret("STRIPE_KEY");
15# Then access with apiKey.value() inside the function

Expected result: All functions.config() references are replaced with .env variables or defineSecret, and the .env file contains your migrated values.

5

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.

typescript
1# functions/.env.local emulator-only overrides
2STRIPE_API_KEY=sk_test_fake_key_for_local_dev
3OPENAI_API_KEY=sk-test-fake-key
4
5# Start the emulator
6firebase emulators:start --only functions
7
8# Your functions will use the .env.local values

Expected result: Functions running in the emulator use values from .env.local, while deployed functions use .env and Cloud Secret Manager.

Complete working example

functions/src/index.ts
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";
6
7admin.initializeApp();
8
9// Environment variables (from .env file)
10const appName = defineString("APP_NAME", {
11 description: "Application display name",
12 default: "MyApp",
13});
14
15const maxRetries = defineInt("MAX_RETRIES", {
16 description: "Max retry attempts",
17 default: 3,
18});
19
20// Secrets (stored in Cloud Secret Manager)
21const stripeKey = defineSecret("STRIPE_API_KEY");
22const sendgridKey = defineSecret("SENDGRID_API_KEY");
23
24// HTTP function using config and secrets
25export 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);
35
36// Firestore trigger using secrets
37export 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();
45
46 logger.info(`New order in ${appName.value()}: ${event.params.orderId}`);
47
48 // Use sendgridKey.value() to send confirmation email
49 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.

ChatGPT Prompt

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.

Firebase Prompt

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.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.