<?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;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;Next.js 16.3, React 19, TypeScript 6&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 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, nothing security-critical lives only in middleware.&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;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. RTL support in particular is something most of the boilerplates in section 2 simply don't ship.&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.&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, with a live &lt;code&gt;/ui-components&lt;/code&gt; showcase page. Because they're code in your repo rather than an imported library, extending one doesn't mean waiting on someone else's release.&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.&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, &lt;code&gt;npm run check&lt;/code&gt; as a single CI gate: typecheck, lint, dead code, tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observability and deployment that aren't afterthoughts.&lt;/strong&gt; Sentry, Vercel Analytics, and a &lt;code&gt;/api/health&lt;/code&gt; endpoint. Standalone Docker output with multi-arch builds (amd64/arm64) for self-hosting on ARM, Dokploy-ready, or one click to Vercel. The project's own Lighthouse report shows 100 across all four categories on the default build.&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;/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.3 and React 19 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://next-elite-boilerplate.vercel.app/" 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 everything under &lt;code&gt;src/features/&lt;/code&gt;, where each feature owns its own components, hooks, schemas, and server logic:&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 + auth-client singletons
│   ├── server/       # Server-only helpers (getCurrentUser)
│   ├── hooks/        # Auth provider + useAuth hook
│   ├── demo/         # Self-contained demo module (delete for prod)
│   ├── rbac/         # permissions, roles, can, require
│   └── schemas/      # Zod login + register schemas
├── i18n/              # next-intl config (routing, request, actions)
└── site/              # siteConfig + locale utilities
&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; (primitives, layout shell, icons), 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;&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.&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 React 19.2's newer primitives (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.&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 &lt;code&gt;AUTH_ADMIN_EMAILS&lt;/code&gt;. Authorization is separate and server-side:&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, not in middleware, and redirects to &lt;code&gt;/login&lt;/code&gt; or &lt;code&gt;/unauthorized&lt;/code&gt; before any protected content renders. Sessions are BetterAuth's local sessions by default; the project's own production checklist calls out that a shared session/Redis adapter is needed once you run more than one server instance, which is a real limitation worth knowing before you deploy multi-instance.&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:&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/dashboard/     # Admin dashboard slot
  ├── @user/dashboard/      # User dashboard slot
  └── 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;roles.ts&lt;/code&gt;, and optionally add a parallel route slot. It intentionally does not attempt multi-tenant, hierarchical, or resource-scoped permissions; the README says as much: 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, that's 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 three 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 missing &lt;code&gt;BETTER_AUTH_SECRET&lt;/code&gt; is a build-time problem, not a 2am production one.&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;, permission strings 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;/ul&gt;

&lt;p&gt;TypeScript 6 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 (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. 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 in the project's own caveats: cookie-based locale means simpler routing, but 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. If per-locale SEO is a hard requirement for your product, that'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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; the boilerplate ships 50+ of these primitives under &lt;code&gt;src/components/ui/&lt;/code&gt;, plus a live &lt;code&gt;/ui-components&lt;/code&gt; showcase page so you can see what exists before building a new one from scratch. 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 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;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 &lt;code&gt;staleTime&lt;/code&gt;, &lt;code&gt;gcTime&lt;/code&gt;, and retry defaults, 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 build-time 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; every variable is documented in &lt;code&gt;.env.example&lt;/code&gt; and validated by &lt;code&gt;src/libs/env.ts&lt;/code&gt; via T3 Env. 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.3 + 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;&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, 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.&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, not marketing claims but numbers Vercel has published in its own release notes. 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;&lt;strong&gt;How Next-Elite handles it:&lt;/strong&gt; &lt;code&gt;npm run analyze&lt;/code&gt; wraps &lt;code&gt;@next/bundle-analyzer&lt;/code&gt; for exactly this reason, so you can see where your bundle spends its weight instead of assuming. The project's own Lighthouse report, checked into the repo, shows 100 across all four categories on the default build, which reflects the defaults (Server Components, minimized client JS, optimized images, centralized SEO metadata) rather than any single trick. That number describes the starting point on a mostly-empty app; it's not a guarantee that survives you adding a heavy client-side chart library without thinking about it. Turbopack is the default dev and build bundler, inherited from Next.js 16 rather than something Next-Elite configures itself.&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;), with a &lt;code&gt;renderWithProviders&lt;/code&gt; helper 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, 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. 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;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.&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;), Vercel Analytics is included for basic page analytics, and 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, and a real health check 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 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, a Raspberry Pi). 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;/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;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;strong&gt;What you get, in one pass:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 16.3 (App Router, Turbopack, Server Actions) + React 19 + TypeScript 6&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 on Tailwind CSS v4 and Radix UI&lt;/li&gt;
&lt;li&gt;TanStack Query pre-configured for your REST/GraphQL/BFF API&lt;/li&gt;
&lt;li&gt;Sentry + Vercel Analytics + a &lt;code&gt;/api/health&lt;/code&gt; endpoint&lt;/li&gt;
&lt;li&gt;Vitest + React Testing Library + Playwright&lt;/li&gt;
&lt;li&gt;Oxlint + Oxfmt + Knip + Lefthook + Commitlint&lt;/li&gt;
&lt;li&gt;Standalone Docker build, multi-arch (amd64/arm64), Dokploy-ready, one-click Vercel deploy&lt;/li&gt;
&lt;li&gt;SEO metadata, dynamic sitemap, &lt;code&gt;robots.txt&lt;/code&gt;, and PWA manifest from one config file&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 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.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://next-elite-boilerplate.vercel.app/" 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;

</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.3 + React 19 boilerplate designed to consume APIs (REST/GraphQL/BFF) instead of owning a database, allowing you to 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://next-elite-boilerplate.vercel.app/" 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%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9ccdc9cf650sv06i200.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv9ccdc9cf650sv06i200.png" alt="Next.js Elite production-ready SaaS boilerplate cover" width="800" height="533"&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, and CI. &lt;a href="https://next-elite-boilerplate.vercel.app/" 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 (providing just a dark mode toggle and a "TODO: add auth" comment) or too bloated (bundling 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 to build a backend-for-frontend (BFF) architecture, tearing out the built-in database layer from 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 fetching structure flexible. It's built to consume APIs directly, allowing you to 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;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 clean, high-performance tech stack built into Next Elite, broken down by core categories:&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.3 (App Router)&lt;/strong&gt; - Fast, modern React framework with Turbopack, standalone output for Docker/self-hosting, and full support for React 19 features (Server/Client components, Server Actions).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;TypeScript 6&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&lt;/strong&gt; - Built on the latest LTS runtime (22.12+ required).&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 &lt;code&gt;AUTH_ADMIN_EMAILS&lt;/code&gt; or &lt;code&gt;NEXT_PUBLIC_AUTH_ADMIN_EMAILS&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Auth UI &amp;amp; Layout&lt;/strong&gt; - Split-pane authentication pages with a custom WebGL particle background animation, sticky topbar with back navigation, theme toggle, and language switcher.&lt;/li&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 actions, collapsible state, mobile sheet, and topbar breadcrumbs.&lt;/li&gt;
&lt;/ul&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 compile-time).&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;p&gt;&lt;strong&gt;shadcn/ui&lt;/strong&gt; - 50+ highly customizable UI components built with Tailwind CSS, Radix UI, and CVA. Includes a live &lt;code&gt;/ui-components&lt;/code&gt; showcase page.&lt;/p&gt;


  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fnext-elite-boilerplate.vercel.app%2FNextjs-Elite-UI-Image.webp" alt="Next Elite UI Components" width="800" height="400"&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Theme Support&lt;/strong&gt; - Easy light/dark mode transitions via theme toggle.&lt;/p&gt;&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;/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; - Complete error tracking and performance instrumentation for client and server.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Vercel Analytics&lt;/strong&gt; - Built-in page analytics via &lt;code&gt;@vercel/analytics&lt;/code&gt;.&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;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Testing Suite&lt;/strong&gt; - Unit/component testing with Vitest and React Testing Library, and E2E testing with Playwright.&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;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 achieving flawless performance and SEO defaults. Out-of-the-box, the production build scores a perfect &lt;strong&gt;100&lt;/strong&gt; across the board on Lighthouse:&lt;/p&gt;

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

&lt;p&gt;This is achieved by rendering Server Components by default, minimizing client-side javascript, optimizing images, and dynamically serving optimized SEO meta tags from a single configuration file.&lt;/p&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;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fvercel.com%2Fbutton" alt="Deploy with Vercel" width="103" height="32"&gt;&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;blockquote&gt;
&lt;p&gt;[!NOTE]&lt;br&gt;
For production deployments, set &lt;code&gt;NEXT_PUBLIC_DEMO_MODE=false&lt;/code&gt; or remove the self-contained &lt;code&gt;src/features/auth/demo/&lt;/code&gt; module.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Docker Setup
&lt;/h3&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;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, 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; for the full list).&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 analyze&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build with &lt;code&gt;@next/bundle-analyzer&lt;/code&gt;
&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 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 utilizes Next.js &lt;strong&gt;Parallel Routes&lt;/strong&gt; to clean up role-agnostic layouts. The routing structure mounts specific slots based on the user's role:&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/dashboard/     # Admin dashboard slot
  ├── @user/dashboard/      # User dashboard slot
  └── 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;src/features/auth/rbac/roles.ts&lt;/code&gt;.&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 configurations that force prefixes like &lt;code&gt;/en/&lt;/code&gt; or &lt;code&gt;/es/&lt;/code&gt; in the URL (which can clutter routes and create duplicate routing configurations), Next Elite implements zero-prefix cookie-based locales.&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="//src/features/site/site.config.json"&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 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.3 + 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;&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 components, hooks, schemas, and config. Shared UI and layout pieces live under &lt;code&gt;src/components/&lt;/code&gt;, and cross-cutting infra 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 + playwright.yml
│   └── renovate.json         Dependency updates
├── config/                   vitest.config.ts, vitest.setup.ts
├── e2e/                      Playwright specs + playwright.config.ts
├── messages/                 next-intl translations (en, bn, ar, fr, es, zh)
├── public/                   Static assets
├── tests/                    Vitest specs (auth, i18n)
├── components.json           shadcn/ui CLI config
├── .oxlintrc.json            Oxlint rules (Next.js, TypeScript, React, Unicorn)
├── .oxfmtrc.json             Oxfmt formatter config (Tailwind class sorting)
├── knip.json
├── next.config.mjs
├── package.json              scripts + Commitlint config
├── package-lock.json         npm lockfile (single source of truth)
├── proxy.ts                  Next.js 16 network proxy (pass-through)
├── tsconfig.json
├── lefthook.yml              Git hooks (pre-commit, commit-msg, pre-push)
├── src/
│   ├── app/                  App Router
│   │   ├── (auth)/           Login, register, &amp;amp;amp; reset-password pages
│   │   ├── (public)/         Marketing pages (home, ui-components)
│   │   ├── (protected)/      Authenticated area + RBAC
│   │   │   ├── @admin/       Admin slots (dashboard, profile, settings)
│   │   │   ├── @user/        User slots (dashboard, profile, settings)
│   │   │   └── layout.tsx    Picks slot based on permissions
│   │   ├── api/               Route handlers (BetterAuth, health)
│   │   ├── styles/           Design system tokens, base CSS, &amp;amp;amp; animations
│   │   ├── fonts.ts           Inter typography configuration
│   │   ├── layout.tsx         Root layout, SEO, Inter font, 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
│   │   ├── pages/             Landing page &amp;amp;amp; UI components page modules
│   │   ├── shared/            User dropdown, text links, theme &amp;amp;amp; language controls
│   │   └── ui/                50+ shadcn/ui primitives
│   ├── config/                App navigation &amp;amp;amp; feature flags configuration
│   ├── features/              Feature modules (vertical slices)
│   │   ├── auth/               BetterAuth + RBAC
│   │   │   ├── hooks/          Auth provider + useAuth hook
│   │   │   ├── demo/           Self-contained demo module (delete for prod)
│   │   │   ├── rbac/           permissions, roles, can, require
│   │   │   └── schemas/        Zod login + register schemas
│   │   ├── i18n/               next-intl config (routing, request, actions)
│   │   └── site/               siteConfig + locale utilities
│   ├── hooks/                 Shared React hooks (useMobile, etc.)
│   ├── libs/                  Cross-cutting infra (env, query-client, utils)
│   ├── instrumentation.ts     Server Sentry init
│   ├── instrumentation-client.ts  Client Sentry init
│   └── 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;Every variable is documented in &lt;a href="//.env.example"&gt;&lt;code&gt;.env.example&lt;/code&gt;&lt;/a&gt; and validated 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;). Use &lt;code&gt;renderWithProviders&lt;/code&gt; from &lt;code&gt;@tests/utils/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; 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.&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; - groups non-major dependency updates and automerges patches.&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. BetterAuth runs without a database adapter out of the box.&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 on your main database and API layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cookie-Based i18n:&lt;/strong&gt; By storing user localization choice in a cookie rather than a path-prefix (like &lt;code&gt;/en/dashboard&lt;/code&gt;), routes remain simpler, but path-prefixed SEO indexing for multiple locales will require a custom router setup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local BetterAuth Sessions:&lt;/strong&gt; By default, session keys run locally. A session adapter is recommended for production setups using multiple server instances.&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 configuration 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 Session Storage Adapter:&lt;/strong&gt; BetterAuth requires an external database or Redis adapter to manage server sessions in multi-instance production environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disable Demo Mode:&lt;/strong&gt; Set &lt;code&gt;NEXT_PUBLIC_DEMO_MODE=false&lt;/code&gt; or completely delete the &lt;code&gt;src/features/auth/demo/&lt;/code&gt; folder.&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; Change &lt;code&gt;src/features/site/site.config.json&lt;/code&gt; with your project domain, official OG image, and app description.&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;, etc.)&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://next-elite-boilerplate.vercel.app/" 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>
