iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Web App Config

Firebase config: the firebaseConfig object, environment switches, Remote Config, and the public-vs-private distinction.

Firebase — config

EXAMPLE
// ===== The firebaseConfig object =====
// You get this from the console (Project Settings -> Your apps).
const firebaseConfig = {
  apiKey: 'AIzaSy...',
  authDomain: 'my-project.firebaseapp.com',
  projectId: 'my-project',
  storageBucket: 'my-project.appspot.com',
  messagingSenderId: '1234567890',
  appId: '1:1234567890:web:abc',
};

// IMPORTANT: this is NOT a secret.
// It identifies your project to Firebase.
// Security lives in your Security Rules + App Check, not in hiding apiKey.

// ===== Environment switching =====
// Use env vars at build time:
const config = {
  dev:  { projectId: 'my-project-dev',  ... },
  prod: { projectId: 'my-project',      ... },
};
const cfg = config[process.env.NODE_ENV ?? 'dev'];

// Or per-bundle .env files:
// .env.development -> VITE_FB_PROJECT_ID=my-project-dev
// .env.production  -> VITE_FB_PROJECT_ID=my-project

// In code:
const cfg = {
  apiKey: import.meta.env.VITE_FB_API_KEY,
  projectId: import.meta.env.VITE_FB_PROJECT_ID,
  ...
};

// ===== Initialise once =====
import { initializeApp, getApps } from 'firebase/app';
const app = getApps()[0] ?? initializeApp(cfg);

// Hot-reload friendly: getApps() avoids re-init errors.

// ===== Remote Config (server-driven config) =====
import { getRemoteConfig, fetchAndActivate, getValue } from 'firebase/remote-config';
const rc = getRemoteConfig(app);
rc.settings.minimumFetchIntervalMillis = 3600 * 1000;
rc.defaultConfig = { showBanner: false, primaryColor: '#2563eb' };

await fetchAndActivate(rc);
const show = getValue(rc, 'showBanner').asBoolean();

// Use cases:
// - Feature flags
// - A/B test variants
// - UI copy / colours
// - Per-tier rate limits

// ===== App Check =====
import { initializeAppCheck, ReCaptchaV3Provider } from 'firebase/app-check';
initializeAppCheck(app, {
  provider: new ReCaptchaV3Provider('reCAPTCHA-site-key'),
  isTokenAutoRefreshEnabled: true,
});

// App Check blocks requests from outside your origin / app.

// ===== Functions config (legacy) =====
// firebase functions:config:set stripe.key="sk_..."
// Then in code:
//   const key = functions.config().stripe.key;
// Migrating: use environment variables and .env files for new code.

// ===== Local vs cloud =====
import { connectFirestoreEmulator } from 'firebase/firestore';
import { connectAuthEmulator } from 'firebase/auth';
if (location.hostname === 'localhost' && import.meta.env.VITE_USE_EMU) {
  connectAuthEmulator(auth, 'http://localhost:9099');
  connectFirestoreEmulator(db, 'localhost', 8080);
}

// ===== Patterns to internalise =====
// - firebaseConfig is public; do not hide it as a secret
// - Per-environment configs via env vars at build time
// - Remote Config for runtime feature flags / experiments
// - App Check + locked Security Rules > guarding the apiKey

// ===== Pitfalls =====
// - Treating firebaseConfig as a secret (it is not)
// - Mixing dev + prod projects via the same app
// - Storing real secrets (Stripe keys, JWT secrets) in client config
// - Skipping App Check on a public product -> bot traffic + cost

Why it matters

firebaseConfig is public; security lives in rules + App Check, not in hiding the apiKey. Use env vars to switch between dev / prod projects, Remote Config for runtime flags, App Check to keep bots out. Once these are reflex, the config side of Firebase is solved.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// firebaseConfig.js
export const firebaseConfig = {
    apiKey: 'AIza…',
    authDomain: 'myapp.firebaseapp.com',
    projectId: 'myapp',
    storageBucket: 'myapp.appspot.com',
    appId: '1:…'
};
Try it Yourself »

Discussion

Loading…