Hype StackHypeStack

Stack

React Admin Panel Template

Every admin panel starts as one protected page for support. Six months later it can write to production, and nobody decided that.

Admin panels often start as small internal tools. Support needs to look up a user, so someone adds a protected page. Over time, that page may gain subscription controls and other writes to production without a corresponding permission model or deployment boundary.

Picking a react admin panel template includes deciding where that boundary sits and how much of it the template enforces in code.

Three ways to get an admin, and what each costs

Hype Stack
Auto-CRUD generator
Hand-built
First screen
Minutes: generate the app and rebrand it
Minutes: point it at a schema and it renders
Days, per screen
Custom logic
Ordinary React and Hono code in your repo
Escape hatches, overrides, then a rewrite
Whatever you want, you wrote it
Auth boundary
Shared session, then a role looked up in a staff table the customer has no row in
Usually a flag on the customer's own user record
Depends on the authentication and authorization design
Deploy target
Its own Vite build, so it can sit behind a VPN or allowlist
A route inside your public app
Your choice
In five years
Source you own, no upstream to track
A dependency whose opinions you inherited
Exactly what you maintained

An auto-CRUD generator is usually faster for the first screen. If your admin covers five tables and serves two trusted people, that may be enough. This template is aimed at admin tools that need custom business logic, broader staff access, or a separate deployment boundary.

The authorization and deployment boundary

apps/admin is its own application in the monorepo with its own Vite build, next to the public frontend and the Hono backend. That separation has three practical effects:

  • Its own authorization, on a shared session. getAdminApp() is new Hono().use(withAuthUser).use(withAdmin), so a request carries the same session cookie a customer would, and then withAdmin looks the user up and throws a 403 unless they are staff. The session is shared. The authorization is not, and it is a lookup rather than a flag.
  • Its own role vocabulary, in its own table. Platform roles are super_admin and admin, and they live in an Admin table that has nothing to do with the organization roles your tenants use. Being manage:all inside a tenant does not grant access here. Managing other admins is restricted to super_admin.
  • Its own deploy. Because it builds separately, you can put it behind a VPN, an IP allowlist, or a private hostname without touching the public frontend or its CDN config.

The first admin needs a bootstrap path. This template resolves it through an environment variable:

ts
// features/admin/helpers/super-admin.ts
export const resolveAdminAccess = async ({
  userId,
  email,
}: {
  userId: string;
  email?: string | null;
}): Promise<AdminRole | null> => {
  if (isSuperAdminEmail(email)) return AdminRole.SUPER_ADMIN;

  const row = await getAdminQuery({ email, userId });
  return row?.role ?? null;
};

SUPER_ADMIN_EMAIL is a comma-separated environment variable, and the addresses in it are super admins whether or not they have a row in the admin table. Nothing is auto-inserted. A fresh database has an owner because the environment says so, and revoking that access requires changing the environment and deploying again.

An integration test verifies this behavior. admin.access-matrix.integration.test.ts runs five cases against real routes: a signed-in non-admin gets a 403, an admin is admitted and reports ADMIN, a bootstrap super admin is admitted and reports SUPER_ADMIN with no database row, a plain admin is blocked from the super_admin-only surface, and a super admin can list it. If a change loosens the middleware, that file fails.

your-app
  • apps/
  • frontend/

    the public app, on your CDN

  • admin/

    its own Vite build, so it can sit behind a VPN

  • backend/
  • src/middleware/

    admin requests use admin middleware

  • src/features/admin/

    platform roles, not tenant roles

  • src/routes/admin/

    the access matrix test lives here

Two builds, one backend, one session. A customer's cookie reaches the admin routes and gets a 403 there, from a role lookup against a table they have no row in, rather than from a flag on their own user record.

It shares the typed SDK with everything else, so an endpoint added for an admin screen is typed on the client the same way a customer endpoint is.

What the included screens support

One useful way to judge an admin panel is to map its screens to the support and operations questions it can answer:

Somebody asksWhere it gets answered
"I can't get into my account"Users: search, open a user, edit them, remove a membership
"Can you move me to the other company's workspace?"Organizations: open an org, edit it, remove a member
"Are we growing?"Dashboard: new users over thirty days, org count, a signups chart, five most recent signups
"Give the new support hire access"Admins: invite and manage platform admins, super_admin only

Those are queries against your own data, written as ordinary feature modules. Adding a widget means adding a Hono route and a card rather than using a plugin extension API. That gives you room to support questions the included screens do not cover.

Where the admin comes from

The template reserves apps/admin, but the screens, the admin middleware, and the platform role model arrive with a paid SaaS starter pack. The free open-source core ships the frontend and backend without them. So this page describes what you get once the starter is composed in, not what a bare clone contains.

What it deliberately does not have

There is no audit log UI. If you need "who changed this record and when" for compliance, you must add it. Audit scope and retention requirements vary by company, so the template does not prescribe a generic implementation.

This gap matters because an admin panel contains write endpoints pointed at production. The authorization boundary decides who can reach them. An audit log records what they changed.

How far to take the boundary

Admin panels can sit at different points on the same isolation axis. Small internal tools often begin inside the main application, while tools with stricter access requirements may justify a separate build, session, or network.

The same admin panel, at four points in its life

Inside the customer app
  1. A page behind a shared password

    Same origin and bundle, with one shared credential protecting the page.

  2. An /admin route with a role flag

    One boolean on the user row separates a customer session from an admin write endpoint.

  3. A separate build, and staff are their own table

    Where this template actually sits. Its own Vite build, a role resolved against an Admin table rather than a column on the customer, and an access-matrix test that fails if that stops being true. The cookie is still the customer's cookie.

  4. A separate session, on a network you have to be on

    Its own identity provider or a second cookie, behind a VPN or an IP allowlist. Not in the box, and for most products not worth it. The separate build is what leaves the option open.

A separately deployed private app

The separate build and staff table provide more isolation than an in-app route, while the shared session means this is not the strictest option shown here.

When evaluating an admin template, check how a request proves it is allowed and which tests fail if that protection is removed. Screens can be changed as requirements grow, but the access boundary affects every admin route.

The admin app is below, running, alongside the files it installs.

See it running

Templates are curated project starters built on this stack: a layout, feature packs, a custom theme, and bonus pages. The previews below are recordings of the real apps.

Two ways to install features

Same features underneath, different starting point. Either command resolves what the packs depend on, copies the source into your repository, and merges the Prisma schema.

Ready-made

Take a template

A landing page, a design system, a themed layout, and the features already wired into it. Rebrand it, put your product in the middle, ship.

$npx @hype-stack/cli template
Browse templates
From scratch

$ hype-stack compose

Auth

Compose your own design

Your design and your choices, without rebuilding auth, billing, or notifications. Tick the packs you want and the CLI wires them into the open-source starter.

$npx @hype-stack/cli compose
Browse packs

Inside the stack

What each pack gives you

Source code, not a dependency. Every pack lands in your repository across the surfaces the feature touches.

Authentication, organizations, roles, sessions, and a full admin app, powered by WorkOS.

  • Email & social login
  • Organizations & members
  • Roles & permissions
  • Admin app & dashboard

Questions, answered

SaaS Starter (WorkOS), which fills the admin app with a dashboard, user lookup and editing, organization management, membership removal, and platform admin management. It shares the typed SDK with the public frontend and the Hono backend.

More stacks

Turn your ideas into
Real applications.

Start free and own every line you ship. When you want more, one All-Access license unlocks every premium pack and template for a year.

All premium packsEvery template12 months of updates
Get All-Access