Environment variables and secrets
Your functions read their settings from .env files, secrets from
.secret.local, and the emulators’ addresses from variables Firenook sets.
This page lists what Firenook reads, in which order, and what your code
sees.
The .env files
Section titled “The .env files”Put the files in your codebase’s folder, next to its package.json:
SHOP_NAME=Demo ShopSUPPORT_EMAIL=help@example.comFirenook reads these files, as the official CLI does. A later file wins over an earlier one for the same key:
| File | What it is for |
|---|---|
.env |
Values for every project |
.env.<project id>, such as .env.demo-shop |
Values for one project, by its id |
.env.<alias>, such as .env.staging |
Values for one project, by its .firebaserc alias |
.env.local |
Values for the emulators only, never deployed |
The start says which files it loaded:
firenook functions: Loaded environment variables from .env, .env.demo-shop, .env.local.When firebase.json gives the codebase a configDir, the .env files are
read from that folder instead.
The project id or its alias
Section titled “The project id or its alias”Which of .env.<project id> and .env.<alias> is read depends on how the
project was chosen. With this .firebaserc:
{ "projects": { "default": "demo-shop", "staging": "demo-shop-staging" }}| You start with | Files read |
|---|---|
--project staging, an alias |
.env, .env.staging, .env.local |
No --project, after firebase use staging in this folder |
.env, .env.staging, .env.local |
--project demo-shop, a project id |
.env, .env.demo-shop, .env.local |
No --project, so the default alias |
.env, .env.demo-shop or .env.default, .env.local |
A project named by its id has no alias. Having both files for one project,
its id’s and its alias’s, stops the codebase loading, as on the official
emulator. Here with .env.demo-shop-staging and .env.staging and
--project staging:
firenook functions: Failed to load function definition from source: FirebaseError: Can't have both dotenv files with projectId (env.demo-shop-staging) and projectAlias (.env.staging) as extensions.Keep one of the two. Without --project, .env.<project id> and
.env.default count as such a pair.
The files use the same dialect as the official CLI: KEY=value lines, an
optional export in front, # comments, double quotes with \n escapes
that can span lines, and single quotes kept as written. A key starts with an
uppercase letter or an underscore and holds only uppercase letters, digits
and underscores. Keys that start with X_GOOGLE_, FIREBASE_ or EXT_, and
names the runtime uses, such as PORT, K_SERVICE and GCLOUD_PROJECT, are
refused, and the codebase does not load:
firenook functions: Failed to load function definition from source: FirebaseError: Failed to load environment variables from .env.Validation failedFailed to validate key FIREBASE_REGION: Key FIREBASE_REGION starts with a reserved prefix (X_GOOGLE_ FIREBASE_ EXT_)When you change a file
Section titled “When you change a file”Firenook watches the .env files and .secret.local, but a change does not
reload your functions, as in the official CLI. Your functions keep the old
values until the next reload. Press r in the terminal to reload, or use
Reload in the console. Until you do, the codebase’s page in the console
names the file that changed after the last load.
Secrets
Section titled “Secrets”Declare a secret with defineSecret and bind it to the functions that use
it:
const {onRequest} = require("firebase-functions/https");const {defineSecret} = require("firebase-functions/params");
const stripeKey = defineSecret("STRIPE_KEY");
exports.checkout = onRequest({secrets: [stripeKey]}, (request, response) => { // stripeKey.value() is the value from .secret.local});Give it a value in .secret.local, in the codebase’s source folder (never
in configDir):
STRIPE_KEY=sk_test_123Firenook never contacts Secret Manager. The official emulator tries your
production secrets first when .secret.local lacks one; Firenook leaves a
missing secret empty, and the SDK logs a warning when your code reads it:
No value found for secret parameter "STRIPE_KEY". A function can only access a secret if you include the secret in the function's dependency array.firenook init writes a functions/.gitignore with *.local, which keeps
.env.local and .secret.local out of Git.
Params
Section titled “Params”Params declared with defineString, defineInt, defineBoolean,
defineList and the like take their values from the same .env files. Call
.value() in your function to read one:
const {onRequest} = require("firebase-functions/https");const {defineString, defineInt} = require("firebase-functions/params");
const greeting = defineString("GREETING", {default: "hello"});const pageSize = defineInt("PAGE_SIZE", {default: 20});
exports.settings = onRequest((req, res) => { res.json({shop: process.env.SHOP_NAME, greeting: greeting.value(), pageSize: pageSize.value()});});Firenook never asks for a value. It resolves params as the official emulator does when no terminal is attached:
-
A value in an
.envfile wins. -
Otherwise the param takes its
default, in.value()and in a function’s options, such asregion,memoryortimeoutSeconds. The start names the params that took theirs:firenook functions: Params no env file sets take their default: GREETING, PAGE_SIZE.and the function answers with them:
Terminal window $ curl http://127.0.0.1:5001/demo-shop/us-central1/settings{"shop":"Demo Shop","greeting":"hello","pageSize":20} -
A param with no value and no default stops its codebase loading, with the official question and where to put the answer. Here
defineString("API_URL")has neither:firenook functions: Failed to load function definition from source: FirebaseError: Question "Enter a string value for API_URL:" does not have a default and cannot be answered in non-interactive mode. Firenook never prompts: set the value in .env, .env.demo-shop or .env.local, or give the param a default.When it is the only codebase, the start stops there.
Two differences are deliberate. The official emulator writes the answers it
took, defaults included, to .env.local; Firenook writes nothing and takes
the default again at every load, so a changed default applies on the next
reload. And a list param reaches your code as the JSON array the SDK’s
.value() parses, as a deployed function gets it.
The console’s Environment tab, on a function’s page, lists every param with
the file its value came from, marks the ones that took their default, and
can write a value to .env.local for you. It also lists the secrets a
function declares and can add a missing one to .secret.local.
Code that reads process.env while it loads, outside a function, sees the
.env values too, as on the official emulator: a region taken from
process.env.SHOP_REGION is the same at load and in the function. Defaults
and secrets are not there yet; the function has them.
PROJECT_ID, GCLOUD_PROJECT, STORAGE_BUCKET and DATABASE_URL are built
in: options that use them get the project’s values.
What your functions see
Section titled “What your functions see”Firenook starts one Node worker per codebase. Its environment is yours, with
your .env values over it and the emulator’s own variables over both.
FIREBASE_TOKEN is removed, and GOOGLE_APPLICATION_CREDENTIALS and
CLOUDSDK_CONFIG point at demo credentials in the run’s folder, so your code
never holds your Google credentials, and a token it asks for comes from the
emulators. A GOOGLE_APPLICATION_CREDENTIALS your own .env sets is kept,
and requests made with it go to Google.
These are the variables Firenook sets, with the values a project on the default ports gets:
| Variable | Value |
|---|---|
FUNCTIONS_EMULATOR |
true |
FIRESTORE_EMULATOR_HOST |
127.0.0.1:8080 |
FIREBASE_AUTH_EMULATOR_HOST |
127.0.0.1:9099 |
FIREBASE_STORAGE_EMULATOR_HOST |
127.0.0.1:9199 |
STORAGE_EMULATOR_HOST |
http://127.0.0.1:9199 |
PUBSUB_EMULATOR_HOST |
127.0.0.1:8085 |
CLOUD_TASKS_EMULATOR_HOST |
127.0.0.1:9499 |
CLOUD_EVENTARC_EMULATOR_HOST |
http://127.0.0.1:9299 |
FIREBASE_EMULATOR_HUB |
127.0.0.1:4400 |
GCLOUD_PROJECT |
your project id, such as demo-shop |
FIREBASE_CONFIG |
{"storageBucket":"demo-shop.appspot.com","databaseURL":"https://demo-shop.firebaseio.com","projectId":"demo-shop"} |
TZ |
UTC |
K_SERVICE, FUNCTION_TARGET |
the name of the function being called |
The Admin SDK reads the *_EMULATOR_HOST variables, so
initializeApp() with no arguments talks to the emulators. The ports follow
your firebase.json.
Change a value and see it in a call: debugging and reload on save covers reloads, the debugger and the logs.