Claude Code Boilerplate
FeaturesPricingBlogDocs
Get started →

Product

  • Features
  • Pricing
  • Skills

Compare

  • vs ShipFast
  • vs MakerKit
  • vs supastarter

Resources

  • Docs
  • Blog
  • Discord

Legal

  • License
  • Privacy Policy
  • Terms of Service
Claude Code Boilerplate

© 2026 Claude Code Boilerplate. All rights reserved.

← All posts

How to Build a SaaS Admin Panel With Next.js -- User Management, Search, and Bulk Actions

July 15, 2026
nextjssaasdrizzle-ormauthadmin

Every SaaS founder eventually has to look something up manually. A customer emails saying they cannot log in. A subscription did not activate after payment. Someone requests account deletion under GDPR. You open your database client, run a query, and fix it by hand.

That works for the first ten customers. It does not scale past the first hundred.

Most founders reach for an external admin tool at this point -- Retool, Appsmith, or a hosted dashboard service. That feels fast at first, but two problems show up later: the external tool has its own access model that drifts out of sync with your actual permissions, and it has no audit trail unless you wire one up yourself.

If your Next.js app already has auth, a database, and an API layer, you have everything you need to build a scoped admin panel inside your own product.

What an admin panel actually needs

You do not need a chart-heavy BI tool. A basic SaaS admin panel has four jobs:

  1. Find a user by email or ID
  2. See their current account state: plan, email verified, active or suspended
  3. Take a corrective action: activate, suspend, send a reset link, delete account
  4. Record what changed and who did it

A table, a search input, a few action buttons, and an audit trail. That is the whole thing.

The external-tool trap

External tools feel faster to set up initially. You connect a database, drag a table component, and you are done. But two things start costing you later.

First, external tools have their own access model. Anyone with tool access can query any table. Scoping it down to "support can see users but not payment details" requires separate configuration that drifts out of sync with your actual app permissions.

Second, you lose the audit trail. When a support agent suspends an account in Retool, there is no record in your own database unless you wire it manually. Inside your codebase, every admin action writes to the same audit log your product already uses.

An internal admin panel also adds no new service to secure and pay for. You are adding a protected route group to an app you already deploy and own.

How to structure it in Next.js

Create a route group at app/(admin)/ with its own layout. The layout checks that the authenticated user has role === 'admin' and redirects everyone else. This is the same role check described in role-based access control applied at the layout level instead of inside individual service functions.

Inside the group, one page does most of the work: app/(admin)/users/page.tsx. It is a server component that reads ?q= and ?page= from the URL and runs a Drizzle query against your users table:

// simplified -- full filter logic lives in userRepo
const users = await userRepo.searchByEmail(q, { page, limit: 25 })

No client state, no separate API endpoint needed. The result renders as a shadcn Table with status badges and action buttons. Each action -- suspend, activate, send a reset link -- posts to a thin API route that calls the relevant service function and writes an audit log entry with the admin user ID, target user ID, action name, and timestamp.

Five actions to build first

Start with the ones that come up every week:

  • Suspend account -- sets a suspended flag on the user row; your JWT validation step already rejects suspended users if you add that check to getUserFromRequest()
  • Activate account -- clears a suspension or manually marks email as verified
  • Send password reset link -- reuses the same signed-token flow your product already has for self-service reset
  • Impersonate user -- log in as a customer to reproduce their exact issue (full pattern here)
  • Delete account -- triggers your GDPR deletion flow behind a confirmation dialog so it cannot be done by accident

Every action writes an audit log row. Six months from now, when a user disputes a suspension, you have a record with the admin's ID, the action, and the exact timestamp.

Who should build it this way

An internal admin panel makes sense when you want support staff to take specific actions without giving them raw database access, when you need a paper trail tied to your existing user IDs, and when you want permissions enforced by the same role system your product already uses.

It does not make sense if you have complex reporting needs across many tables -- a BI tool like Metabase is the right answer for that.

If you are starting from this Next.js SaaS boilerplate, the user table, JWT auth, service layer, and role column are already in place. You are adding a route group and a search page -- not building a data platform from scratch.


Build the admin panel inside your product, not alongside it. Get the boilerplate and ship the first admin view this weekend.