Firebase Multi Project Architecture

Large applications often need more than one Firebase project. A multi-project architecture separates environments — development, staging, and production — or splits a platform into isolated services. Keeping projects separate protects live user data from test activity and lets teams work independently without interfering with each other.

Why Multiple Projects Make Sense

Think of a hospital. The emergency room, the pharmacy, and the administrative office all serve the same institution but run as separate departments with separate records, separate access rules, and separate staff. Mixing them would create chaos. Multi-project Firebase architecture applies the same thinking to your app.

Single project (risky):
Dev team runs tests ---> deletes real user data
Load test           ---> spikes production costs
Broken migration    ---> corrupts live database

Multi-project (safe):
my-app-dev     ---> developers test freely here
my-app-staging ---> QA and client review here
my-app-prod    ---> real users, real data, protected

Standard Three-Environment Setup

Project: my-app-dev
  Purpose: Local development and experimentation
  Users: Fake test accounts
  Data: Sample seed data, reset regularly
  Security Rules: Loose (allow read/write for easy testing)
  Billing: Spark (free) plan usually sufficient

Project: my-app-staging
  Purpose: QA testing before each release
  Users: Realistic test accounts
  Data: Copy of production structure with anonymized data
  Security Rules: Match production exactly
  Billing: Blaze plan (mirrors production costs)

Project: my-app-prod
  Purpose: Live users
  Users: Real accounts
  Data: Real user data
  Security Rules: Locked down, audited
  Billing: Blaze plan

Managing Multiple Projects with the Firebase CLI

The Firebase CLI stores project aliases in .firebaserc:

// .firebaserc
{
  "projects": {
    "default": "my-app-dev",
    "staging": "my-app-staging",
    "production": "my-app-prod"
  }
}

Switch between projects during deployment:

# Deploy to development (default)
firebase deploy

# Deploy to staging
firebase deploy --project staging

# Deploy to production
firebase deploy --project production

Managing Configuration per Environment

Each project has its own Firebase config object. Use environment variables to select the right config at build time:

// config/firebase.dev.js
export const firebaseConfig = {
  apiKey: "dev-api-key",
  projectId: "my-app-dev",
  // ...
};

// config/firebase.prod.js
export const firebaseConfig = {
  apiKey: "prod-api-key",
  projectId: "my-app-prod",
  // ...
};
// .env.development
VITE_FIREBASE_PROJECT_ID=my-app-dev
VITE_FIREBASE_API_KEY=dev-key

// .env.production
VITE_FIREBASE_PROJECT_ID=my-app-prod
VITE_FIREBASE_API_KEY=prod-key
// firebase.js — reads from env variables
const firebaseConfig = {
  apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
  projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
  // ...
};

Your build tool (Vite, Create React App, Next.js) loads the correct .env file based on the build mode. Never commit .env.production to version control — use CI/CD secret management instead.

Multi-Project for Large Platforms

Beyond environments, some platforms use separate Firebase projects for different product lines:

Company: StudyPlatform Inc.

Project: studyplatform-students  ---> student-facing app
Project: studyplatform-teachers  ---> teacher dashboard
Project: studyplatform-admin     ---> internal admin tools

Separation ensures that a bug in the teacher dashboard cannot affect student data. Each project has its own database, its own security rules, and its own billing account — giving precise cost attribution per product.

Sharing Data Across Projects

Firebase does not natively share data between projects. To share data, use the Admin SDK on a server or Cloud Function that has access to both projects:

const admin = require("firebase-admin");

// Initialize two projects
const devApp = admin.initializeApp({
  credential: admin.credential.cert(devServiceAccount),
  projectId: "my-app-dev"
}, "dev");

const prodApp = admin.initializeApp({
  credential: admin.credential.cert(prodServiceAccount),
  projectId: "my-app-prod"
}, "prod");

const devDb = admin.firestore(devApp);
const prodDb = admin.firestore(prodApp);

// Copy data from dev to prod
async function migrateData() {
  const snapshot = await devDb.collection("products").get();
  const batch = prodDb.batch();
  snapshot.docs.forEach((doc) => {
    batch.set(prodDb.collection("products").doc(doc.id), doc.data());
  });
  await batch.commit();
  console.log("Migration complete.");
}

Firestore Security Rules Across Projects

Security rules are project-specific. Keep rules in your repository and deploy them separately to each project:

firebase deploy --only firestore:rules --project staging
firebase deploy --only firestore:rules --project production

Use the same rules file for staging and production. Differences between their rules can cause bugs that only appear in production — exactly the kind of surprise you want to avoid.

Key Takeaway

Multi-project architecture separates development, staging, and production environments into independent Firebase projects. Configure project aliases in .firebaserc and use environment variables to select the right Firebase config per build. Deploy to each project explicitly using the --project flag. Keep staging and production security rules identical, and migrate data between projects using the Admin SDK when necessary.

Leave a Comment

Your email address will not be published. Required fields are marked *