What You’ll Build
Prerequisites
Step 1: Setting Up Your Next.js Project
Step 2: Build the Pages and Layout
Step 3: Add Authentication with NextAuth
Step 4: API Routes - Backend in Next.js
Step 5: Connect to a Database using Prisma
Step 6: Building the Dashboard
Step 7: Deploy with Vercel
Bonus Features to Explore
Testing Your Full-Stack App
Developer Tips
Conclusion
Next.js has quickly become one of the most powerful and developer-friendly frameworks for building modern web applications. Whether you’re a beginner looking to step into full-stack development or an experienced developer exploring the React ecosystem’s cutting edge, this crash course is for you.
In this deep-dive guide, we’ll cover how to build a full-stack application using Next.js from start to finish. You’ll learn the core concepts and apply them in real time to build something functional, beautiful, and production-ready.
A simple yet powerful Task Manager application that includes:
By the end, you’ll have a working full-stack app deployed live on the internet.
npx create-next-app@latest task-manager --typescript
cd task-manager
npm install
Structure:
/pages
/components
/lib
/prisma
/public
/styles
Install Tailwind CSS:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Add Tailwind to styles/globals.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
Configure tailwind.config.js:
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
Start the server:
npm run dev
Next.js uses the /pages directory to automatically generate routes.
Create a layout component:
// components/Layout.tsx
export default function Layout({ children }) {
return (
<div className="min-h-screen bg-gray-100 p-4">
<main>{children}</main>
</div>
);
}
Use it in your pages:
import Layout from "../components/Layout";
export default function Home() {
return (
<Layout>
<h1 className="text-2xl font-bold">Welcome to Task Manager</h1>
</Layout>
);
}
Install NextAuth.js:
npm install next-auth
Create the route:
/pages/api/auth/[...nextauth].ts
Example (using GitHub Provider):
import NextAuth from "next-auth";
import GitHubProvider from "next-auth/providers/github";
export default NextAuth({
providers: [
GitHubProvider({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
],
});
Use the useSession hook:
import { useSession, signIn, signOut } from "next-auth/react";
const { data: session } = useSession();
if (!session) {
return <button onClick={() => signIn()}>Login</button>;
}
Create your first API route:
/pages/api/tasks/index.ts
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === "GET") {
res.status(200).json({ tasks: [] });
} else if (req.method === "POST") {
const { title } = req.body;
res.status(201).json({ task: { id: 1, title } });
}
}
Install Prisma:
npm install prisma --save-dev
npx prisma init
Example PostgreSQL schema:
model Task {
id Int @id @default(autoincrement())
title String
done Boolean @default(false)
createdAt DateTime @default(now())
}
Run migration:
npx prisma migrate dev --name init
Create helper functions:
import { PrismaClient } from '@prisma/client';
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const prisma =
globalForPrisma.prisma ||
new PrismaClient({ log: ['query'] });
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
Use in API:
import { prisma } from "../../../lib/prisma";
const tasks = await prisma.task.findMany();
Tasks List + Add Task Form:
// components/TaskForm.tsx
export default function TaskForm({ onAdd }) {
const [title, setTitle] = useState("");
return (
<form onSubmit={e => {
e.preventDefault();
onAdd(title);
setTitle("");
}}>
<input value={title} onChange={e => setTitle(e.target.value)} />
<button type="submit">Add Task</button>
</form>
);
}
Fetch and render tasks:
useEffect(() => {
async function load() {
const res = await fetch("/api/tasks");
const data = await res.json();
setTasks(data.tasks);
}
load();
}, []);
Push to GitHub, then:
Vercel automatically detects Next.js, installs dependencies, and runs your app in seconds.
Install Jest and React Testing Library:
npm install --save-dev jest @testing-library/react
Test a component:
// __tests__/TaskForm.test.tsx
import { render, screen } from "@testing-library/react";
import TaskForm from "../components/TaskForm";
test("renders input", () => {
render(<TaskForm onAdd={() => {}} />);
expect(screen.getByRole("textbox")).toBeInTheDocument();
});
In just a few hours, you've gone from zero to full-stack, building a complete application using Next.js, API routes, a database, and authentication. You’ve touched on both frontend and backend, and even learned how to deploy to the cloud.
This is just the beginning.
Next.js opens doors to more powerful concepts, like static generation, server-side rendering, image optimization, middleware, edge functions, and more. Once you’re comfortable, try upgrading your task manager with advanced features or even rebuild it using the App Router in Next.js 13+.
Keep coding, keep learning, and ship your ideas into the world.
Do you want the complete source code for this project with styles and folder structure included? Just let me know!
Software Engineer
Senior Software Engineer