How I Structure a Supabase + Vercel Admin Panel From Scratch
Every project I build gets a custom admin panel. Here is the exact structure I use — modules, schema, auth, and the reusable boilerplate approach that saves days of setup time.
Table of contents
Every project I have shipped in the past year has a custom admin panel. Not a third-party dashboard tool. Not an auto-generated CRUD interface. A purpose-built admin that matches exactly what the project needs to manage.
The reason is simple: off-the-shelf admin tools are built for generic use cases. Your project has specific data and specific workflows. A purpose-built admin is faster to use and easier to extend.
Here is the structure I reuse across projects, and why each piece exists.
The Core Modules
Every admin panel I build includes these modules, regardless of the project type:
Dashboard — Aggregate counts and trend indicators. Posts published this week, active clients, new leads, revenue if relevant. The goal is: open the admin, understand the state of the project in 10 seconds, close the admin.
Content CMS — Create, edit, publish, unpublish content. Markdown editor with preview. Tag and category management. Meta description and slug fields. The CMS is always connected to the same database the public site reads from — no sync step, no duplication.
CRM / Pipeline — Client records with pipeline stages. Tasks attached to clients. Interaction history. CSV export. Even projects without paying clients have a lightweight version of this for lead tracking.
Lead inbox — Contact form submissions land here. Source-tagged (which page, which CTA). One-click promotion to CRM pipeline. Nothing gets lost in email.
Settings — API keys for external services. Site configuration. Per-user preferences if the panel has multiple users.
The Database Schema
The Supabase schema for the admin panel side (as opposed to the public-facing side) follows a consistent pattern:
All content tables have: id (bigserial), created_at (timestamptz default now()), updated_at (timestamptz), status or published boolean.
All CRM tables have foreign keys with ON DELETE CASCADE — deleting a client removes their tasks and interactions automatically. No orphaned records.
All write-heavy tables get created_by / updated_by if the panel has multiple users. Single-user panels skip this.
CREATE TABLE clients (
id BIGSERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT,
company TEXT,
pipeline_stage TEXT DEFAULT 'lead',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE client_tasks (
id BIGSERIAL PRIMARY KEY,
client_id BIGINT REFERENCES clients(id) ON DELETE CASCADE,
title TEXT NOT NULL,
due_date DATE,
completed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
Auth and Access Control
For single-user admin panels (most of my projects), Supabase Auth with signInWithPassword is sufficient. One admin user, one password, one session.
The pattern:
// AdminGuard.tsx
const session = await supabase.auth.getSession();
if (!session.data.session) redirect('/admin/login');
For multi-user panels, I add row-level security policies per user role. The roles are: admin (full access), manager (read + write, no delete), viewer (read only). RLS policies enforce this at the database level — not just the UI level.
Deploying on Vercel
The admin panel lives at /admin/* on the same Next.js deployment as the public site. Vercel handles this without any additional configuration — the file-based routing in Next.js means /app/admin routes are just routes.
One important detail: admin pages should not be statically generated. Use export const dynamic = 'force-dynamic' on admin pages, or set up a per-layout config. Admin data should always be fresh.
The Reusable Boilerplate
I maintain a starter that includes:
- —Auth flow (login, session check, redirect)
- —AdminShell component with collapsible nav
- —Dashboard page with aggregate queries
- —Blog CMS with markdown editor
- —CRM with pipeline stages
- —Lead inbox with source tagging
- —Settings page
Scaffolding a new project from this starter takes about 90 minutes instead of 3–4 days. The schema adapts to the project's specific data model, but the structure and patterns are already solved.
Resources
- —Supabase Auth with Next.js — the server-side auth setup for Next.js App Router; slightly different from client-side patterns
- —Supabase RLS documentation — how to write policies that enforce per-role access at the database level
- —Next.js App Router — route segments — how
/app/adminbecomes a protected section with its own layout
Related Posts
- —Case Study: santoshpaudel.me — A Portfolio That Runs Like a Business — the live example of an admin panel using exactly this structure
- —Building a Lead and CRM System Into Your Portfolio Site — the CRM module that sits inside the admin panel
- —Auto Sitemap, Schema, and Robots.txt: The 3 Files Most Developers Forget — the public-facing SEO layer that the admin panel manages content for
Need a custom admin panel for your project? This is one of the core things I build — CMS, CRM, lead inbox, agent panel, API vault. See my services or get in touch.
Get the free AI Prompt Pack + weekly frameworks
30+ tested prompts for images, captions, scripts & keywords, delivered instantly. Plus real insights on AI + marketing — no generic tips.
Want to implement this with guidance?
Santosh helps founders turn insights like this into real systems.
External Resources
Further Reading & Tools
Content Marketing Institute
Annual content marketing benchmarks — budgets, channels, and outcomes
HubSpot Marketing Blog
Data-driven marketing research, inbound strategy, and content guides
Semrush Blog
SEO, content, and digital marketing research and strategy guides
Marketing Week
UK's leading marketing news, strategy insight, and industry research