Next.js SaaS starter + shadcn/ui: compatible, not locked

Every paid Next.js starter says it "uses shadcn/ui". Almost none of them tell you what happens when you run npx shadcn@latest add inside their repo six months later. This page answers that, then argues honestly against the free official starter — the one most people should probably use.

Last updated: Verified against: next 15.5.14, react 19.2.4, shadcn CLI 4.13.0 Live demo

In short

SaaS Starter does not generate its UI with the shadcn CLI. The ten components in src/components/ui/ are hand-written on shadcn's token contract and use shadcn's exact cn() helper. Because the repo ships a components.json, the shadcn CLI, the registry and the MCP all work against it, and anything you pull in inherits the theme without edits. There is no Radix and no class-variance-authority in the box — Radix arrives only when you add a component that needs it.

The question nobody in this search result answers

Search for a Next.js SaaS starter with shadcn and you get lists. Which kits use shadcn, how many stars they have, what they cost. Fine. But that is not the thing you are actually nervous about.

The real worry is narrower. You chose shadcn deliberately — you wanted to own the components, paste them from a registry, and let your editor's MCP pull new ones on demand. Then you consider paying $149 for a starter, and the obvious risk is that the kit has quietly built its own UI layer on top, so the registry, the CLI and the MCP stop being useful the day after you buy. That is why the free official starter feels like the safe default: it is canonical shadcn, and nothing sits between you and the registry.

That fear is reasonable. It is also testable in about sixty seconds, which is what the rest of this page is about. We ran the test on our own repo and published what came out, including the part that did not work at first.

What "shadcn-compatible" means here, precisely

Let's be exact, because this is the kind of claim buyers verify thirty seconds after purchase and request a refund over. Three separate statements, all true:

1. Our components were not generated by shadcn.

button.tsx, card.tsx, input.tsx, modal.tsx, badge.tsx, avatar.tsx, skeleton.tsx, spinner.tsx, textarea.tsx and toggle-theme.tsx were written by hand. They use a plain object for variants, not cva, and they wrap native elements, not Radix primitives. If you came here believing you were buying vendored shadcn source, you are not, and we would rather you know now.

2. They sit on shadcn's token contract.

src/lib/utils.ts exports shadcn's exact cn()twMerge(clsx(inputs)), character for character. Our buttons read --muted, --accent-foreground, --destructive and friends. Those are shadcn's canonical variable names, not ours.

3. The CLI, registry and MCP work against the repo.

components.json ships in the root, pointing at src/styles/globals.css and the @/lib/utils alias. That file is the thing the CLI, the registry and the shadcn MCP all read. Without it, none of them can see your project.

The sixty-second test, and its actual output

Here is the whole proof. Clone the repo, then:

$ npx shadcn@latest add dialog

 Checking registry.
 Installing dependencies.
 Created 1 file:
  - src/components/ui/dialog.tsx

The interesting part is not that it succeeded. It is the top of the file it wrote:

import { Dialog as DialogPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"

A stock registry component resolved our hand-rolled cn() and composed our hand-rolled Button. No edits. That is the whole argument for the token contract: the boundary between "our code" and "registry code" is just CSS variables, so the two sides compose instead of fighting.

We also checked that the theme genuinely lands rather than assuming it. Compiling the stylesheet and grepping the output, all seventeen utilities the dialog relies on resolve to our variables:

.bg-popover     { background-color: var(--popover); }
.bg-destructive { background-color: var(--destructive); }

The part that did not work first time

Running that test is how we found a real hole. The generated dialog uses animate-in, fade-in-0 and zoom-in-95. Tailwind v4 core does not ship those keyframes, so the dialog mounted correctly themed but completely unanimated. The fix is one dependency (tw-animate-css) and one @import line in globals.css, and both are already in the repo as of 16 July 2026 — so shadcn add now works for animated components too. We are documenting it because a "zero edits" claim that quietly needed one edit is exactly the kind of thing that earns a refund.

One honest consequence. Because we do not vendor Radix, adding a registry component that needs it will pull radix-ui into your dependency tree at that moment. We think that is the right default — you get primitives when you ask for them, not before. If you would rather every primitive be present on day one, the official starter already does that, and that is a legitimate reason to prefer it.

The matrix, including the free one that beats us on price

Most comparison tables on paid-starter sites quietly omit nextjs/saas-starter, which is the single most likely thing you are comparing against. Ours used to as well. It is here now, in the first column, because a comparison that hides the obvious alternative is not a comparison.

The last row is the one no competitor publishes: when each kit last shipped a commit. For closed-source kits that number is simply not verifiable from outside, and we say so rather than guessing.

Feature comparison between the free official nextjs/saas-starter and SaaS Starter, verified 16 July 2026
nextjs/saas-starter (official, free) SaaS Starter ($149) Typical paid kit ($199–$299)
Price / licence $0 — MIT $149 — commercial, unlimited projects at $299 $199–$299 — commercial
GitHub stars 15,957 Private repo — not comparable Private repos — not comparable
Next.js / React 15.6.0-canary.59 / 19.1.0 15.5.14 / 19.2.4 (both stable) Varies — check package.json
Database / ORM Postgres + Drizzle Postgres + Prisma Prisma or Supabase
Auth Hand-rolled JWT cookie Clerk (hosted) NextAuth or Supabase
shadcn/ui depth Canonical — generated by the CLI, Radix + cva vendored in Compatible — hand-rolled on the token contract, components.json ships, CLI/registry/MCP work, no Radix until you add one Usually canonical, sometimes wrapped
Payments Stripe + Customer Portal Stripe + webhooks + Customer Portal Stripe
Admin panel + MRR No Yes — users, metrics, MRR Rare or basic
Transactional email No Resend + React Email templates Usually
Blog No MDX built-in Sometimes
Tests No test script 39 Vitest tests, all green Rare
i18n No next-intl, 8 locales Rare
Teams / RBAC Owner & Member roles, activity log User & Admin roles only — no multi-tenant teams Varies
Docs README 6 web docs pages + AI prompt library README or docs site
Last commit 11 December 2025 (7 months ago) 15 July 2026 Closed source — unverifiable

Official starter figures read from the GitHub API and package.json on main, 16 July 2026. Stars and commit dates move; re-check them before you decide. The "typical paid kit" column is deliberately vague because we will not publish specific numbers about closed-source competitors we cannot verify.

$0 vs $149: what the official starter makes you build yourself

The free starter's README does not oversell itself. It says, verbatim:

"While this template is intentionally minimal and to be used as a learning resource, there are other paid versions in the community which are more full-featured."

nextjs/saas-starter README

We are not going to argue with that. It is an excellent piece of code and it does exactly what it says. It gets you auth, Stripe, Drizzle and real shadcn/ui for nothing. The honest pitch for paying us is not that it is bad — it is that it deliberately stops at the point where the boring six weeks begin. Here is that delta, with the time it actually took us to build each piece:

Work the free official starter leaves you to build, with our build times
What you'd build yourself Our build time The part that eats the hours
Admin panel + MRR metrics ~14 h Not the tables — reconciling MRR against Stripe when subscriptions change mid-period
Transactional email (Resend + React Email) ~8 h Templates are fast; making them survive Outlook and dark mode is not
MDX blog ~6 h Frontmatter, draft handling, RSS, and sane typography defaults
Vitest suite (39 tests) ~10 h Mocking Stripe and Clerk so tests run without network or keys
Dark mode (next-themes) ~3 h Killing the flash of wrong theme on first paint
i18n (next-intl, 8 locales) ~16 h Routing and hreflang, not translation
Docs site + AI prompt library ~12 h Writing, mostly. There is no shortcut

That is roughly 69 hours, and that is our time on a stack we wrote and know by heart. Your number will be higher on unfamiliar code — assume something like 90 to 100 hours, and more if you have not wired Stripe webhooks before. At any freelance rate you would recognise, that is the entire argument. If your hourly rate is above about $2, $149 is cheaper than building it.

The inverse is also true and worth saying plainly: if those seven rows are things you do not need, the free starter is the correct choice and you should close this tab. A blog and eight locales are not worth $149 to someone validating an idea over a weekend.

Stack currency, stated plainly

We run Next.js 15.5.14 and React 19.2.4. Not Next.js 16. If a comparison page tells you the free official starter is on Next.js 16 and we are behind, check its package.json yourself — it pins next@15.6.0-canary.59. Both kits are on Next.js 15. Theirs is a canary build, ours is a stable release, and neither of those facts is worth much marketing noise.

Our position on Next.js 16: we will move when the ecosystem does, not before. A starter's job is to be boring on release day. Being one stable minor behind and fully green beats being on a canary that breaks Clerk or Prisma in a way you get to debug on our behalf.

The freshness number that actually matters is the last row of the matrix above. The free starter's most recent commit, as of 16 July 2026, is from 11 December 2025 — and it was a security bump (CVE-2025-55182). That is not an attack on it; unmaintained is the normal state of a repo whose stated job is teaching. But if you adopt it, understand that keeping it current is now your job, and that is a real cost you should price in next to $149.

What's not included, and who should not buy this

Every kit in this search result lists what it has. None list what they lack, which is the cheaper and more useful list. Ours:

No multi-tenant teams

Roles are User and Admin. No organisations, no invitations, no per-seat billing. The free official starter actually beats us here with Owner/Member and an activity log.

Auth is Clerk, not yours

A third-party dependency with its own pricing beyond the free tier. If self-hosted auth is a requirement, do not buy this.

Prisma, not Drizzle

If you have already standardised on Drizzle or Supabase, swapping the ORM will cost you more than the kit saves.

Components are not vendored shadcn

Covered above. If you specifically want Radix primitives and cva already sitting in your repo, the official starter gives you that for free.

No usage-based or metered billing

Flat subscription tiers only. Metered billing is yours to build.

No public star count

It is a private repo, so you cannot audit the code before paying. That is a genuine disadvantage against a 15,957-star MIT repo, and the 14-day refund exists because of it.

If you are learning how auth and billing work, do not buy this — you would be paying to skip the education you are after. Clone the free one. This kit is for people who have already built this plumbing at least once, know exactly how long it takes, and would rather not do it a third time.

Questions people actually ask

Does SaaS Starter use shadcn/ui? +

Not literally. The ten components in src/components/ui/ were written by hand, not generated by the CLI. They are built on shadcn's token contract and use shadcn's exact cn(), and the repo ships a components.json, so the CLI, registry and MCP all work against it. Registry components you add inherit the theme with no edits.

Can I run npx shadcn add inside it? +

Yes, and you should test it before trusting us. npx shadcn@latest add dialog writes src/components/ui/dialog.tsx and it renders themed immediately, because globals.css maps our variables onto the utility names shadcn components expect.

Does a paid starter cut me off from the shadcn registry? +

It can, if the kit wraps or vendors its UI behind custom abstractions. Ours does not. There is no Radix and no class-variance-authority in package.json, so nothing intercepts a registry component. Radix enters your tree only when you add something that needs it.

Is the free official nextjs/saas-starter good enough? +

For learning, yes — its own README says it is "intentionally minimal and to be used as a learning resource". It ships Postgres, Drizzle, Stripe and real shadcn/ui under MIT. It has no admin panel, no MRR metrics, no emails, no blog, no tests and no i18n, and as of 16 July 2026 its last commit was 11 December 2025.

Is SaaS Starter on Next.js 16? +

No. It runs Next.js 15.5.14 and React 19.2.4, both stable. The free official starter is not on Next.js 16 either — it pins next@15.6.0-canary.59. Anyone claiming a Next.js 16 gap between the two is reading marketing copy rather than package.json.

Who should not buy this? +

Anyone who wants self-hosted auth instead of Clerk, anyone committed to Drizzle or Supabase, anyone who needs multi-tenant teams with per-seat billing, and anyone whose goal is to learn how auth and billing work rather than skip building them. In those cases the free official starter or a from-scratch build is the better call.

Still think it's worth the 69 hours?

Then clone the free one — genuinely. If not, $149 gets you the Starter licence for one project, $299 covers unlimited projects, and both include 14-day refunds precisely because you cannot read the code first.

One-time payment · 14-day refund · Instant GitHub access · Read the docs before buying