Stop 11 · Next.jsProjects · 4/4

Admin Dashboard

Part of the Frontend Developer Roadmap

In short

Every real product has an admin panel behind the scenes. Building one teaches you protected routes, server-side data loading, tables, forms and role checks, all things companies need daily.

A protected, data-heavy admin interface built on Next.js — practice for middleware-based auth, Server Components for data fetching, and role-based access.

The jaadu sits at a railway control room desk watching big screens of glowing lines and dots.

Think of it like this

The railway control room

Passengers see platforms and trains. Behind a locked door, a few staff watch every train on big screens and change signals. Your admin dashboard is that control room: only the right people get in, and they see and change everything.

Watch it happen

Two locks on the admin door

Browser
proxy.ts
Admin page

GET /admin/users

1/4An editor, not an admin, opens the users page with a valid session cookie.

The big ideas

What you need to know

Protected routes

A proxy redirects logged-out users, and each page or action checks the session and role again.

Server-loaded data

Fetch stats and tables in Server Components, close to the database, with loading.tsx for skeletons.

Edits via Server Actions

Update, approve or delete records with Server Actions, then revalidatePath to refresh the table.

Role-based access

An editor can edit posts, only an admin can delete users. Check the role on the server for every action.

How it works

Build plan

  1. 1

    Auth gate

    Add a login and a proxy.ts that guards /admin.

  2. 2

    Dashboard layout

    An admin layout.tsx with a sidebar and a header showing the user.

  3. 3

    Data tables

    Users and orders tables with pagination via search params.

  4. 4

    Actions and roles

    Server Actions for edits, each checking the user's role first.

See it in code

Walk through the code

ts
1// lib/auth.ts2import { cookies } from "next/headers";3import { redirect } from "next/navigation";4 5export async function requireRole(role: "admin" | "editor") {6  const store = await cookies();7  const user = await getUserFromSession(store.get("session")?.value);8 9  if (!user) redirect("/login");10  if (role === "admin" && user.role !== "admin") redirect("/admin?error=forbidden");11  return user;12}13 14// In any admin page or Server Action:15// const user = await requireRole("admin");

1/4Read the session cookie and look up who it belongs to.

One helper, called at the top of every admin page and action. If the proxy is ever misconfigured, this still blocks the wrong people.

Save yourself the pain

Common mistakes

Oops

Relying only on the proxy redirect to protect admin data.

Do this instead

Call a role check inside each page and Server Action too. Defence in layers.

Oops

Loading 10,000 rows into a table at once.

Do this instead

Paginate on the server with page and limit in the URL search params.

Your mission

Milestone 1: locked control room

~45 min

Quick check

Why check the user's role inside each Server Action when proxy already guards /admin?

Go deeper

  1. 1Protect the whole `/admin` route segment using middleware.
  2. 2Fetch dashboard data directly in Server Components instead of client-side `useEffect`.
  3. 3Add a layout shared across all admin pages (`app/admin/layout.tsx`).

More projects at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge