1Create a Firebase Project
- Log in with your Google account at console.firebase.google.com
- Click Add project
- Enter a project name
- Configure Google Analytics (optional)
- Click Create project
- After creation, click Add web app (</> icon) to get SDK configuration
Info
After project creation, go to Project Settings in the dashboard to find your API keys and configuration.
2Firestore Database Setup
Select Firestore Database in the dashboard and create a database.
- Click Create database
- Choose production mode or test mode
- Select a region:
asia-northeast3 (Seoul)recommended
Security Rules Setup
Go to Firestore → Rules tab and apply the security rules below.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /todos/{todoId} {
allow read, write: if request.auth != null
&& request.auth.uid == resource.data.userId;
allow create: if request.auth != null
&& request.auth.uid == request.resource.data.userId;
}
}
}Why security rules matter
Without security rules, all users can access all data.
Use request.auth.uid to restrict access so only logged-in users can access their own data.
3Client Setup (React)
Install Dependencies
npm install firebaseEnvironment Variables
# .env.local
VITE_FIREBASE_API_KEY=your-api-key
VITE_FIREBASE_AUTH_DOMAIN=your-project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your-project-id
VITE_FIREBASE_STORAGE_BUCKET=your-project.appspot.com
VITE_FIREBASE_MESSAGING_SENDER_ID=your-sender-id
VITE_FIREBASE_APP_ID=your-app-idFind these in Firebase Console → Project Settings → General → Your apps.
Firebase Client
// src/lib/firebase.ts
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
import { getAuth } from 'firebase/auth';
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,
};
const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);
export const auth = getAuth(app);4CRUD Example (React + Firestore)
A Todo app example using Firestore's realtime subscription (onSnapshot).
// src/hooks/useTodos.ts
import { useState, useEffect } from 'react';
import {
collection,
addDoc,
getDocs,
updateDoc,
deleteDoc,
doc,
query,
where,
orderBy,
onSnapshot,
serverTimestamp,
} from 'firebase/firestore';
import { db, auth } from '../lib/firebase';
interface Todo {
id: string;
title: string;
completed: boolean;
userId: string;
createdAt: any;
}
export function useTodos() {
const [todos, setTodos] = useState<Todo[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const user = auth.currentUser;
if (!user) return;
const q = query(
collection(db, 'todos'),
where('userId', '==', user.uid),
orderBy('createdAt', 'desc')
);
// Realtime subscription
const unsubscribe = onSnapshot(q, (snapshot) => {
const items = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
})) as Todo[];
setTodos(items);
setLoading(false);
});
return () => unsubscribe();
}, []);
// Create
const addTodo = async (title: string) => {
const user = auth.currentUser;
if (!user) throw new Error('Not authenticated');
await addDoc(collection(db, 'todos'), {
title,
completed: false,
userId: user.uid,
createdAt: serverTimestamp(),
});
};
// Update
const toggleTodo = async (id: string, completed: boolean) => {
await updateDoc(doc(db, 'todos', id), { completed });
};
// Delete
const removeTodo = async (id: string) => {
await deleteDoc(doc(db, 'todos', id));
};
return { todos, loading, addTodo, toggleTodo, removeTodo };
}5Authentication Example (Optional)
With Firebase Auth, you can easily implement email/password login.
// src/hooks/useAuth.ts
import { useState, useEffect } from 'react';
import {
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
signOut as firebaseSignOut,
onAuthStateChanged,
User,
} from 'firebase/auth';
import { auth } from '../lib/firebase';
export function useAuth() {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
setUser(user);
setLoading(false);
});
return () => unsubscribe();
}, []);
// Sign up
const signUp = async (email: string, password: string) => {
const { user } = await createUserWithEmailAndPassword(
auth, email, password
);
return user;
};
// Sign in
const signIn = async (email: string, password: string) => {
const { user } = await signInWithEmailAndPassword(
auth, email, password
);
return user;
};
// Sign out
const signOut = async () => {
await firebaseSignOut(auth);
};
return { user, loading, signUp, signIn, signOut };
}Social login
Social login with Google, GitHub, Facebook, and more is also supported. Configure it in Firebase Console → Authentication → Sign-in method.
When should you use Firebase?
Recommended
- - Building a prototype quickly
- - When realtime data sync is needed
- - Supporting mobile and web simultaneously
- - When Google ecosystem integration is needed
Consider carefully
- - Complex relational queries are needed
- - SQL-based data analysis is important
- - Vendor lock-in is a concern
- - Frequent bulk data exports are needed
Next steps
- Auth Guide - Compare JWT, Session, OAuth
- Firebase Official Docs - More detailed features
- Supabase Guide - Compare with a SQL-based alternative