<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Salman Shahriar</title>
    <description>The latest articles on DEV Community by Salman Shahriar (@salmanshahriar).</description>
    <link>https://dev.to/salmanshahriar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1951722%2F6c136fda-088e-4813-ba06-de1af03134ea.jpeg</url>
      <title>DEV Community: Salman Shahriar</title>
      <link>https://dev.to/salmanshahriar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/salmanshahriar"/>
    <language>en</language>
    <item>
      <title>Next.js Best Practices in 2026: Why I Built Next-Elite</title>
      <dc:creator>Salman Shahriar</dc:creator>
      <pubDate>Tue, 01 Sep 2026 02:55:24 +0000</pubDate>
      <link>https://dev.to/salmanshahriar/nextjs-best-practices-in-2026-why-i-built-next-elite-24km</link>
      <guid>https://dev.to/salmanshahriar/nextjs-best-practices-in-2026-why-i-built-next-elite-24km</guid>
      <description>&lt;p&gt;Every serious Next.js project starts with the same fifteen things that aren't the product: auth, layouts, permissions, env validation, an API client, i18n, UI primitives, SEO, tests, linting, formatting, Docker, CI, error tracking, analytics.&lt;/p&gt;

&lt;p&gt;Before I built &lt;a href="https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;Next Elite&lt;/a&gt;, I did what most people do first: I looked at what already existed. The official starter, the popular free kits, the paid ones. Some of them are genuinely excellent at what they set out to do. None of them fit the specific shape of project I kept building, a role-based SaaS dashboard sitting in front of a backend I don't own, shipped in more than one language.&lt;/p&gt;

&lt;p&gt;This post walks through that landscape as it stood in 2026, and then makes the actual case for why Next-Elite is the one I'd hand a developer starting that kind of project today. Not "best" in the abstract. Best for that.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What "best" should mean for a 2026 boilerplate&lt;/li&gt;
&lt;li&gt;The 2026 landscape, honestly&lt;/li&gt;
&lt;li&gt;Where the gap is&lt;/li&gt;
&lt;li&gt;Why Next-Elite fills it&lt;/li&gt;
&lt;li&gt;Feature walkthrough&lt;/li&gt;
&lt;li&gt;Where Next-Elite is not the answer&lt;/li&gt;
&lt;li&gt;Why now, specifically&lt;/li&gt;
&lt;li&gt;Get started&lt;/li&gt;
&lt;/ol&gt;




&lt;h2 id="what-best-means"&gt;1. What "best" should mean for a 2026 boilerplate&lt;/h2&gt;

&lt;p&gt;"Best Next.js boilerplate" is a search query with hundreds of contradictory answers, because nobody agrees on what's being optimized for. A boilerplate that's best for a solo founder shipping a $20/month tool in a weekend is a bad fit for a team shipping a multi-role SaaS dashboard, and vice versa. So before arguing for anything, here's the criteria I actually think matter in 2026:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Current stack, not last cycle's.&lt;/strong&gt; Next.js 16 stabilized Turbopack and shipped React 19.2 with real architectural changes underneath (Cache Components, View Transitions). A boilerplate still pinned to Next.js 14 patterns is teaching you yesterday's defaults.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architectural fit, not architectural maximalism.&lt;/strong&gt; The best boilerplate isn't the one with the most integrations, it's the one whose assumptions match your project's shape. A kit that bundles Prisma and Postgres is the right answer for a project that wants Next.js to be the whole backend, and the wrong answer for one that already has a backend team.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security that lives in the right place.&lt;/strong&gt; 2025's CVE-2025-29927 let attackers skip Next.js middleware entirely with a crafted header, bypassing any auth check that lived only there. A boilerplate built after that lesson should enforce authorization server-side, in Server Components and Route Handlers, not lean on middleware as the only gate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;i18n as a first-class citizen, not an afterthought.&lt;/strong&gt; Most boilerplates are English-only by default. If your product will ever ship in more than one market, retrofitting i18n later is a much bigger job than building on it from day one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tooling that respects your time.&lt;/strong&gt; Linting and formatting on a large codebase with ESLint alone routinely takes 30 to 60 seconds; Rust-based tooling like Oxlint runs the same checks in a fraction of that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost matching the license.&lt;/strong&gt; Free-and-open-source is not automatically better than paid, a $199 to $649 one-time SaaS kit that saves you weeks of Stripe and email wiring is a fair trade for a lot of teams. But it should be a deliberate choice, not the only option on the table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Judged on those six criteria, here's how the landscape actually looks.&lt;/p&gt;




&lt;h2 id="landscape"&gt;2. The 2026 landscape, honestly&lt;/h2&gt;

&lt;p&gt;I'm not going to pretend the alternatives are bad. They're built for different jobs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The official Next.js SaaS Starter&lt;/strong&gt;, maintained by the Next.js team itself, is free, MIT-licensed, and demonstrates the framework's own current best practices. It ships Postgres and Stripe subscriptions with shadcn/ui. It's intentionally minimal: no built-in RBAC, no i18n, no admin dashboard beyond the basics. It's the best free starting point if you want clean foundations and don't mind building the last 40% yourself, which is exactly what it's designed for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;create-t3-app&lt;/strong&gt; scaffolds a typesafe full-stack app from modular pieces, TypeScript, tRPC, Prisma or Drizzle, NextAuth, Tailwind. It's excellent for learning the typesafe-stack pattern and for smaller full-stack apps where Next.js owns the database. It isn't trying to be a role-based SaaS dashboard kit, and doesn't claim to be.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ixartz's Next.js Boilerplate&lt;/strong&gt; is the community heavyweight in the free tier: auth, multi-tenancy, roles and permissions, i18n, database migrations, a full Vitest + Playwright testing suite, all MIT-licensed. It's a serious, well-maintained project and a completely reasonable choice if you want the database and multi-tenancy bundled in from the start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Paid kits like ShipFast and MakerKit&lt;/strong&gt; solve a different problem: speed to a sellable product. ShipFast bundles Stripe payments, transactional email, and a blog for a one-time fee, straightforward, well-documented, no surprises. MakerKit goes further with a Turborepo monorepo, team accounts, and enterprise features, aimed at teams who'll pay for that scaffolding rather than build it. Building an equivalent foundation from scratch, auth, billing, multi-tenancy, a marketing site, has been estimated at somewhere around $7,500 to $12,000 in developer time, which is exactly the math that makes a $200 to $650 one-time kit an easy yes for a lot of founders.&lt;/p&gt;

&lt;p&gt;None of this is a case against any of them. It's the honest starting point for the actual question: what's missing.&lt;/p&gt;




&lt;h2 id="the-gap"&gt;3. Where the gap is&lt;/h2&gt;

&lt;p&gt;Every option above makes the same underlying assumption in one direction or another: either Next.js owns the database (the official starter, T3, ixartz, the paid kits), or you're building something small enough that architecture doesn't matter yet.&lt;/p&gt;

&lt;p&gt;Almost none of them assume the opposite, common, situation: &lt;strong&gt;you already have a backend&lt;/strong&gt;, a Go service, a Laravel API, a BFF layer your platform team owns, and you need a frontend that's genuinely good at consuming it, with real role-based access control and real multi-language support, without dragging in a database layer you're going to rip out on day two.&lt;/p&gt;

&lt;p&gt;That's the specific gap Next-Elite is built for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6z7h0l9jymqw3e0x5dfq.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6z7h0l9jymqw3e0x5dfq.webp" alt="Next Elite home page" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2 id="why-next-elite"&gt;4. Why Next-Elite fills it&lt;/h2&gt;

&lt;p&gt;Here's the direct comparison, using the same six criteria from section 1:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Official Next.js Starter&lt;/th&gt;
&lt;th&gt;ixartz Boilerplate&lt;/th&gt;
&lt;th&gt;ShipFast / MakerKit&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Next-Elite&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Stack currency&lt;/td&gt;
&lt;td&gt;Current&lt;/td&gt;
&lt;td&gt;Current&lt;/td&gt;
&lt;td&gt;Current&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Next.js 16.4, React 19.3, TypeScript 7&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database assumption&lt;/td&gt;
&lt;td&gt;Postgres bundled&lt;/td&gt;
&lt;td&gt;Postgres/Drizzle bundled&lt;/td&gt;
&lt;td&gt;Bundled (Prisma/Postgres)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;None, API-driven by design&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RBAC&lt;/td&gt;
&lt;td&gt;Not included&lt;/td&gt;
&lt;td&gt;Roles &amp;amp; permissions&lt;/td&gt;
&lt;td&gt;Varies by tier&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Permission-based, server-enforced guards&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;i18n / RTL&lt;/td&gt;
&lt;td&gt;Not included&lt;/td&gt;
&lt;td&gt;Included (locales vary)&lt;/td&gt;
&lt;td&gt;Rare&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;6 languages, RTL, type-checked keys&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linting&lt;/td&gt;
&lt;td&gt;ESLint&lt;/td&gt;
&lt;td&gt;ESLint&lt;/td&gt;
&lt;td&gt;ESLint&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Oxlint + Oxfmt (dramatically faster)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Vitest + Playwright&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Vitest + Playwright, pre-wired&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License / cost&lt;/td&gt;
&lt;td&gt;Free (MIT)&lt;/td&gt;
&lt;td&gt;Free (MIT)&lt;/td&gt;
&lt;td&gt;$199 to $649 one-time&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Free (MIT)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Learning current Next.js patterns, small full-stack apps&lt;/td&gt;
&lt;td&gt;Full-stack SaaS that wants the DB bundled&lt;/td&gt;
&lt;td&gt;Fastest path to a sellable, DB-owning SaaS&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Multi-role, multi-language frontends sitting in front of an existing or external API&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The columns aren't competing to be "better" in general, they're solving different problems. Next-Elite's column is the one that exists specifically for "the backend isn't Next.js's job here."&lt;/p&gt;




&lt;h2 id="walkthrough"&gt;5. Feature walkthrough&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Auth and RBAC that enforce on the server.&lt;/strong&gt; BetterAuth handles email/password and Google OAuth. Authorization is separate and deliberate: &lt;code&gt;requireUser()&lt;/code&gt; and &lt;code&gt;requirePermission()&lt;/code&gt; run inside Server Components, and Next.js parallel routes (&lt;code&gt;@admin&lt;/code&gt;, &lt;code&gt;@user&lt;/code&gt;) mean role-specific dashboards (dashboard, analytics, profile, settings) don't need runtime branching in the render tree at all. This is the direct, practical answer to the CVE-2025-29927 lesson from section 1: the project has no middleware at all, so nothing security-critical can be skipped at the edge. Roles and their permissions live in one typed file, so a misspelled permission is a compile error. One thing to plan for: with no database configured, BetterAuth uses an in-memory store, which is perfect for the demo but loses users on restart, so connect a database adapter or your own backend's auth before going to production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AdminDashboardPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;requirePermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard.view:admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;getTranslations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard.admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmh838hztnd7ye66u8ci.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmh838hztnd7ye66u8ci.webp" alt="Next Elite split-pane auth layout" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;i18n that's actually type-safe.&lt;/strong&gt; Six languages, English, Bengali, Arabic (RTL), French, Spanish, Simplified Chinese, via next-intl, cookie-based so there's no &lt;code&gt;/en/&lt;/code&gt; URL prefix to manage. Translation keys are checked at compile time, so a typo'd key fails the build instead of silently rendering blank in production, and a unit test makes sure every locale has the same keys as English. RTL support in particular is something most of the boilerplates in section 2 simply don't ship; Next-Elite's layouts use logical start/end spacing so the same components work in both directions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend-first, API-driven architecture.&lt;/strong&gt; No Prisma, no Drizzle, no Postgres. TanStack Query is pre-configured in &lt;code&gt;providers.tsx&lt;/code&gt;, ready to point at your REST, GraphQL, or BFF endpoint. Drop it in front of whatever backend already exists. (If you want a matching backend, a companion template, &lt;a href="https://github.com/salmanshahriar/Next-Elite-Server" rel="noopener noreferrer"&gt;Next Elite Server&lt;/a&gt;, with NestJS, BetterAuth, Drizzle ORM, and PostgreSQL, is coming soon.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7wkydoi05cats7hqpckl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7wkydoi05cats7hqpckl.webp" alt="Next Elite role-based admin dashboard layout" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;50+ shadcn/ui components you own.&lt;/strong&gt; Built on Tailwind CSS v4 and Radix UI, including stat cards, charts, a sortable and paginated data table, a searchable combobox, and a date picker, with a live &lt;a href="https://nextelite.salmanshahriar.com/ui-components" rel="noopener noreferrer"&gt;&lt;code&gt;/ui-components&lt;/code&gt;&lt;/a&gt; showcase page. Every color and radius comes from light and dark design tokens, so rebranding or adjusting dark mode is a token change, not a find-and-replace. Because the components are code in your repo rather than an imported library, extending one (a new variant) doesn't mean waiting on someone else's release.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdng09lmb762j6uy9har2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdng09lmb762j6uy9har2.webp" alt="Next Elite 50+ custom and reusable UI components" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tooling that doesn't waste your CI minutes.&lt;/strong&gt; Oxlint and Oxfmt for linting and formatting, Knip for dead code, Lefthook wiring pre-commit, commit-msg, and pre-push hooks so problems get caught before they reach a PR, not during it. Dependencies are pinned to exact versions and kept current by Renovate and Dependabot. And because a lot of 2026 code is written with AI agents, the repo ships its conventions for them too: an &lt;code&gt;AGENTS.md&lt;/code&gt; and a &lt;code&gt;project-standards&lt;/code&gt; skill that tell Claude Code, Cursor, Codex and friends to reuse existing components, add variants instead of duplicates, and use design tokens only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing from the first commit.&lt;/strong&gt; Vitest and React Testing Library for units and components, Playwright for the handful of end-to-end flows that matter (including checking that the security headers are actually sent), &lt;code&gt;npm run check&lt;/code&gt; as a single CI gate: typecheck, lint, dead code, tests. CI also deletes the demo code on every push and runs the checks again, so &lt;code&gt;npm run demo:remove&lt;/code&gt; always leaves you a clean, working app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability, security, and deployment that aren't afterthoughts.&lt;/strong&gt; Sentry (lazy-loaded, and only when a DSN is set), Vercel Analytics (rendered only on Vercel), and a &lt;code&gt;/api/health&lt;/code&gt; endpoint. A strict Content Security Policy, HSTS, and frame protection are set in code. Standalone Docker output on a Distroless base image, with multi-arch builds (amd64/arm64) for self-hosting on ARM, Dokploy-ready, or one click to Vercel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance measured, not assumed.&lt;/strong&gt; I ran the Turbopack bundle analyzer on the project and moved everything that didn't need to be on every page off the first load: Sentry, the env validation library, and the charting library. That cut first-load JavaScript by 21–24% per page, and the live demo's total transfer went from 906 KB to 462 KB. The project's Lighthouse report shows 100 across Performance, Accessibility, Best Practices, and SEO, plus 3/3 on Agentic Browsing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2i8jcrrj3qd3h9w7bzwj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2i8jcrrj3qd3h9w7bzwj.webp" alt="Next Elite Lighthouse Report - 100 Performance, Accessibility, Best Practices, and SEO" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of it, MIT-licensed, free.&lt;/p&gt;




&lt;h2 id="not-for-everyone"&gt;6. Where Next-Elite is not the answer&lt;/h2&gt;

&lt;p&gt;An argument for "best for X" is only credible if it also says what it's not for.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You want the database bundled in.&lt;/strong&gt; If you want Next.js to be your whole backend, ixartz's boilerplate or the official Next.js SaaS Starter will serve you better than fighting Next-Elite's API-driven assumption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You want payments and billing pre-wired.&lt;/strong&gt; Next-Elite doesn't include Stripe. ShipFast or MakerKit will save you more time if billing is core to the MVP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your project is small enough that this is overkill.&lt;/strong&gt; A landing page or a weekend prototype doesn't need feature-based architecture, RBAC, or six languages. &lt;code&gt;create-next-app&lt;/code&gt; is the right answer there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need enterprise compliance features out of the box.&lt;/strong&gt; SOC 2 audit logging and SSO aren't in scope here; a kit like Bedrock exists specifically for that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need per-locale URLs for SEO.&lt;/strong&gt; Cookie-based i18n keeps routing simple, but if &lt;code&gt;/es/...&lt;/code&gt; pages must rank separately from &lt;code&gt;/en/...&lt;/code&gt; pages, you'll need a path-prefixed routing setup that Next-Elite doesn't ship.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If none of those describe your project, and it does involve multiple roles, more than one language, or a backend you don't want to duplicate inside your frontend, that's the project Next-Elite was built for.&lt;/p&gt;




&lt;h2 id="why-now"&gt;7. Why now, specifically&lt;/h2&gt;

&lt;p&gt;2026 is a reasonable moment to make this call, not an arbitrary one. Turbopack went stable as the default bundler in Next.js 16, React 19.2 shipped View Transitions and the Activity component underneath it, and the framework's own security posture keeps evolving in ways that reward architecture over reflexive middleware checks. A boilerplate built on last cycle's defaults isn't just missing features, it's teaching patterns the framework itself has moved past. Next-Elite is built on Next.js 16.4, React 19.3, and TypeScript 7 for that reason, not as a version-number flex, but because starting a 2026 project on 2024 patterns is a debt you pay down later.&lt;/p&gt;




&lt;h2 id="get-started"&gt;8. Get started&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/salmanshahriar/Next-Elite.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Next-Elite
npm &lt;span class="nb"&gt;install
cp&lt;/span&gt; .env.example .env
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:6767" rel="noopener noreferrer"&gt;http://localhost:6767&lt;/a&gt;. Auth, RBAC-gated dashboards, six languages, and everything above is already wired together. When you're ready to build your own product, run &lt;code&gt;npm run demo:remove&lt;/code&gt; and &lt;code&gt;npm run check&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://nextelite.salmanshahriar.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite/generate" rel="noopener noreferrer"&gt;Use This Template&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://vercel.com/new/clone?repository-url=https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;Deploy on Vercel&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If this is the project you keep rebuilding from scratch too, it's free, MIT-licensed, and a star helps more people find it.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Next.js Best Practices in 2026: The Boilerplate I Built So I Stop Repeating Myself</title>
      <dc:creator>Salman Shahriar</dc:creator>
      <pubDate>Tue, 01 Sep 2026 02:45:43 +0000</pubDate>
      <link>https://dev.to/salmanshahriar/nextjs-best-practices-in-2026-the-boilerplate-i-built-so-i-stop-repeating-myself-43ld</link>
      <guid>https://dev.to/salmanshahriar/nextjs-best-practices-in-2026-the-boilerplate-i-built-so-i-stop-repeating-myself-43ld</guid>
      <description>&lt;p&gt;Every serious Next.js project I start needs the same fifteen things before the actual product exists: authentication, layouts, permissions, environment validation, an API client, i18n, UI primitives, SEO metadata, tests, linting, formatting, Docker, CI, error tracking, analytics.&lt;/p&gt;

&lt;p&gt;None of that is the product. All of it has to exist before the product can ship.&lt;/p&gt;

&lt;p&gt;I kept rebuilding this foundation project after project, and each time I rebuilt it slightly differently, which meant relearning my own past decisions instead of improving on them. So I wrote down what "doing it right" actually means for a Next.js app in 2026, and then built that answer into an open-source boilerplate, &lt;a href="https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;Next Elite&lt;/a&gt;, so the decision only has to happen once.&lt;/p&gt;

&lt;p&gt;This post is that answer. It is not a features list. For each practice I'll explain the problem it solves, where developers disagree about it, and then show concretely how Next-Elite implements it, distinguishing clearly between "this is a 2026 best practice" and "this is a choice I made in my own boilerplate."&lt;/p&gt;

&lt;p&gt;If you never touch Next-Elite, the checklist at the end still works as a reference for starting a serious Next.js project in 2026.&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What "production-ready" actually means in 2026&lt;/li&gt;
&lt;li&gt;Start with architecture, not components&lt;/li&gt;
&lt;li&gt;Frontend-first and API-driven architecture&lt;/li&gt;
&lt;li&gt;Server Components vs Client Components&lt;/li&gt;
&lt;li&gt;Authentication is not authorization&lt;/li&gt;
&lt;li&gt;RBAC without scattering permission logic everywhere&lt;/li&gt;
&lt;li&gt;TypeScript should enforce architecture, not just describe it&lt;/li&gt;
&lt;li&gt;Type-safe internationalization&lt;/li&gt;
&lt;li&gt;UI architecture with Tailwind + shadcn/ui&lt;/li&gt;
&lt;li&gt;Data fetching: don't turn everything into React state&lt;/li&gt;
&lt;li&gt;Environment variables should fail safely&lt;/li&gt;
&lt;li&gt;SEO should be part of the architecture&lt;/li&gt;
&lt;li&gt;Performance should be a default, not a final optimization&lt;/li&gt;
&lt;li&gt;Testing strategy&lt;/li&gt;
&lt;li&gt;Code quality is an engineering system&lt;/li&gt;
&lt;li&gt;Observability from day one&lt;/li&gt;
&lt;li&gt;Docker and deployment should be boring&lt;/li&gt;
&lt;li&gt;What I intentionally did NOT include&lt;/li&gt;
&lt;li&gt;The trade-offs&lt;/li&gt;
&lt;li&gt;The actual boilerplate: Next Elite&lt;/li&gt;
&lt;li&gt;Final checklist: my 2026 Next.js project checklist&lt;/li&gt;
&lt;/ol&gt;




&lt;h2 id="production-ready"&gt;1. What "production-ready" actually means in 2026&lt;/h2&gt;

&lt;p&gt;"Production-ready" gets used as a synonym for "has TypeScript, Tailwind, and an auth library." That's not what it means. A project with all three of those can still fall over the first time two developers touch the same file, or the first time someone forgets to set an environment variable in a new deploy target.&lt;/p&gt;

&lt;p&gt;In practical terms, production readiness in 2026 means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Maintainability&lt;/strong&gt;: a new developer can find where a feature lives without a guided tour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type safety that extends past props&lt;/strong&gt;: config, permissions, translations, and API responses are typed, not just component inputs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable architecture&lt;/strong&gt;: the same kind of problem is always solved the same way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security boundaries that live on the server&lt;/strong&gt;: the UI can hide a button; only the server can actually deny a request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing at more than one layer&lt;/strong&gt;: unit, component, and end-to-end each catch a different class of bug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability before the incident&lt;/strong&gt;: error tracking and health checks exist before you need them, not after the first outage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A deployment story that doesn't force a rewrite&lt;/strong&gt;: whether that's Vercel or your own Docker host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance and SEO as defaults&lt;/strong&gt;, not a pre-launch checklist item.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these require exotic tools. Most of them require deciding early and enforcing the decision consistently, which is a cultural problem as much as a technical one.&lt;/p&gt;




&lt;h2 id="architecture"&gt;2. Start with architecture, not components&lt;/h2&gt;

&lt;p&gt;The default Next.js tutorial structure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
  components/
  hooks/
  utils/
  app/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works until it doesn't. Once a project has more than a handful of screens, "components" stops meaning anything: it holds unrelated UI for auth, billing, and settings side by side, and touching one feature means opening files scattered across four folders. Notably, Next.js's own documentation doesn't mandate a single structure; the framework explicitly supports colocating by route, splitting by feature, or keeping a flat top-level layout, and leaves the choice to the team. There is no "correct" Next.js folder structure handed down by the framework, which is exactly why so many teams land on the same fix independently: &lt;strong&gt;group code by feature, not by file type.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Next-Elite structures its domain logic under &lt;code&gt;src/features/&lt;/code&gt;, where each feature owns its own hooks, schemas, server helpers, and types:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/features/
├── auth/
│   ├── lib/          # BetterAuth server + auth-client singletons
│   ├── server/       # Server-only helpers (getCurrentUser)
│   ├── hooks/        # Auth provider + useAuth hook
│   ├── rbac/         # permissions, roles, can, require
│   ├── schemas/      # Zod login + register schemas
│   └── types.ts
├── i18n/              # next-intl config (routing, request, locale actions, RTL hook)
└── site/              # site.config.json, its schema, server-only base URL, locale helpers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shared, feature-agnostic UI still lives centrally, under &lt;code&gt;src/components/&lt;/code&gt; (&lt;code&gt;ui/&lt;/code&gt; primitives, &lt;code&gt;shared/&lt;/code&gt; app pieces, &lt;code&gt;layout/&lt;/code&gt; shell, &lt;code&gt;icons/&lt;/code&gt;), because forcing genuinely reusable building blocks into a feature folder just relocates the mess instead of solving it. The rule Next-Elite follows is: if it's about one feature, it lives in that feature's folder; if it's used by every feature, it's shared.&lt;/p&gt;

&lt;p&gt;Demo code gets the same treatment: the landing page, the component showcase, and the demo accounts all live in one &lt;code&gt;src/_demo(DELETE)/&lt;/code&gt; folder, and &lt;code&gt;npm run demo:remove&lt;/code&gt; deletes it and rewrites every file that referenced it. CI runs that removal on every push, so "delete the demo" never turns into an afternoon of chasing broken imports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When this is worth it:&lt;/strong&gt; SaaS apps with multiple roles, dashboards with several independent domains (billing, users, settings), or any project a second developer will touch in six months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When it's over-engineering:&lt;/strong&gt; a landing page, a five-screen MVP, or a prototype you'll throw away in a month. Feature folders for a project with one feature is just extra typing.&lt;/p&gt;




&lt;h2 id="api-driven"&gt;3. Frontend-first and API-driven architecture&lt;/h2&gt;

&lt;p&gt;This is the architectural decision Next-Elite is built around, and it's the one most likely to get pushback, so it deserves the most honest treatment.&lt;/p&gt;

&lt;p&gt;Most Next.js boilerplates assume the framework owns the whole stack: Prisma or Drizzle, a Postgres instance, an ORM schema tightly coupled to the UI. That's a completely reasonable choice for a small product where Next.js genuinely is the backend. It is a much worse fit the moment you already have a backend team, an existing service in Go or Laravel, or a plan to eventually ship a mobile client against the same API.&lt;/p&gt;

&lt;p&gt;Next-Elite deliberately does not own a database. It's built to sit on top of whatever you already have, REST, GraphQL, or a BFF layer, and treats TanStack Query as the seam between the frontend and that backend. The trade-off is explicit:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Frontend owns the DB (Next.js as full stack)&lt;/th&gt;
&lt;th&gt;Frontend is API-driven (Next-Elite's approach)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Solo builder, single client, fastest path to a working app&lt;/td&gt;
&lt;td&gt;Existing backend, multiple clients, a team that owns the API separately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Fewer moving parts, one deploy&lt;/td&gt;
&lt;td&gt;An API contract to define and maintain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk&lt;/td&gt;
&lt;td&gt;Frontend and backend rewrite together if you ever split them&lt;/td&gt;
&lt;td&gt;None, but you're doing more upfront wiring&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mobile/second client later&lt;/td&gt;
&lt;td&gt;Usually means duplicating backend logic&lt;/td&gt;
&lt;td&gt;Already speaks the same API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Neither option is "more architecturally correct." The mistake is picking the database-coupled path by default and discovering the coupling problem only after the product needs a second client or a separate backend team. Next-Elite's stance is: decide this on purpose, and if you decide you want the database bundled in, it isn't the right starting point for you, several other well-known Next.js starters (ones that ship Prisma, Postgres, and multi-tenancy out of the box) solve that problem well and are worth using instead. (For the backend side, I'm also building a companion template, &lt;a href="https://github.com/salmanshahriar/Next-Elite-Server" rel="noopener noreferrer"&gt;Next Elite Server&lt;/a&gt;, with NestJS, BetterAuth, Drizzle ORM, and PostgreSQL. It's coming soon.)&lt;/p&gt;




&lt;h2 id="server-vs-client"&gt;4. Server Components vs Client Components&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; default to Server Components for everything, and only add &lt;code&gt;'use client'&lt;/code&gt; at the smallest possible boundary, a button, a form, a toggle, not an entire page. Next.js 16's App Router still renders Server Components first; the client boundary is where interactivity, browser APIs, or local state actually live. This isn't a style preference so much as a bundle-size decision: every client component is JavaScript the browser has to download, parse, and hydrate, and the newer primitives React 19.2 introduced (View Transitions, &lt;code&gt;useEffectEvent&lt;/code&gt;, &lt;code&gt;&amp;lt;Activity&amp;gt;&lt;/code&gt;, shipped as part of the Next.js 16 line) all assume this server-first default rather than replacing it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; the request lifecycle is intentionally linear. A page renders as a Server Component first, &lt;code&gt;requireUser()&lt;/code&gt; / &lt;code&gt;requirePermission()&lt;/code&gt; check the session there, translations are resolved server-side via &lt;code&gt;next-intl&lt;/code&gt;, and only the interactive parts (forms, the theme toggle, the query-backed lists) cross into &lt;code&gt;'use client'&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TB
    User([User]) --&amp;gt; Page

    subgraph Server["Server (runs first)"]
        Page[Page / Layout]
        Guard["requireUser() / requirePermission()"]
        Page --&amp;gt; Guard
        Guard --&amp;gt;|reads session + role| Auth[BetterAuth]
    end

    subgraph Client["Client (runs in browser)"]
        Hook["useQuery (TanStack Query)"]
        Hook --&amp;gt;|fetch| Api["Your backend API"]
    end

    Page --&amp;gt;|sends HTML| User
    Page -.-&amp;gt;|interactive parts| Hook&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The practical rule Next-Elite's structure encodes: if a component needs &lt;code&gt;useState&lt;/code&gt;, an event handler, or a browser API, it's a client component. If it just needs data and permission, it stays on the server. The boundary also matters for &lt;em&gt;what crosses it&lt;/em&gt;: server-only values are passed down as props instead of imported into client code. For example, the "Google sign-in enabled" flag is read from the validated env on the server and handed to the auth provider, so the env validation library never ends up in the browser bundle.&lt;/p&gt;




&lt;h2 id="auth-vs-authz"&gt;5. Authentication is not authorization&lt;/h2&gt;

&lt;p&gt;These get conflated constantly, and the conflation is where security bugs come from.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt; answers: who are you?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization&lt;/strong&gt; answers: what are you allowed to do, now that I know who you are?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A login form is authentication. A dashboard that only admins can see is authorization. Treating "the user is logged in" as sufficient to gate an admin page is a common and avoidable mistake.&lt;/p&gt;

&lt;p&gt;There's also a sharper, more recent lesson here. In 2025, a critical Next.js vulnerability (CVE-2025-29927) let attackers send a specific header and skip middleware entirely, bypassing any authentication checks that lived only in middleware. The deeper lesson wasn't "patch your dependencies" (although do that too), it was architectural: &lt;strong&gt;middleware is not a security boundary.&lt;/strong&gt; It's an edge layer meant for routing and response shaping, not the last line of defense. Real authorization checks have to live in your Server Components, Route Handlers, and Server Actions, where they can't be skipped by a crafted request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; authenticate however fits your product (email/password, OAuth, passkeys), but authorize on the server, close to the data, every time, not once in middleware and never again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; authentication is BetterAuth, wired for email/password and Google OAuth through &lt;code&gt;/api/auth/*&lt;/code&gt; route handlers, with admin emails configurable via the server-only &lt;code&gt;AUTH_ADMIN_EMAILS&lt;/code&gt; variable. Authorization is separate and server-side, and the project has no middleware at all, so there's no edge layer to bypass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Server Component example&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;requirePermission&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/features/auth/rbac/require&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getTranslations&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-intl/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AdminDashboardPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;requirePermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard.view:admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;getTranslations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard.admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;AdminDashboardPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;requirePermission&lt;/code&gt; runs in the Server Component itself and redirects to &lt;code&gt;/login&lt;/code&gt; (no session) or &lt;code&gt;/unauthorized&lt;/code&gt; (no permission) before any protected content renders. One limitation to know before you deploy: with no database configured, BetterAuth falls back to its built-in in-memory store. That's ideal for the demo and local development, but users and sessions are lost on restart and aren't shared between server instances, so production needs a real database adapter (or auth pointed at your own backend). The project's production checklist calls this out explicitly.&lt;/p&gt;




&lt;h2 id="rbac"&gt;6. RBAC without scattering permission logic everywhere&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; roles and permissions should be defined in one place, checked through a small set of functions, and never re-implemented as ad hoc &lt;code&gt;if (user.role === 'admin')&lt;/code&gt; checks scattered through components. Scattered checks are how a permission gets forgotten on the one page nobody remembered to update.&lt;/p&gt;

&lt;p&gt;It's also worth being honest that RBAC is not always the right amount of complexity. A single-tenant internal tool with one kind of user needs an authentication check, full stop. RBAC earns its cost when a product has genuinely different classes of users with different capabilities, not by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; RBAC is deliberately simple, two roles (&lt;code&gt;user&lt;/code&gt;, &lt;code&gt;admin&lt;/code&gt;) with permission strings, checked through &lt;code&gt;requireUser()&lt;/code&gt; and &lt;code&gt;requirePermission()&lt;/code&gt; on the server, plus Next.js &lt;strong&gt;parallel routes&lt;/strong&gt; so role-specific layouts don't need runtime branching in the render tree at all. Both roles share the same URLs, and the layout mounts the right slot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/(protected)/
  ├── @admin/               # Admin slots (dashboard, analytics, profile, settings)
  ├── @user/                # User slots (dashboard, analytics, profile, settings)
  ├── unauthorized/         # Shown when a role lacks permission
  └── layout.tsx            # Picks slot based on permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a role is a three-step, explicit process: extend the &lt;code&gt;UserRole&lt;/code&gt; union in &lt;code&gt;permissions.ts&lt;/code&gt;, map its permissions in &lt;code&gt;ROLE_PERMISSIONS&lt;/code&gt; in the same file, and optionally add a parallel route slot. It intentionally does not attempt multi-tenant, hierarchical, or resource-scoped permissions; for complex multi-tenant permission graphs, that logic belongs on your main API, not bolted onto a frontend starter. The UI can still hide a disabled button for a role that lacks a permission (&lt;code&gt;useAuth().hasPermission()&lt;/code&gt; exists for exactly that), which is good UX, but the enforcement that matters happens in &lt;code&gt;requirePermission&lt;/code&gt;, on the server, where a hidden button can't be bypassed by editing the DOM.&lt;/p&gt;




&lt;h2 id="typescript"&gt;7. TypeScript should enforce architecture, not just describe it&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; TypeScript's value in 2026 isn't "the compiler catches typos." It's using the type system to make invalid states hard to represent at all, typed config, typed environment variables, typed permission strings, typed translation keys, so an entire category of runtime bug turns into a compile-time error instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; this shows up in four concrete places rather than as a slogan:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Environment variables&lt;/strong&gt; are validated and typed through T3 Env (&lt;code&gt;src/libs/env.ts&lt;/code&gt;), so a malformed value, like an &lt;code&gt;NEXT_PUBLIC_APP_URL&lt;/code&gt; that isn't a URL or a &lt;code&gt;BETTER_AUTH_SECRET&lt;/code&gt; shorter than 32 characters, fails loudly at startup instead of surfacing as a broken feature later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Translation keys&lt;/strong&gt; are type-checked through &lt;code&gt;next-intl&lt;/code&gt;; &lt;code&gt;t('dashboard.title')&lt;/code&gt; only compiles if that key exists in &lt;code&gt;messages/en.json&lt;/code&gt;, so a typo'd key fails the build instead of silently rendering nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RBAC permissions&lt;/strong&gt; are a typed union (&lt;code&gt;UserRole&lt;/code&gt; and &lt;code&gt;AuthPermission&lt;/code&gt; in &lt;code&gt;permissions.ts&lt;/code&gt;), so &lt;code&gt;requirePermission('dashbord.view:admin')&lt;/code&gt;, misspelled, is a type error, not a bug that ships and gets discovered by a user with too much access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Site config&lt;/strong&gt; has a Zod schema that defines its type, and a unit test validates &lt;code&gt;site.config.json&lt;/code&gt; against it, so the config is typed in the editor and checked in CI without shipping the validator to the browser.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TypeScript 7 in strict mode (with &lt;code&gt;noUncheckedIndexedAccess&lt;/code&gt;) across the codebase is table stakes; the part that actually prevents bugs is using types to encode business rules (valid roles, valid locales, valid config shape), not just typing function signatures.&lt;/p&gt;




&lt;h2 id="i18n"&gt;8. Type-safe internationalization&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; i18n bolted on at the end of a project usually means hardcoded strings scattered through components, a hunt-and-replace refactor, and a translation key system with no compile-time safety, so a typo'd key just renders blank in production. It also usually means nobody thought about RTL languages until a customer in an Arabic-speaking market asks why the layout is broken. RTL isn't a CSS afterthought, it changes how you think about "start" and "end" instead of "left" and "right" throughout the component tree, which is much cheaper to design in from the start than to retrofit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; &lt;code&gt;next-intl&lt;/code&gt; provides cookie-based locale switching (a &lt;code&gt;NEXT_LOCALE&lt;/code&gt; cookie set by a Server Action, no &lt;code&gt;/en/&lt;/code&gt; or &lt;code&gt;/es/&lt;/code&gt; URL prefix) across six languages, including Arabic with RTL support, and translation keys are type-checked against &lt;code&gt;messages/en.json&lt;/code&gt; at compile time. A unit test also checks that every locale file has exactly the same keys as English, so a missing translation fails CI. Layout code uses logical utilities (&lt;code&gt;ms-*&lt;/code&gt;/&lt;code&gt;me-*&lt;/code&gt;, &lt;code&gt;ps-*&lt;/code&gt;/&lt;code&gt;pe-*&lt;/code&gt;, &lt;code&gt;border-e&lt;/code&gt;) instead of left/right, so the same components work in both directions. Adding a language is three steps: add the locale to &lt;code&gt;site.config.json&lt;/code&gt;, create &lt;code&gt;messages/&amp;lt;locale&amp;gt;.json&lt;/code&gt;, and the runtime and types pick it up automatically.&lt;/p&gt;

&lt;p&gt;The trade-off is explicit: cookie-based locale means simpler routing, but it has two costs. First, if you need path-prefixed URLs for per-locale SEO indexing (&lt;code&gt;/es/dashboard&lt;/code&gt; ranking separately from &lt;code&gt;/en/dashboard&lt;/code&gt;), that requires a custom router setup Next-Elite doesn't provide out of the box. Second, because the server has to read the cookie to know the language, public pages render on every request instead of being statically cached at the CDN. For an app that lives mostly behind a login, that's the right call; for a large multilingual marketing site, it's a real limitation to know about before you start.&lt;/p&gt;




&lt;h2 id="ui"&gt;9. UI architecture with Tailwind + shadcn/ui&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; treat shadcn/ui as a foundation you own and edit, not a component library you import and never touch. Its actual value in 2026 isn't the number of components available, it's that the code lives in your repo, built on accessible Radix primitives with Tailwind and CVA for variants, so you can change a button's behavior without fighting a black-box dependency's API surface. The second half of the practice is a design system underneath it: colors, radii, and spacing come from tokens, never from hard-coded hex values, so dark mode and rebranding are a token change instead of a find-and-replace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; the boilerplate ships 50+ of these primitives and custom components under &lt;code&gt;src/components/ui/&lt;/code&gt;, including stat cards, an area chart, a sortable and paginated data table, a searchable combobox, and a calendar/date picker, plus a live &lt;a href="https://nextelite.salmanshahriar.com/ui-components" rel="noopener noreferrer"&gt;&lt;code&gt;/ui-components&lt;/code&gt;&lt;/a&gt; showcase page so you can see what exists before building a new one from scratch:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdng09lmb762j6uy9har2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdng09lmb762j6uy9har2.webp" alt="Next Elite 50+ custom and reusable UI components" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every color and radius comes from light and dark tokens in &lt;code&gt;src/app/styles/tokens.css&lt;/code&gt;, mapped to Tailwind utilities. The number isn't the point; the point is that composition and accessibility come for free because they're built on Radix, and because the components are just code in your repo, extending one (a new variant) doesn't mean waiting on an upstream release. Domain-specific UI (the auth forms, the dashboard shell) lives separately under &lt;code&gt;src/components/auth/&lt;/code&gt; and &lt;code&gt;src/components/layout/&lt;/code&gt;, so the line between "generic primitive" and "feature-specific composition" stays visible in the folder structure itself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7wkydoi05cats7hqpckl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7wkydoi05cats7hqpckl.webp" alt="Next Elite role-based admin dashboard layout" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2 id="data-fetching"&gt;10. Data fetching: don't turn everything into React state&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; Server Components and TanStack Query solve different problems, and the 2026 consensus (backed by both the Next.js docs and the wider React ecosystem) is that they're complementary, not competing. Server Components are the right tool for the initial, server-known render, a dashboard's first paint, a product list. TanStack Query is the right tool for anything that needs client-side behavior after that: pagination, optimistic mutations, background refetching, stale-while-revalidate caching, infinite scroll. Reaching for &lt;code&gt;useEffect&lt;/code&gt; plus manual &lt;code&gt;useState&lt;/code&gt; for server data in 2026 means rebuilding caching, retries, and race-condition handling that TanStack Query already solved. The inverse mistake also happens: wrapping genuinely static, server-known data in a client-side query hook just adds a network waterfall and a loading spinner where a Server Component would have sent the HTML already rendered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; &lt;code&gt;QueryClientProvider&lt;/code&gt; is pre-configured in &lt;code&gt;src/app/providers.tsx&lt;/code&gt; with sensible defaults (a 60-second &lt;code&gt;staleTime&lt;/code&gt;, 5-minute &lt;code&gt;gcTime&lt;/code&gt;, one retry, no refetch on window focus), ready to wire &lt;code&gt;useQuery&lt;/code&gt; / &lt;code&gt;useMutation&lt;/code&gt; against your REST, GraphQL, or BFF endpoints. It's deliberately not mandatory scaffolding around every fetch; server-renderable data still belongs in the Server Component that renders it.&lt;/p&gt;




&lt;h2 id="env"&gt;11. Environment variables should fail safely&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; a misconfigured environment variable should be a loud error, not a silent &lt;code&gt;undefined&lt;/code&gt; that surfaces as a broken feature in production three weeks later. This means validating both server-only and public (&lt;code&gt;NEXT_PUBLIC_*&lt;/code&gt;) variables against a schema, and being deliberate about which is which, since a secret accidentally marked public ships straight to the browser bundle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; variables are validated by &lt;code&gt;src/libs/env.ts&lt;/code&gt; via T3 Env, and that module is only imported by server code, so the validation library itself doesn't ship to the browser. A couple of specific decisions worth calling out because they're not the only valid choice: &lt;code&gt;BETTER_AUTH_URL&lt;/code&gt; is optional and derives from &lt;code&gt;VERCEL_URL&lt;/code&gt; in production rather than requiring manual configuration on every deploy, and a missing &lt;code&gt;BETTER_AUTH_SECRET&lt;/code&gt; logs a warning instead of crashing the build, a deliberate softness so local development and CI don't grind to a halt over a secret you'll set before the real deploy. &lt;code&gt;SKIP_ENV_VALIDATION=true&lt;/code&gt; exists specifically for CI and Docker build steps where secrets genuinely aren't available yet at build time.&lt;/p&gt;




&lt;h2 id="seo"&gt;12. SEO should be part of the architecture&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; metadata, Open Graph tags, a sitemap, &lt;code&gt;robots.txt&lt;/code&gt;, and a web manifest shouldn't be a checklist item the week before launch, scattered across whatever files happened to need them at the time. Centralizing them means updating your domain or title once, not hunting through six files hoping you didn't miss one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; &lt;code&gt;src/features/site/site.config.json&lt;/code&gt; is the single source of truth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"appName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Next Elite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://yourdomain.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tagline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Frontend-first, API-driven, batteries included."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Next Elite - Production-Ready SaaS Boilerplate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Frontend-first Next.js 16.4 + React 19 boilerplate with i18n, RBAC and BetterAuth."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The root layout's metadata and JSON-LD structured data, &lt;code&gt;sitemap.ts&lt;/code&gt;, &lt;code&gt;robots.ts&lt;/code&gt;, and &lt;code&gt;manifest.ts&lt;/code&gt; all read from this one file (with &lt;code&gt;NEXT_PUBLIC_APP_URL&lt;/code&gt; able to override the domain), along with the locale configuration, so localized routes and PWA metadata stay in sync with the rest of the i18n setup instead of drifting from it. There's also a &lt;code&gt;/llms.txt&lt;/code&gt; file, a machine-readable summary for AI crawlers and assistants, which is a small 2026 addition that costs nothing and helps AI tools describe your product accurately.&lt;/p&gt;




&lt;h2 id="performance"&gt;13. Performance should be a default, not a final optimization&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; the practical levers in 2026 are the same ones they've been for a few years, rendering on the server by default, minimizing the client JavaScript boundary, using &lt;code&gt;next/image&lt;/code&gt; correctly (setting &lt;code&gt;priority&lt;/code&gt; and &lt;code&gt;sizes&lt;/code&gt; deliberately rather than accepting defaults everywhere), and measuring instead of guessing. What's changed is the tooling underneath: Turbopack graduated to stable as the default bundler in Next.js 16, and the 16.x line has continued shipping real, measured startup and rendering improvements release over release. None of that replaces measuring your specific app; bundle analysis and a Lighthouse run tell you where your app actually spends its budget, which is never quite the generic advice.&lt;/p&gt;

&lt;p&gt;One tooling detail that catches people out: &lt;code&gt;@next/bundle-analyzer&lt;/code&gt; only works with webpack, so under Turbopack it silently does nothing. Use Next's built-in Turbopack analyzer instead (&lt;code&gt;npx next experimental-analyze&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; I ran exactly that analysis on Next-Elite and it found three things that were on every page without being needed there: the Sentry browser SDK (even when no DSN was set), Zod and the env validator (pulled into the browser through the auth provider and site config), and the ApexCharts library (loaded as soon as any chart rendered, even below the fold). The fixes were small and boring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sentry now loads lazily, and only when &lt;code&gt;NEXT_PUBLIC_SENTRY_DSN&lt;/code&gt; is set, including inside the error boundaries.&lt;/li&gt;
&lt;li&gt;Server-only values are passed to client components as props, and the site config is validated in tests instead of in the browser.&lt;/li&gt;
&lt;li&gt;Charts load their library only when they scroll into view.&lt;/li&gt;
&lt;li&gt;Only the font subset the app actually uses is loaded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together that cut first-load JavaScript by 21–24% per page (the home page went from 425 KB to 336 KB gzipped), and the live demo's total transfer roughly halved, from 906 KB to 462 KB.&lt;/p&gt;

&lt;p&gt;The project's Lighthouse report shows 100 across Performance, Accessibility, Best Practices, and SEO, and 3/3 on Agentic Browsing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2i8jcrrj3qd3h9w7bzwj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2i8jcrrj3qd3h9w7bzwj.webp" alt="Next Elite Lighthouse Report - 100 Performance, Accessibility, Best Practices, and SEO" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That number describes the starting point; it's not a guarantee that survives you adding a heavy client-side library without thinking about it. That's exactly why the analyzer step belongs in your workflow, not just in a launch checklist.&lt;/p&gt;




&lt;h2 id="testing"&gt;14. Testing strategy&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; unit and component tests catch logic bugs and rendering regressions fast, cheaply, and in isolation. End-to-end tests catch the thing unit tests structurally can't, whether the whole system actually works together, but they're slower and more expensive to maintain, which means writing them for the handful of flows that actually matter (login, the core happy path) rather than trying to E2E everything. Setting up this infrastructure after a project is already painful to test is a common regret; it's cheaper to have it from the first feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; Vitest and React Testing Library cover unit and component tests (&lt;code&gt;config/vitest.config.ts&lt;/code&gt;), split into a fast &lt;code&gt;node&lt;/code&gt; project for &lt;code&gt;.test.ts&lt;/code&gt; logic and a &lt;code&gt;jsdom&lt;/code&gt; project for &lt;code&gt;.test.tsx&lt;/code&gt; components. Tests live in &lt;code&gt;src/tests/&lt;/code&gt;, mirroring the &lt;code&gt;src/&lt;/code&gt; structure, with a &lt;code&gt;renderWithProviders&lt;/code&gt; helper (&lt;code&gt;@/tests/render&lt;/code&gt;) for components that need the app's context, i18n, theme, auth, React Query, so testing a component that reads the current locale doesn't mean hand-wiring four providers per test file. Playwright covers end-to-end, including the home page, the health endpoint, and the security headers, running on port 6767 against &lt;code&gt;next dev&lt;/code&gt; locally (all browsers) and against a production &lt;code&gt;next start&lt;/code&gt; build in CI (Chromium only, for speed). &lt;code&gt;npm run check&lt;/code&gt; is the single CI gate: typecheck, lint, dead-code detection, and tests, in that order, so a broken type or an unused export fails the build before a flaky E2E test would even get a chance to run.&lt;/p&gt;




&lt;h2 id="code-quality"&gt;15. Code quality is an engineering system&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; linting and formatting stop being cosmetic once a team grows past one person; they're what keeps "the way we do things" from depending on everyone remembering the rules. The honest 2026 state of the tooling landscape is a genuine trade-off, not a clean win for either side. Rust-based linters like Oxlint are dramatically faster than ESLint, independent 2026 benchmarks put the gap at roughly 50 to 100 times on large codebases, but ESLint still has by far the larger plugin ecosystem, meaning teams with heavy plugin dependencies (custom accessibility rules, framework-specific configs) often run both rather than fully switching. For a new project without that legacy plugin baggage, going Oxlint-first is a reasonable, increasingly common choice; for an existing large codebase with deep ESLint plugin investment, a hybrid or gradual migration is the more honest recommendation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; Oxlint and Oxfmt handle linting and formatting, chosen specifically because the project has no legacy ESLint plugin dependency to migrate away from, it's a new codebase, so there was nothing to preserve by staying on the slower tool. Knip catches dead code and unused dependencies. Dependencies are pinned to exact versions (&lt;code&gt;.npmrc&lt;/code&gt; sets &lt;code&gt;save-exact=true&lt;/code&gt;) and kept current by Renovate and Dependabot, so an update is always a reviewed pull request, never a surprise in a fresh install. Lefthook wires all of it into git hooks: a pre-commit hook runs Oxlint and Oxfmt, a commit-msg hook enforces Conventional Commits via Commitlint, and a pre-push hook runs the full &lt;code&gt;npm run check&lt;/code&gt; gate before code ever reaches a PR, which catches problems at the cheapest possible point, before CI, not after.&lt;/p&gt;

&lt;p&gt;In 2026 there's a new member of the team the rules have to reach: AI coding agents. A linter can't tell an agent "use the existing card component instead of writing a new one." So Next-Elite ships its conventions in a form agents read: an &lt;code&gt;AGENTS.md&lt;/code&gt; for tools like Cursor and Codex, and a &lt;code&gt;project-standards&lt;/code&gt; skill for Claude Code. They tell the agent to reuse existing components first, add a variant instead of duplicating a component, use design tokens only, keep public pages as Server Components, and ask before making structural changes. That's the same "the way we do things" problem, extended to contributors that don't attend code review.&lt;/p&gt;




&lt;h2 id="observability"&gt;16. Observability from day one&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; "it works on my machine" is not a monitoring strategy, and neither is waiting for a user to report a bug in a support ticket. Error tracking and a basic health endpoint cost almost nothing to set up and are the difference between finding a production issue in minutes versus discovering it days later from a support ticket. The 2026 addition: observability shouldn't cost every visitor bundle size. Load your error tracking SDK lazily so it never competes with the first paint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; Sentry is wired for both client and server instrumentation (&lt;code&gt;instrumentation.ts&lt;/code&gt;, &lt;code&gt;instrumentation-client.ts&lt;/code&gt;), and both error boundaries report to it. The browser SDK loads lazily, and only when a DSN is configured, so projects that don't use Sentry ship none of it. Vercel Analytics is included for basic page analytics and renders only when the app is actually deployed on Vercel, so self-hosted deploys don't make a failing request on every page. A &lt;code&gt;GET /api/health&lt;/code&gt; endpoint exists specifically so a load balancer, Dokploy, or your own uptime monitor has something concrete to poll. None of this replaces a real incident-response process for a team that needs one; it's the minimum that should exist before you need it, not a substitute for a mature observability stack at scale.&lt;/p&gt;




&lt;h2 id="deployment"&gt;17. Docker and deployment should be boring&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Recommended practice:&lt;/strong&gt; deployment infrastructure shouldn't force an architectural rewrite six months in. Standalone output, multi-arch container builds, a real health check, and security headers set in code (not in some dashboard nobody remembers configuring) are what let you move a project from Vercel to a VPS, or from a single instance to several, without touching application code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; the Dockerfile is a multi-stage build on a Google Distroless base image (&lt;code&gt;gcr.io/distroless/nodejs22-debian12&lt;/code&gt;), so the runtime image contains no shell or package manager. It uses Next.js's standalone output with a built-in &lt;code&gt;HEALTHCHECK&lt;/code&gt; against &lt;code&gt;/api/health&lt;/code&gt;, and Buildx support means one command produces images for both &lt;code&gt;linux/amd64&lt;/code&gt; and &lt;code&gt;linux/arm64&lt;/code&gt;, useful for self-hosting on ARM (Oracle Cloud's free tier, AWS Graviton, a Raspberry Pi). One detail that trips people up: &lt;code&gt;NEXT_PUBLIC_*&lt;/code&gt; values are inlined into the JavaScript at build time, so they're passed as Docker build args, while server secrets like &lt;code&gt;BETTER_AUTH_SECRET&lt;/code&gt; are read at runtime.&lt;/p&gt;

&lt;p&gt;Security headers live in &lt;code&gt;next.config.mjs&lt;/code&gt;: a strict Content Security Policy, HSTS, &lt;code&gt;X-Frame-Options: DENY&lt;/code&gt;, &lt;code&gt;nosniff&lt;/code&gt;, Referrer-Policy, and Permissions-Policy, with E2E tests checking that they're actually sent. One practical lesson from running the live demo behind Cloudflare: a strict CSP also blocks the scripts your host injects (Cloudflare Web Analytics, in my case), so allow-list them deliberately instead of loosening the whole policy.&lt;/p&gt;

&lt;p&gt;It deploys to Vercel with one click, or to &lt;a href="https://dokploy.com" rel="noopener noreferrer"&gt;Dokploy&lt;/a&gt; as a self-hosted alternative, using the same Dockerfile and health check either way. The point isn't a preference for one platform, it's that the same container-based deployment story works whether you're on a $0 Vercel hobby plan or your own hardware.&lt;/p&gt;




&lt;h2 id="not-included"&gt;18. What I intentionally did NOT include&lt;/h2&gt;

&lt;p&gt;A good boilerplate is defined as much by what it refuses to bundle as by what it ships. Next-Elite intentionally does not include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A database or ORM.&lt;/strong&gt; No Prisma, no Drizzle, no Postgres. This is the direct consequence of the API-driven architecture decision in section 3, not an oversight.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments or billing.&lt;/strong&gt; Stripe, subscriptions, and usage metering are product-specific decisions that vary too much between projects to standardize in a starter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queues or Redis.&lt;/strong&gt; Background jobs and caching infrastructure depend entirely on what your backend already provides.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A specific backend framework.&lt;/strong&gt; Next-Elite doesn't assume Go, Node, or Laravel behind it, because assuming any one of them would break the "drop it on any backend" promise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-tenant or hierarchical permission graphs.&lt;/strong&gt; The RBAC system covers two roles well; it doesn't try to be a general-purpose authorization engine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A wired-up password reset email flow.&lt;/strong&gt; The reset page and form are there, but sending the email is your backend's job, so the form is ready to connect rather than tied to one email provider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every one of these is a real feature other boilerplates in the ecosystem provide well, some of them, like ixartz's Next.js Boilerplate, ship a database, multi-tenancy, and a full auth/roles system out of the box, and paid options like ShipFast or MakerKit bundle Stripe, transactional email, and enterprise compliance features for a one-time fee. Building that same foundation from scratch has been estimated at somewhere in the $7,500 to $12,000 range in developer time, which is exactly why those paid options exist and are worth it for the right project. If you want any of what's on this list bundled in, one of those is very likely the better starting point than Next-Elite. That's not a hedge, it's the honest answer to "why doesn't this have X."&lt;/p&gt;




&lt;h2 id="trade-offs"&gt;19. The trade-offs&lt;/h2&gt;

&lt;p&gt;None of this architecture is universally correct, and presenting it that way would be dishonest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next-Elite is probably overkill for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-page landing sites&lt;/li&gt;
&lt;li&gt;Tiny prototypes and weekend experiments&lt;/li&gt;
&lt;li&gt;Projects where Next.js is genuinely the entire backend and will stay that way&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;It's a stronger fit for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SaaS applications with more than one user role&lt;/li&gt;
&lt;li&gt;Admin panels, ERPs, dashboards, and internal tools&lt;/li&gt;
&lt;li&gt;Multilingual products, especially ones that need RTL support&lt;/li&gt;
&lt;li&gt;Products backed by an existing REST, GraphQL, or BFF API&lt;/li&gt;
&lt;li&gt;Teams (or solo developers) who've noticed they're rebuilding the same auth-and-RBAC foundation across projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're not sure which camp you're in: if you can describe your project without the words "roles," "dashboard," or "multiple languages," you probably don't need this, and that's a legitimate outcome, not a failure to be convinced.&lt;/p&gt;




&lt;h2 id="next-elite"&gt;20. The actual boilerplate: Next Elite&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;Next Elite&lt;/a&gt; because I kept answering the same architectural questions from scratch on every new SaaS project, and I wanted the answer to compound instead of resetting. It's MIT-licensed and free to use as a template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmh838hztnd7ye66u8ci.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmh838hztnd7ye66u8ci.webp" alt="Next Elite split-pane auth layout" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you get, in one pass:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 16.4 (App Router, Turbopack, Server Actions) + React 19.3 + TypeScript 7&lt;/li&gt;
&lt;li&gt;Feature-based architecture under &lt;code&gt;src/features/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;BetterAuth (email/password + Google OAuth) with permission-based RBAC, split-pane auth UI, server-side guards, parallel-route dashboard slots&lt;/li&gt;
&lt;li&gt;next-intl across 6 languages including RTL, cookie-based, type-checked translation keys&lt;/li&gt;
&lt;li&gt;50+ shadcn/ui primitives and custom components on Tailwind CSS v4 and Radix UI, with light/dark design tokens&lt;/li&gt;
&lt;li&gt;TanStack Query pre-configured for your REST/GraphQL/BFF API&lt;/li&gt;
&lt;li&gt;Sentry (lazy-loaded) + Vercel Analytics + a &lt;code&gt;/api/health&lt;/code&gt; endpoint&lt;/li&gt;
&lt;li&gt;Security headers (CSP, HSTS, frame and content-type protection) set in code&lt;/li&gt;
&lt;li&gt;Vitest + React Testing Library + Playwright&lt;/li&gt;
&lt;li&gt;Oxlint + Oxfmt + Knip + Lefthook + Commitlint, with pinned dependencies kept current by Renovate and Dependabot&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AGENTS.md&lt;/code&gt; and a &lt;code&gt;project-standards&lt;/code&gt; skill so AI coding agents follow the project's conventions&lt;/li&gt;
&lt;li&gt;Standalone Distroless Docker build, multi-arch (amd64/arm64), Dokploy-ready, one-click Vercel deploy&lt;/li&gt;
&lt;li&gt;SEO metadata, JSON-LD, dynamic sitemap, &lt;code&gt;robots.txt&lt;/code&gt;, PWA manifest, and &lt;code&gt;llms.txt&lt;/code&gt; from one config file&lt;/li&gt;
&lt;li&gt;All demo code in one folder, removable with &lt;code&gt;npm run demo:remove&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Who should use it:&lt;/strong&gt; teams and solo developers building a role-based SaaS, admin panel, or dashboard product against an existing or planned API, especially if multi-language support is on the roadmap.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who shouldn't:&lt;/strong&gt; anyone who needs a bundled database on day one, or whose project is small enough that this is genuinely more structure than the problem needs. Use &lt;code&gt;create-next-app&lt;/code&gt; for that, or the official Next.js SaaS Starter if you want the framework team's own opinionated take.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick start
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/salmanshahriar/Next-Elite.git
&lt;span class="nb"&gt;cd &lt;/span&gt;Next-Elite
npm &lt;span class="nb"&gt;install
cp&lt;/span&gt; .env.example .env
npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:6767" rel="noopener noreferrer"&gt;http://localhost:6767&lt;/a&gt;. You'll land on a working app with auth, RBAC-gated dashboards, six languages, and the rest of this list already wired together, not a scaffold you still have to assemble. When you're ready to build your own product, run &lt;code&gt;npm run demo:remove&lt;/code&gt; and &lt;code&gt;npm run check&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://nextelite.salmanshahriar.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite/generate" rel="noopener noreferrer"&gt;Use This Template&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://vercel.com/new/clone?repository-url=https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;Deploy on Vercel&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2 id="checklist"&gt;21. Final checklist: my 2026 Next.js project checklist&lt;/h2&gt;

&lt;p&gt;Whether or not you use Next-Elite, this is the list I'd check before calling a Next.js project production-ready:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Code is grouped by feature, with genuinely shared UI kept in one place&lt;/li&gt;
&lt;li&gt;✅ Decided on purpose whether Next.js owns the database or consumes an API&lt;/li&gt;
&lt;li&gt;✅ Demo or example code is isolated and removable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Rendering &amp;amp; data&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Pages and layouts are Server Components; &lt;code&gt;'use client'&lt;/code&gt; only at small leaf boundaries&lt;/li&gt;
&lt;li&gt;✅ Server-only values are passed to client components as props, not imported&lt;/li&gt;
&lt;li&gt;✅ Server-known data renders on the server; client data uses TanStack Query, not &lt;code&gt;useEffect&lt;/code&gt; + &lt;code&gt;useState&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Authorization runs in Server Components, Route Handlers, and Server Actions, never only in middleware&lt;/li&gt;
&lt;li&gt;✅ Roles and permissions are defined in one typed place and checked through a few helpers&lt;/li&gt;
&lt;li&gt;✅ Auth has a real database adapter before multi-instance production&lt;/li&gt;
&lt;li&gt;✅ Security headers (CSP, HSTS, frame protection) are set in code and tested&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Type safety &amp;amp; config&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Environment variables are validated, with server and public variables clearly separated&lt;/li&gt;
&lt;li&gt;✅ Translation keys, permissions, and config are typed, not just component props&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;i18n &amp;amp; UI&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Every user-facing string goes through i18n, and every locale has the same keys&lt;/li&gt;
&lt;li&gt;✅ Layouts use logical start/end spacing so RTL works&lt;/li&gt;
&lt;li&gt;✅ Colors and radii come from design tokens, with light and dark values&lt;/li&gt;
&lt;li&gt;✅ Every data view has loading, empty, and error states&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SEO &amp;amp; performance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Metadata, sitemap, robots, manifest, and JSON-LD come from one config&lt;/li&gt;
&lt;li&gt;✅ Bundle analyzed with the Turbopack analyzer; heavy libraries load lazily&lt;/li&gt;
&lt;li&gt;✅ Lighthouse checked on the production build&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quality &amp;amp; delivery&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ One &lt;code&gt;check&lt;/code&gt; command runs typecheck, lint, dead-code detection, and tests&lt;/li&gt;
&lt;li&gt;✅ Git hooks run the cheap checks before code leaves the machine&lt;/li&gt;
&lt;li&gt;✅ Dependencies are pinned and updated through reviewed pull requests&lt;/li&gt;
&lt;li&gt;✅ Unit/component tests plus E2E for the flows that matter&lt;/li&gt;
&lt;li&gt;✅ AI coding agents get the project's conventions in &lt;code&gt;AGENTS.md&lt;/code&gt; (or a skill)&lt;/li&gt;
&lt;li&gt;✅ Error tracking, a health endpoint, and a container build with a health check exist before launch&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>typescript</category>
      <category>architecture</category>
    </item>
    <item>
      <title>I built an opensource production-ready NEXT.JS STARTER KIT!</title>
      <dc:creator>Salman Shahriar</dc:creator>
      <pubDate>Wed, 19 Nov 2025 19:11:28 +0000</pubDate>
      <link>https://dev.to/salmanshahriar/i-built-a-production-ready-nextjs-boilerplate-so-you-dont-have-to-17d3</link>
      <guid>https://dev.to/salmanshahriar/i-built-a-production-ready-nextjs-boilerplate-so-you-dont-have-to-17d3</guid>
      <description>&lt;p&gt;Every time I started a new Next.js project, I lost the first week to setup.&lt;/p&gt;

&lt;p&gt;Authentication. Internationalization. Role-based access. SEO meta tags. Environment validation. Error monitoring. Linting. Testing. CI pipelines.&lt;/p&gt;

&lt;p&gt;By the time I had a working foundation, the excitement was gone, buried under configuration files and boilerplate glue code.&lt;/p&gt;

&lt;p&gt;I kept rebuilding the same foundation across SaaS projects, so I stopped and built it once: &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;Next Elite&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is a frontend-first Next.js 16.4 + React 19.3 boilerplate designed to consume APIs (REST/GraphQL/BFF) instead of owning a database, so you can drop it on top of any backend you already have. It is feature-based, optimized for speed, SEO, and developer productivity, and includes &lt;strong&gt;50+ custom and reusable UI components&lt;/strong&gt; built on shadcn/ui, plus pre-built split-pane auth layouts and role-based dashboard layouts. It is 100% open source under the MIT license.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://nextelite.salmanshahriar.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite/generate" rel="noopener noreferrer"&gt;Use This Template&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://vercel.com/new/clone?repository-url=https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;Deploy on Vercel&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6z7h0l9jymqw3e0x5dfq.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6z7h0l9jymqw3e0x5dfq.webp" alt="Next Elite home page - production-ready Next.js starter kit" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; &lt;code&gt;git clone&lt;/code&gt;, &lt;code&gt;npm install&lt;/code&gt;, &lt;code&gt;cp .env.example .env&lt;/code&gt;, &lt;code&gt;npm run dev&lt;/code&gt;. Open &lt;a href="http://localhost:6767" rel="noopener noreferrer"&gt;http://localhost:6767&lt;/a&gt;. You get auth, RBAC dashboards, 6-language i18n, 50+ UI components, SEO, forms, testing, CI, and AI-agent-ready coding rules. &lt;a href="https://nextelite.salmanshahriar.com/" rel="noopener noreferrer"&gt;Try the demo&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Why Another Next.js Boilerplate? (The Concept)&lt;/li&gt;
&lt;li&gt;What's Inside: The Next Elite Stack &amp;amp; Features&lt;/li&gt;
&lt;li&gt;Lighthouse Score: 100% Performance &amp;amp; SEO&lt;/li&gt;
&lt;li&gt;Quick Start: Launch Your Project in 60 Seconds&lt;/li&gt;
&lt;li&gt;Deep Dive: How Next Elite Works Under the Hood&lt;/li&gt;
&lt;li&gt;Clean Feature-Based Directory Structure&lt;/li&gt;
&lt;li&gt;Configuration &amp;amp; Environment Variables&lt;/li&gt;
&lt;li&gt;Development, Testing &amp;amp; CI/CD&lt;/li&gt;
&lt;li&gt;Architectural Caveats: What Next Elite is NOT&lt;/li&gt;
&lt;li&gt;Production Checklist: Going Live&lt;/li&gt;
&lt;li&gt;Contributing &amp;amp; Open Source&lt;/li&gt;
&lt;/ol&gt;




&lt;h2 id="why-another-nextjs-boilerplate"&gt;1. Why Another Next.js Boilerplate? (The Concept)&lt;/h2&gt;

&lt;p&gt;Most Next.js starters on GitHub are either too bare (a dark mode toggle and a "TODO: add auth" comment) or too bloated (Prisma, PostgreSQL, Docker Compose, Stripe webhooks, and an ORM tightly coupled to their own DB schema).&lt;/p&gt;

&lt;p&gt;If you already have a backend (written in Go, Python, Laravel, or Node.js) or want a backend-for-frontend (BFF) architecture, tearing the built-in database layer out of a boilerplate is painful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next Elite sits in the sweet spot.&lt;/strong&gt; It handles the complex frontend foundation, UI components, role management, and locale settings while leaving the database and API layer up to you. It's built to consume APIs directly, so you can drop it on top of any backend you already have.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use Next Elite
&lt;/h3&gt;

&lt;p&gt;Next Elite is best for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SaaS apps with multiple user roles.&lt;/li&gt;
&lt;li&gt;Admin panels, ERPs, and dashboards.&lt;/li&gt;
&lt;li&gt;Multi-lingual/Internationalized products (LTR + RTL).&lt;/li&gt;
&lt;li&gt;Frontends consuming an existing backend or BFF.&lt;/li&gt;
&lt;li&gt;Projects requiring a clean, feature-based modular structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is probably overkill for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single-page landing sites.&lt;/li&gt;
&lt;li&gt;Apps that need a tightly-coupled DB layer (API-only design).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2 id="whats-inside"&gt;2. What's Inside: The Next Elite Stack &amp;amp; Features&lt;/h2&gt;

&lt;p&gt;Here is the tech stack built into Next Elite, broken down by category:&lt;/p&gt;

&lt;h3&gt;
  
  
  Frameworks &amp;amp; Core
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Next.js 16.4 (App Router)&lt;/strong&gt; - Fast, modern React framework with Turbopack, standalone output for Docker/self-hosting, and full support for React 19.3 features (Server/Client components, Server Actions).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TypeScript 7&lt;/strong&gt; - End-to-end type safety for rock-solid refactoring and developer experience.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Node.js 22.12+&lt;/strong&gt; - Built on the Node.js 22 LTS runtime.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Feature-Based Architecture&lt;/strong&gt; - Structured around self-contained vertical slices/feature folders under &lt;code&gt;src/features/&lt;/code&gt; for maximum modularity and clean separation of concerns.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Authentication &amp;amp; Access Control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;BetterAuth&lt;/strong&gt; - Out-of-the-box email/password and Google OAuth authentication using &lt;code&gt;/api/auth/*&lt;/code&gt; route handlers. Configure admin emails via the comma-separated &lt;code&gt;AUTH_ADMIN_EMAILS&lt;/code&gt; server variable.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Auth UI &amp;amp; Layout&lt;/strong&gt; - Split-pane login, register, and password reset pages with a custom WebGL particle background animation, and a topbar with theme toggle and language switcher. Login and register are wired to BetterAuth; the password reset form is UI-only, ready to connect to your backend's reset flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmh838hztnd7ye66u8ci.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkmh838hztnd7ye66u8ci.webp" alt="Next Elite split-pane auth layout" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Role-Based Access Control (RBAC)&lt;/strong&gt; - Flexible RBAC (&lt;code&gt;user&lt;/code&gt; and &lt;code&gt;admin&lt;/code&gt; roles) with server-side guards (&lt;code&gt;requireUser&lt;/code&gt;, &lt;code&gt;requirePermission&lt;/code&gt;) and parallel route slots (&lt;code&gt;@admin&lt;/code&gt;, &lt;code&gt;@user&lt;/code&gt;) for role-agnostic routing.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Dashboard &amp;amp; Navigation&lt;/strong&gt; - Modern sidebar navigation with fixed bottom Settings (&lt;code&gt;/settings&lt;/code&gt;) and Logout (with a confirm dialog) actions, collapsible state remembered in a cookie, mobile sheet, and topbar breadcrumbs generated from the URL. Users without permission land on a dedicated &lt;code&gt;/unauthorized&lt;/code&gt; page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7wkydoi05cats7hqpckl.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7wkydoi05cats7hqpckl.webp" alt="Next Elite role-based admin dashboard layout" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Internationalization (i18n)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;next-intl&lt;/strong&gt; - Type-safe, cookie-based localizations (no URL prefix) with support for English, বাংলা, العربية (RTL), Français, Español, and 简体中文. Translation keys are type-checked (&lt;code&gt;t("key")&lt;/code&gt; works; typos fail at compile time), and the language switcher updates the locale through a Server Action.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  UI &amp;amp; Styling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Tailwind CSS 4&lt;/strong&gt; - Utility-first styling with &lt;code&gt;@tailwindcss/postcss&lt;/code&gt; and &lt;code&gt;tw-animate-css&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Design Tokens&lt;/strong&gt; - Light and dark color, radius, and spacing tokens in &lt;code&gt;src/app/styles/tokens.css&lt;/code&gt;, mapped to Tailwind utilities, so there are no hard-coded colors anywhere.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;shadcn/ui&lt;/strong&gt; - 50+ highly customizable UI components built with Tailwind CSS, Radix UI, and CVA variants: cards, stat cards, charts, a sortable and paginated data table, forms, selects, comboboxes, a calendar/date picker, dialogs, sheets, and more. Includes a live &lt;a href="https://nextelite.salmanshahriar.com/ui-components" rel="noopener noreferrer"&gt;&lt;code&gt;/ui-components&lt;/code&gt;&lt;/a&gt; showcase page.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdng09lmb762j6uy9har2.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdng09lmb762j6uy9har2.webp" alt="Next Elite 50+ custom and reusable UI components" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Theme Support&lt;/strong&gt; - Light, dark, and system themes, with a circular "wave" transition (View Transitions API) when you toggle, and no flash on load because the theme is read on the server.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Feedback Built In&lt;/strong&gt; - Toast notifications with Sonner, a top page-loading bar, skeleton loading states, and loading-aware buttons.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API &amp;amp; Data Fetching
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;TanStack Query (React Query)&lt;/strong&gt; - Pre-configured &lt;code&gt;QueryClientProvider&lt;/code&gt; in &lt;code&gt;src/app/providers.tsx&lt;/code&gt; with sensible defaults (&lt;code&gt;staleTime&lt;/code&gt;, &lt;code&gt;gcTime&lt;/code&gt;, retry). Ready to wire &lt;code&gt;useQuery&lt;/code&gt; / &lt;code&gt;useMutation&lt;/code&gt; hooks to your REST, GraphQL, or BFF endpoints.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite-Server" rel="noopener noreferrer"&gt;Next Elite Server&lt;/a&gt; (Coming Soon)&lt;/strong&gt; - A companion backend template built with NestJS, BetterAuth, Drizzle ORM, PostgreSQL, and multi-tenancy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Observability &amp;amp; Infrastructure
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Sentry Integration&lt;/strong&gt; - Error tracking and performance instrumentation for client and server. The browser SDK loads lazily and only when &lt;code&gt;NEXT_PUBLIC_SENTRY_DSN&lt;/code&gt; is set, so it never blocks the first page load.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Vercel Analytics&lt;/strong&gt; - Page analytics via &lt;code&gt;@vercel/analytics&lt;/code&gt;, rendered only when deployed on Vercel.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Health Probes&lt;/strong&gt; - Direct &lt;code&gt;GET /api/health&lt;/code&gt; endpoint for load balancers.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Security Headers&lt;/strong&gt; - A strict Content Security Policy, HSTS, &lt;code&gt;X-Frame-Options: DENY&lt;/code&gt;, &lt;code&gt;nosniff&lt;/code&gt;, Referrer-Policy, and Permissions-Policy are set in &lt;code&gt;next.config.mjs&lt;/code&gt;, and E2E tests check them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quality Gates &amp;amp; Tooling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Validated Config&lt;/strong&gt; - Environment variables are validated on the server with T3 Env (&lt;code&gt;src/libs/env.ts&lt;/code&gt;), and &lt;code&gt;site.config.json&lt;/code&gt; is checked against its schema in unit tests, so neither ships zod to the browser.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Testing Suite&lt;/strong&gt; - Unit/component testing with Vitest and React Testing Library (separate &lt;code&gt;node&lt;/code&gt; and &lt;code&gt;jsdom&lt;/code&gt; projects), and E2E testing with Playwright.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Pinned Dependencies&lt;/strong&gt; - Exact versions only (&lt;code&gt;.npmrc&lt;/code&gt; sets &lt;code&gt;save-exact=true&lt;/code&gt;), kept up to date by Renovate and Dependabot.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Hygiene &amp;amp; Linting&lt;/strong&gt; - &lt;a href="https://oxc.rs/docs/guide/usage/linter" rel="noopener noreferrer"&gt;Oxlint&lt;/a&gt; and &lt;a href="https://oxc.rs/docs/guide/usage/formatter" rel="noopener noreferrer"&gt;Oxfmt&lt;/a&gt; for fast linting and formatting, plus Knip for dead code/dependency hygiene.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Git Hook Automation&lt;/strong&gt; - Lefthook pre-commit hooks (oxlint + oxfmt), Commitlint for conventional commits, and a pre-push hook that runs &lt;code&gt;npm run check&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AI Agent Ready
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; + &lt;code&gt;project-standards&lt;/code&gt; skill&lt;/strong&gt; - The repo ships coding rules for AI agents (Claude Code, Cursor, Codex, and others). They require agents to reuse the existing components first, add variants instead of duplicating components, use design tokens only, render public pages on the server, and ask before making structural changes. That way, AI-written code still looks like the rest of the codebase.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;/llms.txt&lt;/code&gt;&lt;/strong&gt; - A machine-readable project summary for AI crawlers and assistants.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2 id="lighthouse-score"&gt;3. Lighthouse Score: 100% Performance &amp;amp; SEO&lt;/h2&gt;

&lt;p&gt;One of the key goals of Next Elite was flawless performance and SEO defaults. Out of the box, the production build scores a perfect &lt;strong&gt;100&lt;/strong&gt; for Performance, Accessibility, Best Practices, and SEO on Lighthouse, and passes all &lt;strong&gt;3/3 Agentic Browsing&lt;/strong&gt; checks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2i8jcrrj3qd3h9w7bzwj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2i8jcrrj3qd3h9w7bzwj.webp" alt="Next Elite Lighthouse Report - 100 Performance, Accessibility, Best Practices, and SEO" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This comes from rendering Server Components by default, serving SEO meta tags from a single configuration file, and keeping client-side JavaScript lean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Heavy libraries like ApexCharts load only when a chart scrolls into view.&lt;/li&gt;
&lt;li&gt;Sentry loads lazily and only when it is configured.&lt;/li&gt;
&lt;li&gt;Validation libraries stay on the server.&lt;/li&gt;
&lt;li&gt;Only the font subsets the app needs are loaded.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2 id="quick-start"&gt;4. Quick Start: Launch Your Project in 60 Seconds&lt;/h2&gt;

&lt;h3&gt;
  
  
  One-click Deploy
&lt;/h3&gt;

&lt;p&gt;Deploy this template to Vercel with one click:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://vercel.com/new/clone?repository-url=https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;Deploy with Vercel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set the environment variables from &lt;code&gt;.env.example&lt;/code&gt; in your Vercel project (Production + Preview).&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Node.js &lt;strong&gt;22.12&lt;/strong&gt; or later&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;npm&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Local Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Clone the repository and navigate into it:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/salmanshahriar/Next-Elite.git
   &lt;span class="nb"&gt;cd &lt;/span&gt;Next-Elite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install dependencies:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Set up your environment variables:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start the development server:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;a href="http://localhost:6767" rel="noopener noreferrer"&gt;http://localhost:6767&lt;/a&gt; to view your local instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo Credentials
&lt;/h3&gt;

&lt;p&gt;When &lt;code&gt;NEXT_PUBLIC_DEMO_MODE=true&lt;/code&gt; is enabled, the login screen includes a quick-fill panel with these seed credentials:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;th&gt;Email&lt;/th&gt;
&lt;th&gt;Password&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User&lt;/td&gt;
&lt;td&gt;&lt;code&gt;user@test.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;12345678&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin&lt;/td&gt;
&lt;td&gt;&lt;code&gt;admin@test.com&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;12345678&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Removing the Demo Code
&lt;/h3&gt;

&lt;p&gt;All demo code (landing page, &lt;code&gt;/ui-components&lt;/code&gt; showcase, promo logos, demo accounts) lives in &lt;code&gt;src/_demo(DELETE)/&lt;/code&gt;. When you're ready to build your own app, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run demo:remove
npm run check
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script deletes the demo folder and rewrites every file that references it, so you're left with a clean, working app. CI runs this same removal on every push to make sure it keeps working.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker Setup
&lt;/h3&gt;

&lt;p&gt;The production image uses a multi-stage &lt;strong&gt;Google Distroless&lt;/strong&gt; base image (&lt;code&gt;gcr.io/distroless/nodejs22-debian12&lt;/code&gt;) for maximum security, zero unnecessary OS packages, and a minimal image size.&lt;/p&gt;

&lt;p&gt;Run the application locally via Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; next-elite &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--env-file&lt;/span&gt; .env &lt;span class="nt"&gt;-p&lt;/span&gt; 6767:6767 next-elite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or using Docker Compose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Dockerfile uses Next.js &lt;strong&gt;standalone&lt;/strong&gt; output with a built-in health check against &lt;code&gt;/api/health&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;code&gt;NEXT_PUBLIC_*&lt;/code&gt; variables are inlined into the JavaScript at build time, so pass them as build args (&lt;code&gt;--build-arg NEXT_PUBLIC_APP_URL=...&lt;/code&gt;, &lt;code&gt;NEXT_PUBLIC_GOOGLE_AUTH_ENABLED&lt;/code&gt;, &lt;code&gt;NEXT_PUBLIC_DEMO_MODE&lt;/code&gt;). Server-only secrets like &lt;code&gt;BETTER_AUTH_SECRET&lt;/code&gt; are read at runtime from &lt;code&gt;--env-file&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Multi-Arch Deploy (ARM64 + AMD64)
&lt;/h3&gt;

&lt;p&gt;The Dockerfile produces images that run on both &lt;code&gt;linux/amd64&lt;/code&gt; and &lt;code&gt;linux/arm64&lt;/code&gt;. Build a multi-arch image with Buildx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker buildx create &lt;span class="nt"&gt;--name&lt;/span&gt; multiarch &lt;span class="nt"&gt;--use&lt;/span&gt;   &lt;span class="c"&gt;# one-time setup&lt;/span&gt;
docker buildx build &lt;span class="nt"&gt;--platform&lt;/span&gt; linux/amd64,linux/arm64 &lt;span class="nt"&gt;-t&lt;/span&gt; next-elite &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is ideal for self-hosting on ARM servers (Oracle Cloud, Raspberry Pi, AWS Graviton, etc.).&lt;/p&gt;

&lt;h3&gt;
  
  
  Dokploy Deployment
&lt;/h3&gt;

&lt;p&gt;This template is ready for &lt;a href="https://dokploy.com" rel="noopener noreferrer"&gt;Dokploy&lt;/a&gt; - the open-source PaaS.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new &lt;strong&gt;Application&lt;/strong&gt; in Dokploy and point it to your fork of this repo.&lt;/li&gt;
&lt;li&gt;Set the build type to &lt;strong&gt;Dockerfile&lt;/strong&gt; (auto-detected).&lt;/li&gt;
&lt;li&gt;Configure environment variables via the Dokploy UI (see &lt;code&gt;.env.example&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Deploy - Dokploy automatically builds and runs the container with health checks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The included &lt;code&gt;HEALTHCHECK&lt;/code&gt; instruction pings &lt;code&gt;/api/health&lt;/code&gt; so Dokploy can monitor and restart the container if it becomes unresponsive.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;View Available Scripts &amp;amp; CLI Commands&lt;/b&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start the dev server (port 6767)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run build&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Production build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run start&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start the production server (port 6767)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run start:standalone&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run standalone server (Playwright CI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run typecheck&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;tsc --noEmit&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run lint&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Oxlint + Oxfmt check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run lint:fix&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auto-fix with Oxlint + Oxfmt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run format&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Format with Oxfmt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run format:check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check formatting with Oxfmt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run knip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Detect unused files / exports / deps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CI gate: typecheck + lint + knip + tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run test&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Vitest run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run test:watch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Vitest watch mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run demo:remove&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Delete all demo code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run playwright:install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Download Playwright browsers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run playwright:install:deps&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Install OS libs for browsers (Linux)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run e2e&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Playwright E2E&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run e2e:ui&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Playwright UI mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;npm run e2e:webkit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Playwright WebKit only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2 id="deep-dive"&gt;5. Deep Dive: How Next Elite Works Under the Hood&lt;/h2&gt;

&lt;p&gt;The big picture: a page is rendered on the server, auth/role is checked there, and any live data is fetched on the client.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TB
    User([User]) --&amp;gt; Page

    subgraph Server["Server (runs first)"]
        Page[Page / Layout]
        Guard["requireUser() / requirePermission()"]
        Page --&amp;gt; Guard
        Guard --&amp;gt;|reads session + role| Auth[BetterAuth]
    end

    subgraph Client["Client (runs in browser)"]
        Hook["useQuery (TanStack Query)"]
        Hook --&amp;gt;|fetch| Api["Your backend API"]
    end

    Page --&amp;gt;|sends HTML| User
    Page -.-&amp;gt;|interactive parts| Hook&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;How a request flows:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;User opens a page&lt;/strong&gt; - the Server Component renders first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth + role check&lt;/strong&gt; - &lt;code&gt;requireUser()&lt;/code&gt; / &lt;code&gt;requirePermission()&lt;/code&gt; read the BetterAuth session and redirect to &lt;code&gt;/login&lt;/code&gt; or &lt;code&gt;/unauthorized&lt;/code&gt; if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML is sent&lt;/strong&gt; to the browser; translations come from &lt;code&gt;messages/&lt;/code&gt; via &lt;code&gt;next-intl&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live data&lt;/strong&gt; (lists, forms, etc.) is fetched on the client with TanStack Query → your API (REST/GraphQL/BFF).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Type-Safe RBAC &amp;amp; BetterAuth
&lt;/h3&gt;

&lt;p&gt;Permissions are checked on the server, not with scattered &lt;code&gt;if (role === 'admin')&lt;/code&gt; checks.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;View Auth &amp;amp; RBAC Usage&lt;/b&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Server Component example&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;requirePermission&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/features/auth/rbac/require&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getTranslations&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next-intl/server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AdminDashboardPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[,&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;requirePermission&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard.view:admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;getTranslations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dashboard.admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;AdminDashboardPage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Next Elite uses Next.js &lt;strong&gt;Parallel Routes&lt;/strong&gt; to keep layouts role-agnostic. The routing structure mounts specific slots based on the user's role, and both roles share the same URLs (&lt;code&gt;/dashboard&lt;/code&gt;, &lt;code&gt;/analytics&lt;/code&gt;, &lt;code&gt;/profile&lt;/code&gt;, &lt;code&gt;/settings&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/(protected)/
  ├── @admin/               # Admin slots (dashboard, analytics, profile, settings)
  ├── @user/                # User slots (dashboard, analytics, profile, settings)
  └── layout.tsx            # Picks slot based on permissions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;b&gt;Adding a Role&lt;/b&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Append the role to the &lt;code&gt;UserRole&lt;/code&gt; union in &lt;code&gt;src/features/auth/rbac/permissions.ts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Map permissions for the role in &lt;code&gt;ROLE_PERMISSIONS&lt;/code&gt; in the same file.&lt;/li&gt;
&lt;li&gt;Optional: add a parallel route slot - &lt;code&gt;src/app/(protected)/@/...&lt;/code&gt; - and update &lt;code&gt;(protected)/layout.tsx&lt;/code&gt; to render it based on permissions.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Zero-Prefix cookie-based i18n
&lt;/h3&gt;

&lt;p&gt;Unlike standard i18n setups that force prefixes like &lt;code&gt;/en/&lt;/code&gt; or &lt;code&gt;/es/&lt;/code&gt; into the URL (which clutters routes and duplicates routing config), Next Elite stores the locale in a &lt;code&gt;NEXT_LOCALE&lt;/code&gt; cookie, so URLs have no prefix.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Adding a Language&lt;/b&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the locale code to &lt;code&gt;languages.supported&lt;/code&gt; in &lt;code&gt;site.config.json&lt;/code&gt; and add an entry under &lt;code&gt;languages.locales&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create &lt;code&gt;messages/.json&lt;/code&gt; mirroring &lt;code&gt;messages/en.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;next-intl&lt;/code&gt; runtime picks it up automatically; types update from &lt;code&gt;src/global.d.ts&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Site &amp;amp; SEO Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite/blob/main/src/features/site/site.config.json" rel="noopener noreferrer"&gt;&lt;code&gt;src/features/site/site.config.json&lt;/code&gt;&lt;/a&gt; is the single source of truth for SEO metadata, dynamic sitemaps, localized routes, and the PWA manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"appName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Next Elite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"domain"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://yourdomain.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tagline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Frontend-first, API-driven, batteries included."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Next Elite - Production-Ready SaaS Boilerplate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Frontend-first Next.js 16.4 + React 19 boilerplate with i18n, RBAC and BetterAuth."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file is validated against a Zod schema in the unit tests, so a typo fails &lt;code&gt;npm run check&lt;/code&gt; instead of breaking production.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;View Forms Usage (React Hook Form + Zod)&lt;/b&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;zodResolver&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@hookform/resolvers/zod&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useForm&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-hook-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;loginSchema&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;LoginInput&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/features/auth/schemas/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;zodResolver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loginSchema&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;defaultValues&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2 id="project-structure"&gt;6. Clean Feature-Based Directory Structure&lt;/h2&gt;

&lt;p&gt;Next Elite uses a &lt;strong&gt;Feature-Based (Vertical Slice) Architecture&lt;/strong&gt; under &lt;code&gt;src/features/&lt;/code&gt;. Each folder contains its own hooks, schemas, server helpers, and config. Shared UI and layout pieces live under &lt;code&gt;src/components/&lt;/code&gt;, and cross-cutting infra lives under &lt;code&gt;src/libs/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;View Directory Structure&lt;/b&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── .github/
│   ├── workflows/            CI: check.yml (incl. demo removal) + playwright.yml
│   ├── dependabot.yml        Dependency updates
│   └── renovate.json         Dependency updates
├── .claude/skills/           project-standards skill for AI coding agents
├── config/                   Vitest, Playwright, and Knip configs
├── e2e/                      Playwright specs
├── messages/                 next-intl translations (en, bn, ar, fr, es, zh)
├── public/                   Static assets + llms.txt
├── scripts/                  remove-demo.mjs (npm run demo:remove)
├── .vscode/                  Oxc extension + format-on-save settings
├── components.json           shadcn/ui CLI config
├── .env.example              Environment variable template
├── .npmrc                    save-exact=true (pinned dependencies)
├── .oxlintrc.json            Oxlint rules (Next.js, TypeScript, React, Unicorn)
├── .oxfmtrc.json             Oxfmt formatter config (Tailwind class sorting)
├── Dockerfile                Multi-stage Distroless build + HEALTHCHECK
├── docker-compose.yml
├── next.config.mjs           Security headers, Sentry, next-intl, standalone output
├── postcss.config.mjs        Tailwind CSS v4
├── package.json              scripts + Commitlint config
├── package-lock.json
├── tsconfig.json
├── lefthook.yml              Git hooks (pre-commit, commit-msg, pre-push)
├── AGENTS.md                 Rules for AI coding agents
├── src/
│   ├── _demo(DELETE)/        Landing page, showcase, demo accounts (delete for your app)
│   ├── app/                  App Router
│   │   ├── (auth)/           Login, register, &amp;amp;amp; reset-password pages
│   │   ├── (public)/         Public pages
│   │   ├── (protected)/      Authenticated area + RBAC
│   │   │   ├── @admin/       Admin slots (dashboard, analytics, profile, settings)
│   │   │   ├── @user/        User slots (dashboard, analytics, profile, settings)
│   │   │   ├── unauthorized/ Shown when a role lacks permission
│   │   │   └── layout.tsx    Picks slot based on permissions
│   │   ├── api/              Route handlers (BetterAuth, health)
│   │   ├── styles/           tokens.css, base.css, components.css (theme transition)
│   │   ├── error.tsx         Error boundary (reports to Sentry)
│   │   ├── global-error.tsx  Root error boundary
│   │   ├── not-found.tsx     404 page
│   │   ├── fonts.ts          Inter typography configuration
│   │   ├── layout.tsx        Root layout, SEO, fonts, providers
│   │   ├── providers.tsx     Theme + Auth + TanStack Query
│   │   ├── manifest.ts       Web app manifest
│   │   ├── robots.ts         robots.txt
│   │   └── sitemap.ts        Dynamic sitemap
│   ├── components/
│   │   ├── auth/             Auth forms &amp;amp;amp; particle animation canvas
│   │   ├── icons/            Centralized SVG icon components &amp;amp;amp; barrel export
│   │   ├── layout/           App shell, navigation sidebars, topbar &amp;amp;amp; branding
│   │   ├── shared/           Page header, theme &amp;amp;amp; language controls, user dropdown
│   │   └── ui/               shadcn/ui primitives &amp;amp;amp; custom components
│   ├── features/             Feature modules (vertical slices)
│   │   ├── auth/             BetterAuth + RBAC (hooks, lib, rbac, schemas, server)
│   │   ├── i18n/             next-intl config (routing, request, actions)
│   │   └── site/             site config, schema, base URL + locale utilities
│   ├── hooks/                Shared React hooks
│   ├── libs/                 Cross-cutting infra (env, query-client, utils)
│   ├── tests/                Unit/component tests (components, features, libs) + renderWithProviders
│   ├── instrumentation.ts    Server Sentry init
│   ├── instrumentation-client.ts  Client Sentry init (lazy)
│   └── global.d.ts           next-intl type augmentation
└── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2 id="configuration"&gt;7. Configuration &amp;amp; Environment Variables&lt;/h2&gt;

&lt;p&gt;Environment variables are validated on the server by &lt;code&gt;src/libs/env.ts&lt;/code&gt; (T3 Env).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;BETTER_AUTH_URL&lt;/code&gt; is optional - derived from &lt;code&gt;VERCEL_URL&lt;/code&gt; in production, &lt;code&gt;http://localhost:6767&lt;/code&gt; locally.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BETTER_AUTH_SECRET&lt;/code&gt; (32+ chars) must be set at runtime in production. A missing secret logs a warning instead of crashing the build.&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;SKIP_ENV_VALIDATION=true&lt;/code&gt; in CI / Docker build steps when env vars aren't available yet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Key variables:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BETTER_AUTH_SECRET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auth signing secret (32+ chars)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GOOGLE_CLIENT_ID/SECRET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Optional Google OAuth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NEXT_PUBLIC_GOOGLE_AUTH_ENABLED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Show Google sign-in button&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AUTH_ADMIN_EMAILS&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Comma-separated admin role emails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NEXT_PUBLIC_DEMO_MODE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Demo credentials panel (disable for prod)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;SENTRY_DSN&lt;/code&gt; / &lt;code&gt;NEXT_PUBLIC_SENTRY_DSN&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Optional Sentry error tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NEXT_PUBLIC_APP_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Public app URL (SEO/OAuth)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2 id="development-testing"&gt;8. Development, Testing &amp;amp; CI/CD&lt;/h2&gt;

&lt;h3&gt;
  
  
  Editor Setup
&lt;/h3&gt;

&lt;p&gt;Install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=oxc.oxc-vscode" rel="noopener noreferrer"&gt;Oxc VS Code extension&lt;/a&gt; (&lt;code&gt;oxc.oxc-vscode&lt;/code&gt;) for format-on-save and Oxlint fix-on-save. Project settings in &lt;code&gt;.vscode/settings.json&lt;/code&gt; are preconfigured.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit / component:&lt;/strong&gt; Vitest + React Testing Library (&lt;code&gt;config/vitest.config.ts&lt;/code&gt;). Tests live in &lt;code&gt;src/tests/&lt;/code&gt;, mirroring the &lt;code&gt;src/&lt;/code&gt; folder structure. Use &lt;code&gt;renderWithProviders&lt;/code&gt; from &lt;code&gt;@/tests/render&lt;/code&gt; for components that need app context (i18n, theme, auth, React Query). Plain &lt;code&gt;render&lt;/code&gt; is fine for isolated UI primitives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end:&lt;/strong&gt; Playwright in &lt;code&gt;e2e/&lt;/code&gt; checks the home page, the health endpoint, and the security headers. It runs on port &lt;strong&gt;6767&lt;/strong&gt; (&lt;code&gt;127.0.0.1&lt;/code&gt;). Local runs use &lt;code&gt;next dev&lt;/code&gt; (all browsers); CI uses production &lt;code&gt;next start&lt;/code&gt; (Chromium only). Run &lt;code&gt;playwright:install&lt;/code&gt; before the first E2E run; on Linux, WebKit needs &lt;code&gt;playwright:install:deps&lt;/code&gt; (sudo). Stop &lt;code&gt;npm run dev&lt;/code&gt; before &lt;code&gt;npm run e2e&lt;/code&gt; - E2E starts its own server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CI/CD Pipeline
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.github/workflows/check.yml&lt;/code&gt; - typecheck → lint → knip → unit tests → build on every push and PR, plus a job that runs &lt;code&gt;npm run demo:remove&lt;/code&gt; on a clean copy and checks that the app still passes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.github/workflows/playwright.yml&lt;/code&gt; - build → Playwright E2E (Chromium, production server).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.github/renovate.json&lt;/code&gt; - weekly grouped updates, automerging patch and minor versions while keeping majors separate.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.github/dependabot.yml&lt;/code&gt; - weekly grouped npm and GitHub Actions updates.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2 id="architectural-caveats"&gt;9. Architectural Caveats: What Next Elite is NOT&lt;/h2&gt;

&lt;p&gt;To keep the boilerplate clean and adaptable, I made specific design trade-offs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;No Database Bundled:&lt;/strong&gt; There is no Prisma, Drizzle, Postgres, or MongoDB setup. Next Elite is built to communicate with an external API. Without a database configured, BetterAuth falls back to its built-in in-memory store, which is perfect for the demo and local development.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple RBAC System:&lt;/strong&gt; The starter RBAC covers two roles (&lt;code&gt;user&lt;/code&gt; and &lt;code&gt;admin&lt;/code&gt;) with a fast-path admin list via environment variables. For complex multi-tenant permissions, map roles in your main database and API layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie-Based i18n:&lt;/strong&gt; Storing the locale in a cookie rather than a path prefix (like &lt;code&gt;/en/dashboard&lt;/code&gt;) keeps routes simpler, but public pages render per request, and per-locale SEO indexing would need a custom path-prefixed router setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-Memory Auth Store:&lt;/strong&gt; Because of that fallback, users and sessions live in server memory by default. They're lost on restart and aren't shared between server instances, so production needs a database adapter (or point auth at your own backend).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2 id="production-checklist"&gt;10. Production Checklist: Going Live&lt;/h2&gt;

&lt;p&gt;Before deploying Next Elite to production, run through these essential steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configure Auth Secrets:&lt;/strong&gt; Set &lt;code&gt;BETTER_AUTH_SECRET&lt;/code&gt; (at least 32 characters long) in your hosting dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a Database Adapter:&lt;/strong&gt; Connect BetterAuth to a database (for example Postgres via Drizzle or Prisma) so users and sessions survive restarts and work across multiple instances. Optionally add Redis as secondary storage for sessions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remove the Demo:&lt;/strong&gt; Run &lt;code&gt;npm run demo:remove&lt;/code&gt;, or at least set &lt;code&gt;NEXT_PUBLIC_DEMO_MODE=false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Link Your API:&lt;/strong&gt; Point &lt;code&gt;NEXT_PUBLIC_APP_URL&lt;/code&gt; at your live domain and wire TanStack Query hooks to your REST/GraphQL/BFF service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update SEO Metadata:&lt;/strong&gt; Update &lt;code&gt;src/features/site/site.config.json&lt;/code&gt; with your project domain, OG image, and app description, and replace the images in &lt;code&gt;public/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wire Password Reset:&lt;/strong&gt; Connect the password reset form to your backend's reset email flow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enable Error Tracking:&lt;/strong&gt; Set &lt;code&gt;SENTRY_DSN&lt;/code&gt; and &lt;code&gt;NEXT_PUBLIC_SENTRY_DSN&lt;/code&gt; to activate Sentry instrumentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set &lt;code&gt;SKIP_ENV_VALIDATION=true&lt;/code&gt;&lt;/strong&gt; in CI/Docker build steps when env vars aren't available at build time.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2 id="contributing"&gt;11. Contributing &amp;amp; Open Source&lt;/h2&gt;

&lt;p&gt;Next Elite is free and open-source under the &lt;strong&gt;MIT license&lt;/strong&gt;. Contributions, bug reports, and discussions are welcome!&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fork &amp;amp; branch from &lt;code&gt;main&lt;/code&gt; (&lt;code&gt;feat/...&lt;/code&gt;, &lt;code&gt;fix/...&lt;/code&gt;, &lt;code&gt;docs/...&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Ensure &lt;code&gt;npm run check&lt;/code&gt; passes locally.&lt;/li&gt;
&lt;li&gt;Use Conventional Commits.&lt;/li&gt;
&lt;li&gt;Open a pull request.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  If this boilerplate saved you time, a star helps more devs discover it
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://nextelite.salmanshahriar.com/" rel="noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;GitHub Repo&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://github.com/salmanshahriar/Next-Elite/generate" rel="noopener noreferrer"&gt;Use Template&lt;/a&gt;&lt;/strong&gt; · &lt;strong&gt;&lt;a href="https://vercel.com/new/clone?repository-url=https://github.com/salmanshahriar/Next-Elite" rel="noopener noreferrer"&gt;Deploy on Vercel&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>boilerplate</category>
      <category>betterauth</category>
    </item>
  </channel>
</rss>
