google

Firebase v11+: Environment-Safe Modular Setup

2026-02-18 google 1 min read

Tutor's Note: Instead of hardcoding Firebase credentials, we leverage environment variables. This allows secure separation between Dev, Staging, and Prod environments, while keeping your firebase.js modular and tree-shakable.

Firebase v11+ Modular Setup With Environment Variables

Using environment variables ensures your credentials are never exposed in source code, and makes swapping between multiple environments effortless. This approach is perfect for SvelteKit and modern bundlers like Vite.

1. Installing Firebase

Install Firebase in your project:

bash
						
npm install firebase
					

2. Setting Up Your Environment Variables

Create a .env file for each environment (dev, prod) and store your Firebase configuration there. Example:

bash
						
PUBLIC_FIREBASE_API_KEY=your-api-key
PUBLIC_FIREBASE_AUTH_DOMAIN=your-app-dev.firebaseapp.com
PUBLIC_FIREBASE_PROJECT_ID=your-app-dev
PUBLIC_FIREBASE_STORAGE_BUCKET=your-app-dev.appspot.com
PUBLIC_FIREBASE_MESSAGING_SENDER_ID=1234567890
PUBLIC_FIREBASE_APP_ID=1:1234567890:web:abcdef123456
PUBLIC_RECAPTCHA_SITE_KEY=your-recaptcha-key
					

3. The Modular firebase.js

Use this environment-safe Firebase setup:

javascript
						
import { initializeApp, getApps } from 'firebase/app';
import { initializeAppCheck, ReCaptchaV3Provider } from 'firebase/app-check';
import { getFirestore } from 'firebase/firestore';
import { browser } from '$app/environment';

import {
    PUBLIC_FIREBASE_API_KEY,
    PUBLIC_FIREBASE_AUTH_DOMAIN,
    PUBLIC_FIREBASE_PROJECT_ID,
    PUBLIC_FIREBASE_STORAGE_BUCKET,
    PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
    PUBLIC_FIREBASE_APP_ID,
    PUBLIC_RECAPTCHA_SITE_KEY
} from '$env/static/public';

const firebaseConfig = {
    apiKey: PUBLIC_FIREBASE_API_KEY,
    authDomain: PUBLIC_FIREBASE_AUTH_DOMAIN,
    projectId: PUBLIC_FIREBASE_PROJECT_ID,
    storageBucket: PUBLIC_FIREBASE_STORAGE_BUCKET,
    messagingSenderId: PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
    appId: PUBLIC_FIREBASE_APP_ID
};

// Initialize Firebase app
const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];

// Export Firestore
export const db = getFirestore(app);

// Initialize App Check (client-only)
export let appCheck;
if (browser) {
    if (location.hostname === 'localhost' || location.hostname === '127.0.0.1') {
        self.FIREBASE_APPCHECK_DEBUG_TOKEN = true;
    }

    appCheck = initializeAppCheck(app, {
        provider: new ReCaptchaV3Provider(PUBLIC_RECAPTCHA_SITE_KEY),
        isTokenAutoRefreshEnabled: true
    });
}
					

4. Benefits of This Approach

  • Security: Credentials never live in your repo.
  • Environment Flexibility: Easily switch between dev, staging, and prod.
  • Modular: Only imports Firebase features you need.
  • Tree-shakable: Smaller bundle size for modern front-end apps.

5. Using Firestore

After importing db, your real-time updates are modular:

javascript
						
import { collection, onSnapshot, query, orderBy } from 'firebase/firestore';
import { db } from './firebase.js';

const postsRef = collection(db, 'posts');
const q = query(postsRef, orderBy('createdAt', 'desc'));

onSnapshot(q, snapshot => {
    const posts = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
    renderBlogUI(posts);
});
					

6. Uploading Files Securely

Environment-safe Firebase Storage usage:

javascript
						
import { getStorage, ref, uploadBytes, getDownloadURL } from 'firebase/storage';
import { app } from './firebase.js';

const storage = getStorage(app);

async function uploadFile(file) {
    const storageRef = ref(storage, `uploads/${file.name}`);
    await uploadBytes(storageRef, file);
    return await getDownloadURL(storageRef);
}
					

7. Deploying with firebase.json

Your firebase.json remains environment-agnostic. Keys are never exposed, and you can still define CSP headers, rewrites, and redirects as usual.

Conclusion

By following this environment-variable approach, you make your Firebase integration secure, modular, and production-ready — all while keeping things easy for new developers to experiment locally.