# How to Integrate Bolt.new with Firebase

- Tool: Bolt.new
- Difficulty: Intermediate
- Time required: 30 minutes
- Last updated: April 2026

## TL;DR

Use Firebase as a full Backend-as-a-Service alternative to Supabase in Bolt.new by installing the firebase npm package and initializing Firestore, Auth, and Storage. The Firebase JS SDK communicates over HTTP and WebSocket — fully compatible with Bolt's WebContainer. Note: choosing Firebase means losing Bolt's native Stripe integration, which requires Supabase edge functions. Firestore real-time listeners work in the preview; OAuth login requires a deployed URL.

## Use Firebase as a Full Backend Alternative in Bolt.new

Firebase is the most popular alternative to Supabase for Bolt.new projects. Its JavaScript SDK communicates over HTTP and WebSocket — matching Bolt's WebContainer architecture perfectly, unlike raw TCP database drivers that fail in the browser-based runtime. Firestore's real-time document listeners even work in the preview environment, making live data development unusually smooth. Storage file uploads, authentication flows, and Cloud Functions calls all work through the same HTTP-based SDK.

The key trade-off to understand before choosing Firebase: Bolt.new's native Stripe payment integration is built around Supabase edge functions. If your project needs payments, choosing Firebase as your backend means you lose access to Bolt's one-click Stripe setup and must implement payments manually via Next.js API routes or your own Cloud Functions. If your project doesn't need payments, or you're comfortable with manual Stripe setup, Firebase is an excellent choice — particularly for teams already in the Google ecosystem or applications that benefit from Firebase's real-time database capabilities.

Firebase's document/collection data model differs from Supabase's relational PostgreSQL. It excels at hierarchically organized data (users → posts → comments), real-time collaboration features, and apps that need to work offline. It's less suited for complex relational queries, server-side aggregations, or applications where SQL's expressiveness matters. Bolt's AI understands both backends well — clearly stating 'Use Firebase' in your prompts keeps the AI generating Firebase SDK code rather than Supabase patterns.

## Before you start

- A Google account to access the Firebase Console at console.firebase.google.com
- A Firebase project created with Firestore, Authentication, and Storage enabled
- Your Firebase web app configuration object (from Project Settings → Your apps)
- A Bolt.new project (Vite or Next.js — both work with the Firebase JS SDK)
- Basic understanding of NoSQL document/collection data modeling

## Step-by-step guide

### 1. Create a Firebase Project and Get Configuration

Go to console.firebase.google.com and click 'Add project'. Name your project, optionally enable Google Analytics, and click 'Create project'. Once created, click the web app icon (`</>`) in the Project Overview to register a web app. Give it a nickname (e.g., 'Bolt App') and click 'Register app'. Firebase shows your configuration object — a JavaScript object with apiKey, authDomain, projectId, storageBucket, messagingSenderId, and appId. Copy the entire config object. Next, enable the services you need: in the left sidebar, click 'Firestore Database' → 'Create database' → select a region → choose 'Start in test mode' for development (you'll tighten security rules before production). Click 'Authentication' → 'Get started' → enable Email/Password and optionally Google sign-in. Click 'Storage' → 'Get started' → 'Start in test mode'. Test mode allows all reads and writes without authentication — fine for development, but set proper security rules before going live. Your Firebase config values are safe to include in client-side code (they're designed to be public) — the apiKey is a project identifier, not a secret. Security is enforced through Firestore Security Rules, not by keeping the config private.

```
// lib/firebase.ts
import { initializeApp, getApps } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
import { getAuth } from 'firebase/auth';
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,
};

// Prevent re-initialization on hot reload
const app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];

export const db = getFirestore(app);
export const auth = getAuth(app);
export const storage = getStorage(app);
export default app;
```

**Expected result:** Firebase is initialized. The db, auth, and storage exports are ready to use throughout your app.

### 2. Implement Firestore CRUD with Real-Time Listeners

Firestore's document database organizes data into collections and documents — conceptually similar to a folder (collection) containing files (documents), where each file has key-value fields. CRUD operations use `addDoc`, `setDoc`, `updateDoc`, `deleteDoc`, and `getDoc` from `firebase/firestore`. The standout feature for Bolt development is `onSnapshot` — a real-time listener that fires whenever data changes. Unlike polling, onSnapshot pushes updates from Firebase to your app instantly, and this works in Bolt's WebContainer preview environment. Each listener returns an unsubscribe function — call it in a React cleanup function to prevent memory leaks. Firestore queries support filtering (`where`), ordering (`orderBy`), and limiting (`limit`), but compound queries (filtering on multiple fields) require composite indexes created in the Firebase Console. If a query returns a 'requires index' error with a link, clicking that link auto-creates the index.

```
// hooks/useTasks.ts
import { useState, useEffect } from 'react';
import {
  collection,
  onSnapshot,
  addDoc,
  updateDoc,
  deleteDoc,
  doc,
  orderBy,
  query,
  serverTimestamp,
} from 'firebase/firestore';
import { db } from '@/lib/firebase';

export interface Task {
  id: string;
  title: string;
  description: string;
  status: 'todo' | 'in-progress' | 'done';
  createdAt: Date | null;
}

export function useTasks() {
  const [tasks, setTasks] = useState<Task[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const q = query(collection(db, 'tasks'), orderBy('createdAt', 'desc'));
    const unsubscribe = onSnapshot(q, (snapshot) => {
      const taskList = snapshot.docs.map((doc) => ({
        id: doc.id,
        ...doc.data(),
        createdAt: doc.data().createdAt?.toDate() ?? null,
      })) as Task[];
      setTasks(taskList);
      setLoading(false);
    });
    return () => unsubscribe();
  }, []);

  return { tasks, loading };
}

export async function addTask(title: string, description: string) {
  return addDoc(collection(db, 'tasks'), {
    title,
    description,
    status: 'todo',
    createdAt: serverTimestamp(),
  });
}

export async function updateTask(id: string, changes: Partial<Task>) {
  return updateDoc(doc(db, 'tasks', id), changes);
}

export async function deleteTask(id: string) {
  return deleteDoc(doc(db, 'tasks', id));
}
```

**Expected result:** The useTasks hook subscribes to Firestore changes in real time. Opening two browser tabs and adding a task in one immediately shows it in the other.

### 3. Add Firebase Authentication

Firebase Authentication handles user sign-up, login, and session management. The `onAuthStateChanged` listener from `firebase/auth` is the canonical way to track the current user across page refreshes — Firebase stores the session in IndexedDB and automatically restores it. Email/password authentication works fully in Bolt's WebContainer preview. Google Sign-In, GitHub, and other OAuth providers redirect to an external authorization page — this redirect works in the preview, but the OAuth provider must have your app's URL registered as an authorized redirect URI. The preview URL is dynamic and changes between sessions, so you cannot pre-register it in Google Cloud Console or GitHub OAuth apps. For social login, either test on your deployed URL or use `signInWithPopup` instead of `signInWithRedirect` — popups work in the preview without redirect URI registration. Set up an AuthContext to make the current user available throughout your app via React context.

```
// contexts/AuthContext.tsx
import { createContext, useContext, useEffect, useState, ReactNode } from 'react';
import { User, onAuthStateChanged } from 'firebase/auth';
import { auth } from '@/lib/firebase';

interface AuthContextValue {
  user: User | null;
  loading: boolean;
}

const AuthContext = createContext<AuthContextValue>({ user: null, loading: true });

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (firebaseUser) => {
      setUser(firebaseUser);
      setLoading(false);
    });
    return () => unsubscribe();
  }, []);

  return (
    <AuthContext.Provider value={{ user, loading }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  return useContext(AuthContext);
}

// lib/auth.ts
import {
  createUserWithEmailAndPassword,
  signInWithEmailAndPassword,
  signInWithPopup,
  GoogleAuthProvider,
  signOut as firebaseSignOut,
} from 'firebase/auth';
import { auth } from '@/lib/firebase';

export const signUpWithEmail = (email: string, password: string) =>
  createUserWithEmailAndPassword(auth, email, password);

export const signInWithEmail = (email: string, password: string) =>
  signInWithEmailAndPassword(auth, email, password);

export const signInWithGoogle = () =>
  signInWithPopup(auth, new GoogleAuthProvider());

export const signOut = () => firebaseSignOut(auth);
```

**Expected result:** Email/password sign-up and login work in the preview. Google Sign-In popup opens Firebase's Google OAuth flow. The useAuth() hook provides the current user throughout the app.

### 4. Understand the Firebase vs Supabase Trade-Off in Bolt

Before committing to Firebase as your backend, understand the key trade-off in the context of Bolt.new. Bolt's native Stripe payment integration — the one-click setup in Settings → Stripe that auto-generates checkout code — is built specifically around Supabase edge functions. Choosing Firebase means Bolt cannot auto-generate Stripe checkout flows, and you must implement payments manually using a Next.js API route or your own Firebase Cloud Functions. If your project needs payments, weigh this carefully. Firebase is the better choice when: your team already uses Firebase/Google Cloud products, your data model is naturally document-based (not relational), you need offline support or advanced real-time sync, or you're building a mobile app alongside the web app. Supabase is the better choice when: you want Bolt's one-click Stripe integration, you prefer SQL and relational data, you need complex queries that Firestore handles poorly, or you want a PostgreSQL-compatible database that can scale to full-featured analytics. You cannot use both Firebase and Supabase as the primary backend in the same Bolt project without significant complexity — pick one and commit. If you choose Firebase and need payments, add Stripe manually using the Next.js API route pattern.

```
// app/api/checkout/route.ts
// Manual Stripe checkout when using Firebase (bypasses Bolt's native Stripe integration)
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2024-04-10',
});

export async function POST(request: NextRequest) {
  const { priceId, userId } = await request.json();

  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    mode: 'payment',
    line_items: [{ price: priceId, quantity: 1 }],
    success_url: `${request.nextUrl.origin}/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${request.nextUrl.origin}/pricing`,
    metadata: { userId },
  });

  return NextResponse.json({ url: session.url });
}
```

**Expected result:** Manual Stripe checkout works with Firebase as the backend. The /api/checkout route creates sessions server-side without Supabase edge functions.

## Best practices

- Use signInWithPopup for OAuth providers during development — it works in Bolt's preview without requiring pre-registered redirect URIs
- Add authorized domains in Firebase Console → Authentication → Settings before deploying, or OAuth login will fail on your production URL
- Understand the Supabase trade-off before choosing Firebase — Bolt's native Stripe integration requires Supabase and won't work with Firebase as the backend
- Write Firestore Security Rules before deploying to production — test mode's open access expires 30 days after project creation
- Use the getApps().length === 0 guard in your Firebase initialization to prevent errors during Vite's hot module replacement
- Firestore's onSnapshot works in Bolt's WebContainer preview — use it to build and test real-time features before deploying
- For collections with more than 1 million documents, design your data model to avoid full-collection reads — always filter and limit queries

## Use cases

### Real-Time Collaborative App

Build a collaborative task board, shared document editor, or team chat application where multiple users see updates in real time. Firestore's onSnapshot listeners push database changes to all connected clients instantly — no polling required.

Prompt example:

```
Build a real-time collaborative task board using Firebase Firestore. Users can add, edit, and delete tasks that appear instantly for all users viewing the board. Use Firestore's onSnapshot listener for real-time updates. Organize tasks in a 'tasks' collection with fields: title, description, status (todo/in-progress/done), assignedTo, and createdAt.
```

### User Authentication with Google Login

Add sign-in with Google, email/password registration, and session management to a Bolt.new app. Firebase Auth handles the OAuth flow, token management, and user profile storage. Note: Google OAuth redirect requires a deployed URL to register as an authorized redirect URI.

Prompt example:

```
Add Firebase Authentication to my app with email/password signup, Google Sign-In, and GitHub login. Show a login page with these options. After authentication, redirect to /dashboard and show the user's display name and avatar from their Firebase profile. Protect the /dashboard route — redirect unauthenticated users to /login.
```

### File Upload App with Firebase Storage

Let users upload images, documents, or other files to Firebase Storage with progress tracking. Store file metadata (URL, name, size, uploader) in Firestore. Display uploaded files in a gallery with download links.

Prompt example:

```
Build a file upload system using Firebase Storage. Users can drag and drop files to upload. Show a progress bar during upload. Store the download URL and metadata in a Firestore 'uploads' collection. Display all uploaded files in a grid with file name, size, upload date, and a download button. Limit uploads to 10MB per file.
```

## Troubleshooting

### Firebase initialization fails with 'Firebase: No Firebase App named [DEFAULT] has been created'

Cause: The Firebase app is being used (db, auth, storage calls) before initializeApp() has been called, or in a module that doesn't import from lib/firebase.ts.

Solution: Ensure all Firebase usage imports db, auth, or storage from your lib/firebase.ts file (which calls initializeApp). The getApps().length === 0 guard in lib/firebase.ts prevents double-initialization during hot reload.

```
// Always import from your central firebase.ts
import { db, auth } from '@/lib/firebase';
// Never call initializeApp() directly in component files
```

### Firestore query returns an error requiring an index with a link to create it

Cause: Compound Firestore queries (filtering on multiple fields, or filtering + ordering) require composite indexes that must be created in the Firebase Console.

Solution: Click the link in the error message — it opens Firebase Console with the index pre-configured for one-click creation. Wait 1-2 minutes for the index to build, then retry the query.

### Google Sign-In fails with 'auth/unauthorized-domain' error

Cause: The current domain (either the Bolt preview URL or your deployed domain) is not in Firebase's list of authorized domains for OAuth redirects.

Solution: In Firebase Console → Authentication → Settings → Authorized domains, add your deployed domain (e.g., your-app.netlify.app). For the Bolt preview, use signInWithPopup instead of signInWithRedirect — popups don't require pre-registered domains.

```
// Use popup (works in preview) instead of redirect (requires domain registration)
import { signInWithPopup, GoogleAuthProvider } from 'firebase/auth';
const result = await signInWithPopup(auth, new GoogleAuthProvider());
```

### Firestore reads return no data even though documents exist in the Firebase Console

Cause: Firestore Security Rules are blocking reads. By default, test mode allows all access for 30 days after project creation, after which rules may default to denying all access.

Solution: In Firebase Console → Firestore Database → Rules, check the current rules. For development, set rules to allow all reads and writes. For production, write rules that only allow authenticated users to read their own data.

```
// Firestore rules for development (update before production!)
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}
```

## Frequently asked questions

### Does the Firebase JS SDK work in Bolt's WebContainer?

Yes. The Firebase JS SDK uses HTTP and WebSocket protocols under the hood, which are fully supported in Bolt's WebContainer runtime. Firestore CRUD operations, real-time listeners (onSnapshot), Authentication, and Storage uploads all work in the preview environment. This makes Firebase one of the most WebContainer-compatible backend options available.

### Can I use Firebase and Bolt's native Stripe integration together?

No — Bolt's native Stripe integration (Settings → Stripe → 'Add payments') auto-generates Supabase edge functions and requires Supabase as the backend. If you use Firebase, you must implement Stripe manually using a Next.js API route. The manual approach works well — you just don't get Bolt's one-click Stripe setup.

### Should I choose Firebase or Supabase for my Bolt.new app?

Choose Firebase for real-time collaborative features, document-based data, offline support, or if you're in the Google ecosystem. Choose Supabase if you want relational SQL, Bolt's native Stripe integration, complex queries, or prefer PostgreSQL. Both work in Bolt's WebContainer, but Supabase unlocks Bolt's automated payment setup.

### How do I deploy a Bolt.new app with Firebase to Netlify?

In Bolt, click Settings → Applications and connect Netlify via OAuth. Click Publish. After deploying, add your Firebase config values (NEXT_PUBLIC_FIREBASE_API_KEY, etc.) as environment variables in Netlify's Site Configuration → Environment Variables. Add your Netlify domain to Firebase Console → Authentication → Settings → Authorized domains. Redeploy to apply environment variables.

### Do Firebase Cloud Functions work with Bolt.new?

You can call deployed Firebase Cloud Functions (v2) from your Bolt app via HTTP using the Firebase SDK or standard fetch. However, you cannot develop or deploy Firebase Cloud Functions from within Bolt itself — Cloud Functions require the Firebase CLI, which runs outside the WebContainer. Develop functions locally and deploy via the CLI, then call them from your Bolt app by URL.

---

Source: https://www.rapidevelopers.com/bolt-ai-integrations/firebase
© RapidDev — https://www.rapidevelopers.com/bolt-ai-integrations/firebase
