Skip to main content

Architecture

From 25 repos to 2 archetypes

Rebuilding the same client-project scaffolding by hand, slightly differently each time, is how 25 shipped repos happen instead of one reusable system. An audit of those 25 shipped Next.js repos (8 client sites, 17 personal projects) found they weren't 25 different designs — they were 3 archetypes built on one shared house style, with most of the shared code duplicated by copy-paste rather than packaged. next-starters turns the two highest-value archetypes into clean, genericized starters so a new client project goes from zero to a running app in one command:

  • templates/marketing — a local-business marketing site (salon, trades, service, product), genericized from a real shipped client site.
  • templates/dashboard — a multi-tenant SaaS dashboard / control plane, genericized from a real shipped product.

Shared house style

Every template is built on the same baseline, so a developer moving between scaffolded projects doesn't relearn conventions:

  • Next.js 16 App Router
  • React 19
  • TypeScript throughout
  • Tailwind v4, CSS-first @theme (no tailwind.config.js token sprawl)
  • shadcn/ui ("radix-nova" variant)
  • pnpm exclusively — no npm/yarn lockfiles

Each template is a self-contained standalone project (its own package.json, not workspace-linked to this repo), so the CLI can lift one out cleanly into a brand-new client repo.

The token + module system

Every client-specific value in a template — a brand name, a hex color, a font, a URL — is an UPPER_SNAKE placeholder token like __BRAND_NAME__ or __COLOR_PRIMARY__. Each template declares its tokens and optional modules in a template.config.json:

{
"name": "marketing",
"description": "…",
"tokens": {
"__BRAND_NAME__": { "prompt": "Business name", "default": "Acme Studio" }
},
"modules": {
"booking": { "description": "Booking wizard", "default": false }
},
"postScaffold": ["pnpm install"]
}

Modules are opt-in feature slices (booking wizards, Stripe billing, an admin app) that stay off by default and get enabled per-scaffold with --enable. A moduleFlagsFile in the config tells the CLI which file(s) actually consume the resulting flags, so an enabled module without a real consumption site is a wiring bug the CLI can catch rather than a silent no-op.

Scaffold flow

node bin/create-client.mjs <name> --template <marketing|dashboard> --out <path>


read templates/<template>/template.config.json


resolve tokens (template default < stored answer < --set/--enable)
(prompts interactively unless --yes)


copy template (excluding node_modules/.next/.git/.turbo/dist)


literal-replace every __TOKEN__ across all text files + paths


drop template.config.json, write scaffold.json (records the choices made)


optionally copy .env.example -> .env per file (--env)


run postScaffold commands (pnpm install)


project ready at --out

Packaging strategy

Now: workspace-only. Each template carries its own copy of shared code (ui, config, mock-data, auth, db). The duplication is deliberate — it keeps templates self-contained and unblocked from each other.

Later: de-duplicate one package at a time into published @cogs/* packages, updating templates to consume them as each stabilizes. Dedup never blocks shipping templates.

Skills as reusable capability packages

Beyond the two templates, this repo ships 22 skills — self-contained, documented capabilities (auth flows, environment configuration, Playwright testing conventions, MCP tooling, and more) that can be layered into a scaffolded project, or into an entirely different repo, independent of the scaffold CLI. See the Skills Catalog for the full list.