Skip to main content
Tutorial

How I Build Internal Admin Dashboards Without Third-Party Tools

5 min read

How to build a custom admin dashboard with Next.js and Prisma without third-party tools

Next.jsPrismaadmin dashboardTypeScriptUAE tech

Last month, a real estate client in Abu Dhabi asked for an admin dashboard that could manage 10k+ property listings in both Arabic and English. Their previous dashboard (built with a bloated third-party template) had become a maintenance nightmare. I rebuilt it from scratch using Next.js, Prisma, and custom components. Took 3 weeks. No UI kits, no paid tools. Just vanilla code and a clear plan.

Let me walk through how I structure these projects without relying on expensive templates or drag-and-drop builders.

Why I Stopped Using Third-Party Admin Templates

My last Laravel project in Dubai used a $500 admin theme. It looked great, but:

  • Half its JS dependencies broke when PHP 8.3 dropped
  • Customizing its routing for Arabic language switches meant 3 days of hacks
  • The client couldn't touch the codebase afterward

Now I avoid third-party tools for internal dashboards. Yes, it's more work upfront, but:

  • Zero dependency bloat
  • 100% control over code quality
  • Easier to train a client's team on clean, explicit patterns

I'm not against libraries – we use next-auth.js and react-table – but core dashboard architecture is always custom.

Data Modeling: Starting with Prisma

Every dashboard starts with the data. For a UAE e-commerce client, I mapped their order flows in Prisma before writing any frontend code.

The schema looks like this in Prisma 5.0:

prisma
model Order {
  id         String   @id @default(cuid())
  status     String   @default("pending") // "processing", "delivered", "cancelled"
  items      Json
  createdAt  DateTime @default(now())
  updatedAt  DateTime @updatedAt
}

This simple model powers the whole order management section. Prisma Studio helps me visualize it during development – no separate admin panel needed.

One mistake I made: Adding a JSON column for order items early on seemed flexible. But when the client wanted search-by-product-name functionality 2 months in, I had to migrate to a proper Product model. Learn from me: denormalize data only when you absolutely need performance gains.

Caching Data in Next.js

I use the App Router’s fetch caching by default but override it for dynamic dashboard filters:

ts
async function getOrders(filter: string) {
  const response = await fetch(`/api/orders?status=${filter}`, {
    cache: 'no-cache', 
  });
  return response.json();
}

This prevents stale data from showing after urgent admin actions. For read-heavy pages like statistics charts, I stick with cache: 'force-cache' – it reduced API calls by 70% for a logistics client in Sharjah.

Building UI Components from Scratch

I use Tailwind CSS but skip component libraries. For a limo booking dashboard I built in 2024 (Tawasul Limo), the team needed real-time ride tracking in both RTL and LTR layouts.

The solution:

  1. Create layout wrappers for language direction
  2. Style buttons manually using Tailwind classes
  3. Reuse a single Table component across all dashboards
tsx
function DashboardTable({ data, columns }) {
  // React-table implementation here
}

Yes, it took longer than using a UI kit. But now I have a component that:

  • Handles right-to-left text properly
  • Works with any Prisma model
  • Doesn’t force clients to pay for licenses

Authentication & Role Management

For a Dubai fintech startup, I built role-based access using Next.js app directory patterns:

/app  
  /admin  
    /dashboard  
    /users  
  /api  
    /auth  

Middleware checks roles against a database field:

ts
async function checkUserRole(request) {
  const user = await getCurrentUser();
  if (!user.permissions.includes('admin')) {
    redirect('/unauthorized');
  }
}

They wanted granular permissions (like "can_edit_pricing" flags), so I stored role rules in a JSON column. Wasn’t perfect – JSON searches in PostgreSQL can be slow – but it worked well enough for their 200-user dashboard.

Handling Arabic Language Support

Any dashboard for GCC clients needs bidirectional text handling. For Reach Home Properties, I stored strings in Arabic/English pairs in the database:

json
{
  "en": "Property added successfully",
  "ar": "تم إضافة العقار بنجاح"
}

Frontend displays the correct version using a locale helper:

ts
function t(key: string) {
  const lang = useLocalStorage('language', 'en');
  return translations[key][lang.value];
}

But right-to-left forms are tricky. For dates and currency inputs in Arabic, I used react-hook-form with custom RTL formatting – took 2 whole days to make dropdown arrows and text alignment look right.

Deployment and Maintenance

All my dashboards deploy on Vercel with PostgreSQL hosted on Neon. For larger UAE enterprise clients (like a corporate site I built for DAS Holding), I include:

  1. Daily database backups via Neon’s branching
  2. GitHub Actions for staging deployments
  3. Simple monitoring with Vercel logs and Sentry

Maintenance is where third-party tools usually break. One government client had 26 dashboard filters built with a UI library – when a major React update broke their codebase, fixing it cost them 10 dev days. With custom dashboards, you know exactly what will break where.

Frequently Asked Questions

Why not use tools like Retool or Supabase for internal dashboards?

They're great for prototypes, but for production use with complex auth/business rules, they get expensive and restrictive. Last year I built a Supabase dashboard for a UAE logistics company – they paid $500/month to exceed row limits. Custom dashboards on Neon cost them 1/10th that.

How do you handle performance with large datasets?

Prisma pagination. For a client with 200k orders, we implemented cursor-based pagination using skip and take with indexed database fields. Response time went from 6s to 0.3s.

What’s your stack for real-time features?

For stock management dashboards, I use Pusher with Laravel broadcasting and React Query for live updates. Pusher costs money, but it’s worth it for real-time data – unlike custom WebSocket implementations that take longer and have edge cases.

Can you use the same codebase for both admin and public dashboards?

Yes. At a high level, the architecture is the same. For a hotel booking platform, the admin and customer-facing dashboards shared the same Prisma ORM and auth logic – just different UI layers built with Next.js slots.

If you're building or rebuilding an admin dashboard and want to avoid third-party bloat, I’ve done this 40+ times for UAE and GCC clients. Let’s talk – book a free consultation to walk through your requirements.

Most of my clients come to me stuck with unscalable templates or broken dependencies. I help them build something that lasts 3-5 years without rewrite cycles.

S

Sarah

Senior Full-Stack Developer & PMP-Certified Project Lead — Abu Dhabi, UAE

7+ years building web applications for UAE & GCC businesses. Specialising in Laravel, Next.js, and Arabic RTL development.

Work with Sarah