Books/Firebase Essentials/Connecting Firebase to Your App

    Connecting Firebase to Your App

    Connecting Firebase to Your App

    You have a Firebase project and understand Firestore. Now let's wire it all up — connecting your frontend and backend code to Firebase so they can read and write data.

    Frontend Setup (React + TypeScript)

    Step 1: Install the Firebase SDK

    npm install firebase

    Step 2: Set Up Environment Variables

    Never hardcode your Firebase config. Use environment variables instead.

    Create a .env file in your project root (or .env.local for Vite/Next.js):

    # For Vite projects (variables must start with VITE_)
    VITE_FIREBASE_API_KEY=AIzaSyD...
    VITE_FIREBASE_AUTH_DOMAIN=my-app.firebaseapp.com
    VITE_FIREBASE_PROJECT_ID=my-app
    VITE_FIREBASE_STORAGE_BUCKET=my-app.firebasestorage.app
    VITE_FIREBASE_MESSAGING_SENDER_ID=123456789
    VITE_FIREBASE_APP_ID=1:123456789:web:abc123
    # For Next.js projects (variables must start with NEXT_PUBLIC_)
    NEXT_PUBLIC_FIREBASE_API_KEY=AIzaSyD...
    NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=my-app.firebaseapp.com
    # ... same pattern

    Important: Add .env to your .gitignore so secrets aren't committed to Git!

    Also create a .env.example file (without real values) so others know what variables are needed:

    VITE_FIREBASE_API_KEY=your-api-key-here
    VITE_FIREBASE_AUTH_DOMAIN=your-app.firebaseapp.com
    VITE_FIREBASE_PROJECT_ID=your-project-id
    VITE_FIREBASE_STORAGE_BUCKET=your-app.firebasestorage.app
    VITE_FIREBASE_MESSAGING_SENDER_ID=your-sender-id
    VITE_FIREBASE_APP_ID=your-app-id

    What to ask your AI: "Set up environment variables for Firebase in my [Vite/Next.js/Create React App] project. Include a .env.example file."

    Step 3: Create the Firebase Config File

    Create src/lib/firebase.ts (or src/config/firebase.ts):

    import { initializeApp } from "firebase/app";
    import { getAuth, GoogleAuthProvider } from "firebase/auth";
    import { getFirestore } from "firebase/firestore";
    import { getStorage } from "firebase/storage";
    
    const firebaseConfig = {
      apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
      authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
      projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
      storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
      messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
      appId: import.meta.env.VITE_FIREBASE_APP_ID,
    };
    
    // Initialize Firebase
    const app = initializeApp(firebaseConfig);
    
    // Export the services you need
    export const auth = getAuth(app);
    export const googleProvider = new GoogleAuthProvider();
    export const db = getFirestore(app);
    export const storage = getStorage(app);

    For Next.js, replace import.meta.env.VITE_ with process.env.NEXT_PUBLIC_.

    This file is the single source of truth for Firebase in your app. Every other file imports from here.

    Step 4: Create Service Files

    Organize your Firestore operations in service files:

    // src/services/userService.ts
    import { db } from "@/lib/firebase";
    import {
      collection, doc, getDocs, getDoc, addDoc,
      updateDoc, deleteDoc, query, where, orderBy, Timestamp
    } from "firebase/firestore";
    
    // Define the interface
    interface User {
      id: string;
      name: string;
      email: string;
      role: string;
      createdAt: Timestamp;
      updatedAt: Timestamp;
    }
    
    type UserInput = Omit<User, "id" | "createdAt" | "updatedAt">;
    
    const COLLECTION = "users";
    
    // Get all users
    export async function getUsers(): Promise<User[]> {
      const snapshot = await getDocs(
        query(collection(db, COLLECTION), orderBy("createdAt", "desc"))
      );
      return snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() } as User));
    }
    
    // Get user by ID
    export async function getUserById(id: string): Promise<User | null> {
      const docSnap = await getDoc(doc(db, COLLECTION, id));
      if (!docSnap.exists()) return null;
      return { id: docSnap.id, ...docSnap.data() } as User;
    }
    
    // Create user
    export async function createUser(data: UserInput): Promise<string> {
      const docRef = await addDoc(collection(db, COLLECTION), {
        ...data,
        createdAt: Timestamp.now(),
        updatedAt: Timestamp.now(),
      });
      return docRef.id;
    }
    
    // Update user
    export async function updateUser(id: string, data: Partial<UserInput>): Promise<void> {
      await updateDoc(doc(db, COLLECTION, id), {
        ...data,
        updatedAt: Timestamp.now(),
      });
    }
    
    // Delete user
    export async function deleteUser(id: string): Promise<void> {
      await deleteDoc(doc(db, COLLECTION, id));
    }

    What to ask your AI: "Create a Firestore service file for my [collection] with full CRUD operations, TypeScript types, and proper timestamps."

    Step 5: Use in React Components

    import { useEffect, useState } from "react";
    import { getUsers } from "@/services/userService";
    import type { User } from "@/services/userService";
    
    const UserList = () => {
      const [users, setUsers] = useState<User[]>([]);
      const [loading, setLoading] = useState(true);
    
      useEffect(() => {
        const fetchUsers = async () => {
          const data = await getUsers();
          setUsers(data);
          setLoading(false);
        };
        fetchUsers();
      }, []);
    
      if (loading) return <p>Loading...</p>;
    
      return (
        <ul>
          {users.map(user => (
            <li key={user.id}>{user.name}{user.email}</li>
          ))}
        </ul>
      );
    };

    Backend Setup (Node.js + Firebase Admin)

    For server-side code (scripts, APIs, Cloud Functions), you use firebase-admin instead of firebase.

    Step 1: Install Firebase Admin

    npm install firebase-admin

    Step 2: Initialize with Credentials

    Option A: Application Default Credentials (simplest for local development)

    If you're logged in via firebase login or gcloud auth application-default login:

    import { initializeApp, applicationDefault } from "firebase-admin/app";
    import { getFirestore } from "firebase-admin/firestore";
    
    initializeApp({
      credential: applicationDefault(),
      projectId: "your-project-id",
    });
    
    const db = getFirestore();

    Option B: Service Account Key (for production servers)

    1. In Firebase Console → Project Settings → Service Accounts → Generate New Private Key
    2. Save the JSON file securely (never commit it to Git!)
    import { initializeApp, cert } from "firebase-admin/app";
    import { getFirestore } from "firebase-admin/firestore";
    
    initializeApp({
      credential: cert("./service-account-key.json"),
    });
    
    const db = getFirestore();

    Step 3: Use Firestore from the Backend

    The Admin SDK syntax is slightly different from the client SDK:

    import { getFirestore, Timestamp } from "firebase-admin/firestore";
    
    const db = getFirestore();
    
    // Create
    await db.collection("users").add({
      name: "Alice",
      email: "alice@example.com",
      createdAt: Timestamp.now(),
    });
    
    // Read
    const snapshot = await db.collection("users").get();
    snapshot.forEach(doc => {
      console.log(doc.id, doc.data());
    });
    
    // Query
    const admins = await db.collection("users")
      .where("role", "==", "admin")
      .orderBy("createdAt")
      .get();
    
    // Update
    await db.collection("users").doc("alice123").update({
      role: "admin",
      updatedAt: Timestamp.now(),
    });
    
    // Delete
    await db.collection("users").doc("alice123").delete();

    Client SDK vs Admin SDK

    Client (firebase)Admin (firebase-admin)
    Runs inBrowserServer (Node.js)
    AuthUser's permissionsFull access (bypasses rules)
    SyntaxaddDoc(collection(db, "users"), data)db.collection("users").add(data)
    Importfrom "firebase/firestore"from "firebase-admin/firestore"
    Use forReact apps, frontendsScripts, APIs, Cloud Functions

    What to ask your AI: "I need to write a Node.js script that reads data from Firestore and generates a report. Use firebase-admin."

    Common Patterns

    Authentication Context (React)

    // src/contexts/AuthContext.tsx
    import { createContext, useContext, useEffect, useState } from "react";
    import { User, onAuthStateChanged } from "firebase/auth";
    import { auth } from "@/lib/firebase";
    
    interface AuthContextType {
      user: User | null;
      loading: boolean;
    }
    
    const AuthContext = createContext<AuthContextType>({ user: null, loading: true });
    
    export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
      const [user, setUser] = useState<User | null>(null);
      const [loading, setLoading] = useState(true);
    
      useEffect(() => {
        const unsubscribe = onAuthStateChanged(auth, (user) => {
          setUser(user);
          setLoading(false);
        });
        return unsubscribe;
      }, []);
    
      return (
        <AuthContext.Provider value={{ user, loading }}>
          {children}
        </AuthContext.Provider>
      );
    };
    
    export const useAuth = () => useContext(AuthContext);

    Protected Routes

    const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
      const { user, loading } = useAuth();
    
      if (loading) return <p>Loading...</p>;
      if (!user) return <Navigate to="/login" />;
    
      return children;
    };

    What to ask your AI: "Set up Firebase Authentication in my React app with Google sign-in, auth context, and protected routes."

    Project Structure

    A well-organized Firebase project typically looks like:

    src/
    ├── lib/
    │   └── firebase.ts          # Firebase initialization
    ├── services/
    │   ├── userService.ts        # User CRUD operations
    │   ├── postService.ts        # Post CRUD operations
    │   └── storageService.ts     # File upload operations
    ├── contexts/
    │   └── AuthContext.tsx        # Auth state management
    ├── components/
    │   └── ...
    ├── pages/
    │   └── ...
    └── types/
        └── index.ts              # Shared TypeScript interfaces
    

    What's Next?

    Your app is connected to Firebase! Next, we'll learn how to deploy your app to the internet with Firebase Hosting.

    What to ask your AI: "Review my Firebase setup and project structure. Is there anything I should improve for production readiness?"


    🌐 www.genai-mentor.ai