In today’s fast-paced tech world, choosing the right stack is essential for entrepreneurs and startups eager to bring their ideas to life quickly.
The combination of Next.js, and Firebase provides a powerful way to rapidly prototype and build apps, making it the ideal environment to test out your new ideas at a very important pace.
With Next.js’s flexible, component-based front end, and Firebase’s all-in-one cloud services like authentication, database, and hosting, this stack makes it easy to develop proof-of-concept (PoC) projects and iterate on ideas fast—without complex infrastructure setup.
In this guide, we’ll build a simple to-do app to show how quickly you can go from concept to working application.
What You’ll Build in This Guide
We’ll build a simple task management application where users can:
- Sign up and sign in using Firebase Authentication.
- Create and manage tasks (CRUD operations) stored in Firebase Firestore.
- The app will be deployed on Vercel, making it production-ready.
Prerequisites
Here is a quick list about the things to have before going any further:
- A Firebase account.
- Basic knowledge of React and Next.js.
- Node.js installed on your machine.
Step 1: Setting up the Next.js project
Open a terminal and write the command below:
npx create-next-app task-manager
cd task-manager
This creates a Next.js application inside the folder task-manager
.
Install Firebase SDK
Install the necessary Firebase packages using the command below:
npm install firebase
The Firebase SDK will allow us to interact with the services included like Firestore and Authentication from within the Next.js app.
Step 2: Firebase Setup
Create a Firebase project
- Go to the Firebase console and create a new Firebase project.
- Enable Firebase Authentication and Firestore Database.
Configure Firebase Authentication
In the Authentication section, add a new sign-in method using the native email/password provider.
In the Firestore Database section, create a new database and start in test mode for development purposes.
Download Firebase Config
To connect your app to Firebase, you'll need to configure Firebase in your Next.js app.
Go to Project Settings in Firebase Console, then under Your Apps, select Web App to get the Firebase configuration.
Copy this configuration as you'll use it to initialize Firebase in your app.
Step 3: Initialize Firebase in the Next.js app
Create Firebase Configuration file
Create a file called firebase.js
inside the src/
folder or wherever you prefer.
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';
import 'firebase/auth';
import { getAuth } from 'firebase/auth';
const firebaseConfig = {
apiKey: 'YOUR_API_KEY',
authDomain: 'YOUR_AUTH_DOMAIN',
projectId: 'YOUR_PROJECT_ID',
storageBucket: 'YOUR_STORAGE_BUCKET',
messagingSenderId: 'YOUR_MESSAGING_SENDER_ID',
appId: 'YOUR_APP_ID',
};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const auth = getAuth(app);
export { db, auth };
Replace the placeholders with your Firebase configuration copied in the previous step.
Step 4: Build the Authentication using Firebase
In this step, we will build the authentication part where users can sign up, sign in, and sign out.
Sign-up and Sign-in pages
Create the pages/signUp.js
for the signing page:
import { useState } from 'react';
import { auth } from '../firebase';
import { useRouter } from 'next/router';
import { createUserWithEmailAndPassword } from 'firebase/auth';
const Signup = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState(null);
const router = useRouter();
const handleSubmit = async (e) => {
e.preventDefault();
try {
await createUserWithEmailAndPassword(auth, email, password);
router.push('/tasks'); // Redirect to tasks page after signup
} catch (err) {
setError(err.message);
}
};
return (
<div>
<h2>Sign Up</h2>
<form onSubmit={handleSubmit}>
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Sign Up</button>
</form>
{error && <p>{error}</p>}
</div>
);
};
export default Signup;
Create the pages/signIn.js
for the signing page:
import { useState } from 'react';
import { auth } from '../firebase';
import { useRouter } from 'next/router';
import { signInWithEmailAndPassword } from 'firebase/auth';
const Signin = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState(null);
const router = useRouter();
const handleSubmit = async (e) => {
e.preventDefault();
try {
await signInWithEmailAndPassword(auth, email, password);
router.push('/tasks'); // Redirect to tasks page after login
} catch (err) {
setError(err.message);
}
};
return (
<div>
<h2>Sign In</h2>
<form onSubmit={handleSubmit}>
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Sign In</button>
</form>
{error && <p>{error}</p>}
</div>
);
};
export default Signin;
Step5: Task management and CRUD operations with Firestore
This step is focusing on implementing the core of the application: the task management system.
Tasks Page with CRUD Operations
Create pages/tasks.js where users can add, view, and delete tasks:
import { useState, useEffect } from 'react';
import { db, auth } from '../firebase';
import { useRouter } from 'next/router';
import { collection, query, where, onSnapshot, addDoc, deleteDoc, doc } from 'firebase/firestore';
const Tasks = () => {
const [tasks, setTasks] = useState([]);
const [task, setTask] = useState('');
const [error, setError] = useState(null);
const router = useRouter();
useEffect(() => {
if (!auth.currentUser) {
router.push('/signin');
return;
}
const q = query(
collection(db, 'tasks'),
where('userId', '==', auth.currentUser.uid)
);
const unsubscribe = onSnapshot(q, (snapshot) => {
const newTasks = snapshot.docs.map((doc) => {
return { id: doc.id, ...doc.data() };
});
setTasks(newTasks);
});
return () => unsubscribe();
}, []);
const handleAddTask = async (e) => {
e.preventDefault();
if (task.trim()) {
try {
await addDoc(collection(db, 'tasks'), {
userId: auth.currentUser.uid,
task,
completed: false,
});
setTask('');
} catch (err) {
setError(err.message);
}
}
};
const handleDeleteTask = async (id) => {
try {
await deleteDoc(doc(db, 'tasks', id));
} catch (err) {
setError(err.message);
}
};
return (
<div>
<h2>Your Tasks</h2>
<form onSubmit={handleAddTask}>
<input
type="text"
value={task}
onChange={(e) => setTask(e.target.value)}
placeholder="Add a new task"
/>
<button type="submit">Add Task</button>
</form>
{error && <p>{error}</p>}
<ul>
{tasks.map((task) => (
<li key={task.id}>
{task.task}
<button onClick={() => handleDeleteTask(task.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
};
export default Tasks;
This page allows users to:
- Add tasks to Firebase Firestore.
- View tasks associated with their user.
- Delete tasks from Firestore.
Step 6: Deploying the app using Vercel
To deploy the app, you can use Vercel, which is built specifically for Next.js. Here’s how to deploy:
- Push your code to a GitHub repository.
- Go to Vercel, sign in with your **GitHub **account, and import the repository.
- Vercel **automatically detects that it’s a **Next.js project and handles the build and deployment process.
Conclusion
You’ve now built a full-stack application using Next.js and Firebase, covering essential features like authentication and CRUD operations with Firestore. This stack offers a powerful way to build scalable, serverless applications quickly, making it perfect for MVPs and production apps alike.
Please let me know if you have any problem going through this guide or if you see any possible improvement :)
Happy coding!
Top comments (0)