DEV Community

Cover image for I built a production ready NEXT.JS Boilerplate so you dont have to!
Salman Shahriar
Salman Shahriar

Posted on • Edited on

I built a production ready NEXT.JS Boilerplate so you dont have to!

Every time I started a new Next.js project, I lost the first week to setup.

Authentication. Internationalization. Role-based access. SEO meta tags. Environment validation. Error monitoring. Linting. Testing. CI pipelines.

By the time I had a working foundation, the excitement was gone, buried under config files and boilerplate glue code.

After doing this across multiple SaaS projects, I stopped and asked myself: What if I built the foundation once, properly, and never had to do it again?

So I did. Then I rebuilt it from scratch with a better architecture.

The result is Nextjs-Elite-Boilerplate: a production-ready, frontend-first Next.js 16 starter kit that's completely open source.

🔗 Live Demo · 📦 GitHub Repo · 🚀 Use This Template · Deploy on Vercel

Next.js Elite Boilerplate: homepage and feature overview


Table of Contents

  1. Why Another Boilerplate?
  2. What Makes This One Different
  3. The Full Feature Breakdown
  4. Lighthouse? All 100s.
  5. Getting Started in 5 Minutes
  6. The Project Structure (For Humans)
  7. Everything You Get Out of the Box
  8. Who Should Use This (and Who Shouldn't)
  9. Contributing
  10. Final Thoughts

Why Another Boilerplate?

I know what you're thinking. The world doesn't need another Next.js starter.

Honestly? Most of the time, you'd be right. Most starters fall into two camps:

  1. Too bare. A create-next-app with a theme toggle and a "TODO: add auth here" comment.
  2. Too opinionated. Ships with a Prisma schema, a specific database, and an ORM you didn't ask for, tightly coupling you to decisions you haven't made yet.

I wanted something in between: a frontend-first foundation that handles auth, roles, i18n, SEO, forms, data fetching, error monitoring, and developer tooling, but doesn't force a database on you. You bring your own API (REST, GraphQL, BFF, whatever), and this boilerplate handles everything else.

That's what Next.js Elite is. And it's free, MIT-licensed, and open source.


What Makes This One Different

Here's what you get with a single git clone:

  • Next.js 16 + React 19 with App Router and Server Components
  • BetterAuth with email/password, Google OAuth, and Upstash Redis sessions
  • Permission-based RBAC using parallel routes (@admin, @user)
  • Type-safe i18n via next-intl: 6 languages, RTL, cookie-based locale, compile-time checked keys
  • T3 Env for Zod-validated environment variables (server + client split)
  • TanStack Query + ofetch for API data fetching with caching
  • React Hook Form + Zod for forms with shared validation schemas
  • Sentry for error monitoring, pino for server logging
  • Storybook 10 for isolated component development
  • Vitest + Playwright for unit and E2E testing
  • Lefthook + Commitlint + Knip for automated code quality
  • One JSON file drives all SEO, sitemap, robots.txt, and manifest config
  • Docker + Vercel deployment ready

And the Lighthouse scores? Well...


Lighthouse? All 100s.

This isn't just "good enough for a starter." The boilerplate scores 100 across all four Lighthouse categories: Performance, Accessibility, Best Practices, and SEO, right out of the box.

Lighthouse report showing perfect 100 scores in Performance, Accessibility, Best Practices, and SEO

No tricks. No deferred audits. That's the production build, tested against the live demo at nextjs-elite-boilerplate.vercel.app.

Most boilerplates treat performance as an afterthought. Here, it's baked in from day one: server components by default, client components only where needed, zero layout shift, semantic HTML, proper heading hierarchy, and optimized asset loading.


The Full Feature Breakdown

Let's walk through every major system. I'll cover what it does, why I chose it, and how it works.

Authentication: BetterAuth + Upstash Redis

I originally built this with NextAuth. It worked, but I hit limitations around serverless session persistence and flexibility. So I migrated to BetterAuth.

Here's what the auth system gives you:

  • Email/password sign-up and login: works immediately
  • Google OAuth: flip one env var to enable: NEXT_PUBLIC_GOOGLE_AUTH_ENABLED=true
  • Serverless sessions: uses Upstash Redis in production, falls back to in-memory for local dev
  • Admin role mapping: list admin emails in AUTH_ADMIN_EMAILS and they get elevated permissions automatically

There's also a demo mode: a self-contained module at src/features/auth/demo/ that adds click-to-fill credentials and auto-registers seed accounts. Set NEXT_PUBLIC_DEMO_MODE=true and you get instant test users:

Role Email Password
User user@test.com 12345678
Admin admin@test.com 12345678

Going to production? Set the flag to false, or just delete the demo/ folder. Nothing else in the codebase depends on it.

RBAC: Permissions, Not Just Roles

Most boilerplates give you if (role === 'admin') checks scattered across your code. That doesn't scale.

Next.js Elite uses permission-based RBAC. Each role maps to a set of permissions, and your pages check for specific permissions, not raw role strings:

// This is all you need in a Server Component
import { requirePermission } from '@/features/auth/rbac/require';

const AdminDashboardPage = async () => {
  const user = await requirePermission('dashboard.view:admin');
  return <h1>Welcome back, {user.email}</h1>;
};
Enter fullscreen mode Exit fullscreen mode

Invalid sessions redirect to /login. Insufficient permissions redirect to /unauthorized. No conditionals in your page components.

The routing layer uses Next.js 16 parallel routes to keep things clean:

src/app/(protected)/
  @admin/dashboard/    → Admin sees this
  @user/dashboard/     → Regular users see this
  layout.tsx           → Picks the right slot based on permissions
Enter fullscreen mode Exit fullscreen mode

Want to add a moderator role? Three steps:

  1. Add it to the UserRole union in rbac/permissions.ts
  2. Map its permissions in rbac/roles.ts
  3. Optionally create a @moderator/ parallel route

That's it. No refactoring.

Internationalization: next-intl with Type Safety

I used to roll custom i18n. It worked until it didn't: missing keys in production, no RTL support, locale scattered across URL prefixes.

The boilerplate uses next-intl with:

  • Cookie-based locale: no /en/ or /fr/ cluttering your URLs
  • 6 languages out of the box: English, বাংলা, العربية (with full RTL), Français, Español, 简体中文
  • Compile-time type checking: t("navigation.home") autocompletes, and typos break the build, not production

Translation files live in messages/. Adding a new language is two steps: add it to site.config.json, create messages/<locale>.json. The runtime handles the rest.

SEO: One Config File

SEO in most projects means hunting down metadata across five different files. Here, it's a single source of truth: src/features/site/site.config.json.

That one file drives:

  • Open Graph and Twitter Card meta tags
  • JSON-LD structured data (Organization + WebSite schemas)
  • Language alternates for multilingual SEO
  • Dynamic sitemap generation
  • robots.txt
  • PWA web app manifest
  • Canonical URLs

The config is validated by a Zod schema at build time. Typo in a field name? The build fails with a clear error, not a silent SEO regression you discover months later.

{
  "appName": "My SaaS",
  "domain": "https://mysaas.com",
  "title": "My SaaS — Do X Better",
  "description": "We help Y achieve Z.",
  "organization": {
    "name": "My Company",
    "url": "https://mysaas.com"
  },
  "images": { "og": "/og-image.webp" }
}
Enter fullscreen mode Exit fullscreen mode

Data Fetching: ofetch + TanStack Query

The API layer is built on ofetch (typed HTTP) and TanStack Query (caching, retries, server-state). The boilerplate includes a fully worked users feature you can copy as a starting point:

import { useQuery } from '@tanstack/react-query';
import { getUsers } from '@/features/users/api';

const { data, isLoading } = useQuery({
  queryKey: ['users', { page: 1 }],
  queryFn: () => getUsers({ page: 1 }),
});
Enter fullscreen mode Exit fullscreen mode

Forms: React Hook Form + Zod

Every form uses React Hook Form with Zod resolvers. Validation schemas are shared between client and server, so you define validation once and use it everywhere:

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { loginSchema, type LoginInput } from '@/features/auth/schemas/login';

const form = useForm<LoginInput>({
  resolver: zodResolver(loginSchema),
  defaultValues: { email: '', password: '' },
});
Enter fullscreen mode Exit fullscreen mode

Environment Variables: T3 Env

No more .env typos silently breaking production. @t3-oss/env-nextjs + Zod validates every environment variable at build time with a clean server/client split. Missing a required secret? The build tells you immediately.

UI: shadcn/ui + Tailwind CSS v4

The component layer uses shadcn/ui (Radix + CVA + Tailwind CSS v4). Components are copy-and-own, no hidden dependency tree. Dark mode is handled by next-themes with system detection and a manual toggle.

Observability: Sentry + pino + Rate Limiting

  • Sentry is wired into both server (instrumentation.ts) and client (instrumentation-client.ts). Drop in your DSN and you have production error tracking.
  • pino handles structured server logging with pretty output in dev.
  • @upstash/ratelimit helpers are ready for protecting your route handlers.

Testing: Vitest + Playwright

  • Unit tests: Vitest + React Testing Library. Specs live in tests/.
  • E2E tests: Playwright in e2e/. Run npm run e2e and the dev server starts automatically.
  • Coverage: npm run test:coverage with V8 coverage reports.

Developer Experience: The Full Pipeline

Most boilerplates stop at "ESLint + Prettier." This one goes further:

  • Lefthook: auto-lint and format on pre-commit
  • Commitlint: enforces Conventional Commits
  • Knip: flags unused files, exports, and dependencies
  • Storybook 10: isolated component dev on :6006
  • Renovate: automates dependency updates
  • GitHub Actions CI: typecheck → lint → knip → test → build on every push

Getting Started in 5 Minutes

Prerequisites: Node.js 20.9+, and your preferred package manager (npm/pnpm/yarn/bun).

1. Clone and install

git clone https://github.com/salmanshahriar/Nextjs-Elite-Boilerplate.git
cd Nextjs-Elite-Boilerplate
npm install
Enter fullscreen mode Exit fullscreen mode

2. Set up environment

cp .env.example .env
Enter fullscreen mode Exit fullscreen mode

The .env.example file documents every variable. Key ones:

  • BETTER_AUTH_SECRET: required in production (32+ chars). Generate with openssl rand -base64 32
  • BETTER_AUTH_URL: optional, auto-derived on Vercel
  • NEXT_PUBLIC_GOOGLE_AUTH_ENABLED=true + Google credentials for OAuth
  • NEXT_PUBLIC_DEMO_MODE=true for instant test accounts
  • SKIP_ENV_VALIDATION=true for CI/Docker builds where secrets aren't available yet

3. Brand it

Edit src/features/site/site.config.json: app name, domain, SEO, social links, organization details. One file, Zod-validated at build time.

4. Add languages (optional)

Add the locale to site.config.json, create messages/<locale>.json, done. The next-intl runtime picks it up automatically.

5. Run

npm run dev
Enter fullscreen mode Exit fullscreen mode

Open http://localhost:3000. You're live.

All available scripts

Command What it does
npm run dev Dev server (Turbopack)
npm run build Production build
npm run start Production server
npm run analyze Bundle analysis (@next/bundle-analyzer)
npm run typecheck tsc --noEmit
npm run lint ESLint + Prettier check
npm run lint:fix Auto-fix lint + format
npm run format Prettier check
npm run format:fix Prettier write
npm run knip Dead code/dependency detection
npm run check Full CI gate (typecheck + lint + knip + test)
npm run test Vitest run
npm run test:watch Vitest watch mode
npm run test:coverage Vitest with V8 coverage
npm run e2e Playwright E2E
npm run e2e:ui Playwright UI mode
npm run e2e:webkit WebKit-only E2E
npm run storybook Storybook on :6006
npm run storybook:build Static Storybook export

Deploy

Vercel (one click):

Deploy with Vercel

Docker:

docker build -t nextjs-elite .
docker run --rm --env-file .env -p 3000:3000 nextjs-elite
# or: docker compose up --build
Enter fullscreen mode Exit fullscreen mode

The Project Structure (For Humans)

The codebase uses a feature-sliced architecture. Each feature owns its components, hooks, schemas, and server logic. Cross-cutting infrastructure lives separately in libs/.

.
├── .github/workflows/        CI pipelines
├── e2e/                      Playwright E2E specs
├── messages/                 Translation files (en, bn, ar, fr, es, zh)
├── src/
│   ├── app/                  Next.js App Router
│   │   ├── (auth)/           Login & registration
│   │   ├── (public)/         Marketing pages
│   │   ├── (protected)/      Auth-gated area
│   │   │   ├── @admin/       Admin dashboard slot
│   │   │   ├── @user/        User dashboard slot
│   │   │   └── layout.tsx    Permission-based slot picker
│   │   ├── api/              Route handlers (auth, health)
│   │   ├── layout.tsx        Root layout + SEO
│   │   ├── providers.tsx     Theme + Auth + Query providers
│   │   ├── manifest.ts       PWA manifest
│   │   ├── robots.ts         robots.txt
│   │   └── sitemap.ts        Dynamic sitemap
│   ├── components/
│   │   ├── shared/           App-level UI (logo, hero)
│   │   ├── icons/            Icon components
│   │   └── ui/               shadcn/ui primitives
│   ├── features/
│   │   ├── auth/             BetterAuth, RBAC, demo mode
│   │   ├── i18n/             next-intl config
│   │   ├── navigation/       Header + Sidebar
│   │   ├── site/             Site config + utilities
│   │   ├── theme/            Theme provider + toggle
│   │   └── users/            Example feature (copy this!)
│   ├── hooks/                Cross-feature hooks
│   ├── libs/                 Infra: env, logger, API client, rate-limit
│   ├── schemas/              Shared Zod schemas
│   ├── instrumentation.ts    Sentry (server)
│   └── instrumentation-client.ts  Sentry (client)
├── tests/                    Vitest specs
├── proxy.ts                  Middleware
├── lefthook.yml              Git hooks
├── commitlint.config.js      Conventional Commits
├── knip.json                 Dead-code config
├── playwright.config.ts
└── vitest.config.ts
Enter fullscreen mode Exit fullscreen mode

Key conventions:

  • features/<name>/: vertical slices. Everything a feature needs lives here.
  • libs/: cross-cutting infra (env, logger, API client). No business logic.
  • components/ui/: shadcn/ui primitives. Copy and extend, don't edit in place.
  • schemas/: shared Zod schemas used across multiple features.

Everything You Get Out of the Box

✅ Next.js 16 + React 19 (App Router, Server Components)
✅ TypeScript 5.9 (strict mode)
✅ Tailwind CSS v4
✅ BetterAuth (email/password + Google OAuth + Redis sessions)
✅ Permission-based RBAC with parallel routes
✅ next-intl (6 languages, RTL, type-safe, cookie-based)
✅ T3 Env (Zod-validated server + client env vars)
✅ TanStack Query + ofetch (API layer with caching)
✅ React Hook Form + Zod (forms with shared validation)
✅ SEO suite (OG, Twitter Cards, JSON-LD, sitemap, robots, manifest)
✅ next-themes (dark mode with system detection)
✅ shadcn/ui (Radix + CVA + Tailwind)
✅ Sentry (server + client error monitoring)
✅ pino (structured server logging)
✅ Upstash rate limiting
✅ Storybook 10
✅ Vitest + React Testing Library
✅ Playwright E2E
✅ Lefthook + Commitlint (git hooks + conventional commits)
✅ Knip (dead-code hygiene)
✅ ESLint + Prettier (Next.js, TS, Tailwind, a11y)
✅ GitHub Actions CI
✅ Docker + Docker Compose
✅ Demo mode (self-contained seed accounts)
✅ Health check (GET /api/health)
✅ Renovate (automated dependency updates)
✅ Vercel one-click deploy


Who Should Use This (and Who Shouldn't)

This is a good fit if you're building:

  • A SaaS product with multiple user roles
  • An internationalized app (especially with RTL requirements)
  • A frontend that consumes an existing API or BFF
  • An enterprise app that needs auth, RBAC, and observability from day one

Probably not the right choice for:

  • A single-page landing site (this is more than you need)
  • An app that requires a tightly-coupled database layer (this is intentionally API-only, bring your own backend)

Contributing

The project is fully open source and contributions are welcome:

  1. Fork and branch from main (feat/..., fix/...)
  2. Run npm run check: it must pass
  3. Use Conventional Commits (Lefthook enforces this)
  4. Open a PR with a clear description

🐛 Report a bug · ⭐ Star on GitHub · 🤝 Submit a PR


Final Thoughts

I built the first version because I was tired of repeating myself. Then I tore it apart and rebuilt it with a feature-sliced architecture, migrated to BetterAuth, added type-safe everything (env vars, i18n keys, form schemas), and wired up a complete DX pipeline with Sentry, Storybook, Lefthook, and Knip.

The goal was never to build the biggest starter kit. It was to build the one I actually want to use on day one of every project, and still be glad I chose on day 100.

If it saves you a few hours of setup time, it was worth it.

What's your biggest pain point when starting a new Next.js project? Drop a comment. I'm always looking for ways to make this better.

Happy building. 🚀


🔗 Live Demo · 📦 GitHub · 🚀 Use Template · Deploy on Vercel

Top comments (22)

Collapse
 
jtorchia profile image
Juan Torchia

50 hours is an honest number — most boilerplate authors underestimate the invisible cost of the glue layer (auth callbacks, RBAC middleware, i18n routing edge cases). One thing I'd push on: how does the RBAC model handle permission inheritance vs. flat role assignment? In my experience that's the first thing that breaks when a real client asks for 'editor who can publish but only their own content'. The difference between a boilerplate that ships fast and one that survives the first feature request is usually that one decision.

Collapse
 
salmanshahriar profile image
Salman Shahriar

Great point!
and you’re exactly right that RBAC inheritance is where “simple boilerplate auth” usually collapses.

In this boilerplate, the model is intentionally flat role assignment + explicit permission checks, with ownership-aware rules layered in policy helpers (for cases like “publish own only”). That keeps the base predictable, but it does mean inheritance trees (e.g. admin > editor > author) are not first-class by default.

Collapse
 
anni profile image
Anietie Brownson

This is awesome
Good work

Collapse
 
salmanshahriar profile image
Salman Shahriar

Thanks man ‼️

Collapse
 
samihamahin profile image
Samiha Muntaha Mahin

Thats amazingg

Collapse
 
salmanshahriar profile image
Salman Shahriar

Thanks ‼️

Collapse
 
fahad_alikhan_5ec98c68a2 profile image
Fahad Ali Khan

Nice simple design. I'll surely use it in the future.

Collapse
 
salmanshahriar profile image
Salman Shahriar

❤️❤️

Collapse
 
sharafat_hossain_3dcc1f75 profile image
Sharafat Hossain

Mad respect man

Collapse
 
salmanshahriar profile image
Salman Shahriar

Thanks‼️

Collapse
 
leob profile image
leob

Nice! Bookmarked, and kept for "whenever I need it"

Collapse
 
salmanshahriar profile image
Salman Shahriar

Thanks, man! Feel free to share any suggestions anytime! ❤️

Collapse
 
sadi_nahin_5b099dbb050907 profile image
Sadi Nahin

Coolest shit, needed this!

Collapse
 
salmanshahriar profile image
Salman Shahriar

Thanks, man! Feel free to share any suggestions anytime! ❤️

Collapse
 
popy_chan_7f62c449a0c66c2 profile image
popy chan

damn! Good Work brother.

Collapse
 
salmanshahriar profile image
Salman Shahriar

thanks!

Collapse
 
joey_tribbiani_4771602dc5 profile image
Joey Tribbiani

Thanks for this blog.

Collapse
 
salmanshahriar profile image
Salman Shahriar • Edited

How you DOINNNN xD

Some comments may only be visible to logged-in visitors. Sign in to view all comments.