# How to Access Config Variables in Firebase Cloud Functions

- Tool: Firebase
- Difficulty: Beginner
- Time required: 10-15 min
- Compatibility: Firebase Blaze plan, Cloud Functions v2, firebase-functions 4.x+, Node.js 18/20/22
- Last updated: March 2026

## 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.

## Before you start

- 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.

```
# functions/.env — applies to all deployed environments
STRIPE_WEBHOOK_URL=https://api.stripe.com/v1/webhooks
APP_NAME=MyFirebaseApp
MAX_RETRIES=3

# functions/.env.local — emulator only, overrides .env
STRIPE_WEBHOOK_URL=http://localhost:4242/webhook
APP_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.

```
import { defineString, defineInt } from "firebase-functions/params";
import { onRequest } from "firebase-functions/v2/https";

// Define parameters — CLI prompts if not set
const stripeWebhookUrl = defineString("STRIPE_WEBHOOK_URL", {
  description: "The Stripe webhook endpoint URL",
  default: "https://api.stripe.com/v1/webhooks",
});

const maxRetries = defineInt("MAX_RETRIES", {
  description: "Maximum retry attempts for failed operations",
  default: 3,
});

export const processPayment = onRequest(async (req, res) => {
  const url = stripeWebhookUrl.value();
  const retries = maxRetries.value();

  res.json({ webhook: url, maxRetries: retries });
});
```

**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.

```
import { defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/v2/https";

const stripeApiKey = defineSecret("STRIPE_API_KEY");
const openaiKey = defineSecret("OPENAI_API_KEY");

export const createCharge = onRequest(
  { secrets: [stripeApiKey, openaiKey] },
  async (req, res) => {
    // Secrets are available via .value() at runtime
    const stripe = require("stripe")(stripeApiKey.value());
    const charge = await stripe.charges.create({
      amount: 1000,
      currency: "usd",
      source: req.body.token,
    });

    res.json({ chargeId: charge.id });
  }
);
```

**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.

```
# Step 1: Export existing config to .env format
firebase functions:config:export
# This creates a .env file with your existing config values

# Step 2: Replace in code
# BEFORE (deprecated):
# const apiKey = functions.config().stripe.key;

# AFTER (v2 — choose one approach):
# Option A: process.env
# const apiKey = process.env.STRIPE_KEY;

# Option B: defineSecret (recommended for secrets)
# const apiKey = defineSecret("STRIPE_KEY");
# 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.

```
# functions/.env.local — emulator-only overrides
STRIPE_API_KEY=sk_test_fake_key_for_local_dev
OPENAI_API_KEY=sk-test-fake-key

# Start the emulator
firebase emulators:start --only functions

# 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 code example

File: `functions/src/index.ts`

```typescript
import * as admin from "firebase-admin";
import { defineString, defineInt, defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/v2/https";
import { onDocumentCreated } from "firebase-functions/v2/firestore";
import { logger } from "firebase-functions";

admin.initializeApp();

// Environment variables (from .env file)
const appName = defineString("APP_NAME", {
  description: "Application display name",
  default: "MyApp",
});

const maxRetries = defineInt("MAX_RETRIES", {
  description: "Max retry attempts",
  default: 3,
});

// Secrets (stored in Cloud Secret Manager)
const stripeKey = defineSecret("STRIPE_API_KEY");
const sendgridKey = defineSecret("SENDGRID_API_KEY");

// HTTP function using config and secrets
export const healthCheck = onRequest(
  { secrets: [stripeKey] },
  async (req, res) => {
    res.json({
      app: appName.value(),
      maxRetries: maxRetries.value(),
      stripeConfigured: !!stripeKey.value(),
    });
  }
);

// Firestore trigger using secrets
export const onOrderCreated = onDocumentCreated(
  {
    document: "orders/{orderId}",
    secrets: [sendgridKey],
  },
  async (event) => {
    if (!event.data) return;
    const order = event.data.data();

    logger.info(`New order in ${appName.value()}: ${event.params.orderId}`);

    // Use sendgridKey.value() to send confirmation email
    logger.info("SendGrid configured:", !!sendgridKey.value());
  }
);
```

## Common mistakes

- **Putting API keys and passwords in .env files instead of using defineSecret()** — undefined Fix: 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.
- **Forgetting to list secrets in the function's options object** — undefined Fix: 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.
- **Still using the deprecated functions.config() API in new functions** — undefined Fix: 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

## 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.

---

Source: https://www.rapidevelopers.com/firebase-tutorial/how-to-access-firebase-config-variables-in-functions
© RapidDev — https://www.rapidevelopers.com/firebase-tutorial/how-to-access-firebase-config-variables-in-functions
