Skip to main content
RapidDev - Software Development Agency
firebase-tutorial

How to Add Firebase to an Existing Web Project

To add Firebase to an existing web project, create a Firebase project in the Console, register a web app to get your config object, install the firebase npm package, and call initializeApp() with your config. Store config values in environment variables for security. The modular v9+ SDK uses tree-shakeable imports like getFirestore and getAuth, keeping your bundle size small. Works with React, Next.js, Vue, and any JavaScript framework.

What you'll learn

  • How to create a Firebase project and register a web app in the Console
  • How to install the Firebase SDK and initialize it with your project config
  • How to use the modular v9+ import syntax for tree-shaking
  • How to securely store Firebase config using environment variables
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner7 min read10-15 minFirebase (all plans), firebase 10.x+, any JavaScript/TypeScript frameworkMarch 2026RapidDev Engineering Team
TL;DR

To add Firebase to an existing web project, create a Firebase project in the Console, register a web app to get your config object, install the firebase npm package, and call initializeApp() with your config. Store config values in environment variables for security. The modular v9+ SDK uses tree-shakeable imports like getFirestore and getAuth, keeping your bundle size small. Works with React, Next.js, Vue, and any JavaScript framework.

Adding Firebase to an Existing Web Project with the Modular SDK

This tutorial walks you through connecting Firebase to an existing JavaScript or TypeScript project. You will create a Firebase project, register a web app, install the SDK, and write a reusable initialization module using the modular v9+ syntax. The guide covers environment variable setup for security and shows how to import individual Firebase services like Firestore, Auth, and Storage.

Prerequisites

  • A Google account to access the Firebase Console
  • An existing web project with npm/yarn initialized (package.json exists)
  • Node.js 18 or later installed
  • A code editor like VS Code or Cursor

Step-by-step guide

1

Create a Firebase project in the Console

Go to console.firebase.google.com and click Add project. Enter a project name, optionally enable Google Analytics, and click Create project. This takes about 30 seconds. Once created, you land on the project dashboard where you can add apps and enable services.

Expected result: A new Firebase project is created and visible in your Firebase Console dashboard.

2

Register a web app and copy the config

From the project dashboard, click the web icon (</>) to add a web app. Give it a nickname (e.g., your project name). You do not need to enable Firebase Hosting at this step. After registering, Firebase displays your config object containing apiKey, authDomain, projectId, and other values. Copy this entire config object.

typescript
1// Firebase displays this config object after registering your app:
2const firebaseConfig = {
3 apiKey: "AIzaSy...",
4 authDomain: "your-project.firebaseapp.com",
5 projectId: "your-project-id",
6 storageBucket: "your-project.appspot.com",
7 messagingSenderId: "123456789",
8 appId: "1:123456789:web:abc123",
9};

Expected result: You have a firebaseConfig object with your project's specific values.

3

Install the Firebase SDK

In your project root, install the firebase npm package. This single package includes all Firebase client services: Firestore, Auth, Storage, Analytics, and more. You import only what you need thanks to the modular v9+ architecture.

typescript
1npm install firebase
2
3# Or with yarn:
4yarn add firebase

Expected result: The firebase package appears in your package.json dependencies.

4

Create a Firebase initialization module

Create a file (e.g., src/lib/firebase.ts) that initializes Firebase and exports the service instances you need. Use the modular v9+ import syntax which enables tree-shaking — your bundler only includes the Firebase code you actually use. Initialize each service once and export it for use throughout your app.

typescript
1// src/lib/firebase.ts
2import { initializeApp } from "firebase/app";
3import { getFirestore } from "firebase/firestore";
4import { getAuth } from "firebase/auth";
5import { getStorage } from "firebase/storage";
6
7const firebaseConfig = {
8 apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
9 authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
10 projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
11 storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
12 messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
13 appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
14};
15
16const app = initializeApp(firebaseConfig);
17
18export const db = getFirestore(app);
19export const auth = getAuth(app);
20export const storage = getStorage(app);

Expected result: A firebase.ts module exports initialized db, auth, and storage instances ready for import anywhere in your app.

5

Set up environment variables

Store your Firebase config values in environment variables instead of hardcoding them. Create a .env.local file in your project root for local development. For production, set the same variables in your hosting platform's environment settings (Vercel, Netlify, etc.).

typescript
1# .env.local (Next.js)
2NEXT_PUBLIC_FIREBASE_API_KEY=AIzaSy...
3NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
4NEXT_PUBLIC_FIREBASE_PROJECT_ID=your-project-id
5NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
6NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=123456789
7NEXT_PUBLIC_FIREBASE_APP_ID=1:123456789:web:abc123
8
9# For Vite projects, use VITE_ prefix:
10# VITE_FIREBASE_API_KEY=AIzaSy...

Expected result: Environment variables are loaded at build time and your Firebase config uses them instead of hardcoded values.

6

Use Firebase services in your app

Import the exported service instances from your firebase.ts module and use them throughout your application. Each Firebase service has its own modular functions that you import separately. This keeps imports clean and bundle sizes small.

typescript
1// Example: Read a document from Firestore
2import { db } from "@/lib/firebase";
3import { doc, getDoc } from "firebase/firestore";
4
5async function getUser(userId: string) {
6 const userDoc = await getDoc(doc(db, "users", userId));
7 if (userDoc.exists()) {
8 return { id: userDoc.id, ...userDoc.data() };
9 }
10 return null;
11}
12
13// Example: Check auth state
14import { auth } from "@/lib/firebase";
15import { onAuthStateChanged } from "firebase/auth";
16
17onAuthStateChanged(auth, (user) => {
18 if (user) {
19 console.log("Signed in:", user.uid);
20 } else {
21 console.log("Not signed in");
22 }
23});

Expected result: Your app can read from Firestore and check auth state using the initialized Firebase services.

Complete working example

src/lib/firebase.ts
1// Firebase initialization module
2// Import this file anywhere you need Firebase services
3import { initializeApp, getApps } from "firebase/app";
4import { getFirestore } from "firebase/firestore";
5import { getAuth } from "firebase/auth";
6import { getStorage } from "firebase/storage";
7import { getAnalytics, isSupported } from "firebase/analytics";
8
9const firebaseConfig = {
10 apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
11 authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
12 projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
13 storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
14 messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
15 appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
16};
17
18// Prevent re-initialization in development (hot reload)
19const app =
20 getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
21
22// Core services
23export const db = getFirestore(app);
24export const auth = getAuth(app);
25export const storage = getStorage(app);
26
27// Analytics — only in browser, not during SSR
28export const analytics = async () => {
29 if (typeof window !== "undefined" && (await isSupported())) {
30 return getAnalytics(app);
31 }
32 return null;
33};
34
35export default app;

Common mistakes when adding Firebase to an Existing Web Project

Why it's a problem: Calling initializeApp() multiple times due to hot module replacement in development

How to avoid: Check getApps().length before initializing: const app = getApps().length === 0 ? initializeApp(config) : getApps()[0]. This prevents the 'Firebase App already exists' error.

Why it's a problem: Using the compat (v8) import syntax instead of modular v9+ imports

How to avoid: Import from 'firebase/firestore' not 'firebase/compat/firestore'. The compat layer is larger and does not support tree-shaking, resulting in much bigger bundle sizes.

Why it's a problem: Hardcoding Firebase config values directly in source code committed to public repositories

How to avoid: Use environment variables (.env.local) for config values and add .env.local to .gitignore. While the apiKey is safe to expose, keeping config in env vars is a best practice for managing multiple environments.

Why it's a problem: Trying to use getAnalytics() during server-side rendering, causing 'window is not defined' errors

How to avoid: Guard Analytics initialization with typeof window !== 'undefined' and await isSupported() before calling getAnalytics(). Analytics only works in the browser.

Best practices

  • Use the modular v9+ import syntax (import { getFirestore } from 'firebase/firestore') for tree-shaking and smaller bundles
  • Create a single firebase.ts initialization module and import services from it throughout your app
  • Store all Firebase config values in environment variables, even though the apiKey is safe to expose publicly
  • Guard against re-initialization with getApps().length check to handle hot module replacement in development
  • Initialize Analytics only in the browser with isSupported() to avoid SSR errors in Next.js or Nuxt
  • Enable only the Firebase services you actually need to keep dependencies minimal

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

Show me how to add Firebase to an existing Next.js TypeScript project using the modular v9+ SDK. I need Firestore, Auth, and Storage initialized in a single module with environment variables for the config values. Include the getApps() guard for hot reload.

Firebase Prompt

Add Firebase to my existing project. Install the firebase npm package, create src/lib/firebase.ts with initializeApp using environment variables, and export getFirestore, getAuth, and getStorage instances. Use modular v9+ imports and guard against re-initialization with getApps().

Frequently asked questions

Is the Firebase apiKey safe to expose in client-side code?

Yes. The apiKey only identifies your Firebase project. It does not grant access to data. Access control is enforced by Firestore Security Rules, Auth rules, and Storage rules. Treat it like a project ID, not a password.

Can I use Firebase with both React and Next.js?

Yes. The Firebase SDK works with any JavaScript framework. The only difference is the environment variable prefix: NEXT_PUBLIC_ for Next.js, VITE_ for Vite/Lovable, and REACT_APP_ for Create React App.

Do I need the Blaze plan to use Firebase in my project?

Not for basic features. Firestore, Auth (email/social), Hosting, and Analytics work on the free Spark plan. You need Blaze for Cloud Functions, phone authentication, and multiple Realtime Database instances.

How do I avoid the 'Firebase App already exists' error?

Check if Firebase is already initialized before calling initializeApp: const app = getApps().length === 0 ? initializeApp(config) : getApps()[0]. This handles hot module replacement in development.

What is the difference between the modular v9+ SDK and the compat SDK?

The modular SDK uses individual function imports (getFirestore, doc, getDoc) that enable tree-shaking, reducing bundle size by up to 80%. The compat SDK uses the older firebase.firestore() syntax and includes all code regardless of what you use.

Can I add Firebase to a project that already uses Supabase?

Yes. Firebase and Supabase can coexist in the same project. A common pattern is using Firebase for Auth and Analytics while using Supabase for the database, or vice versa.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.