Most "website templates" you buy online are a single landing page with a hero, three feature cards, and a dead "Contact" button. I wanted the opposite: 20 templates that are actually shippable websites — multiple routes, working navigation, real forms, and zero broken buttons. This post is the architecture I landed on.
The constraint that shaped everything: one config file
The single most important decision was that a buyer should never have to hunt through JSX to rebrand a template. Every template reads from one data source — src/lib/data.ts (or content.ts / siteConfig.ts depending on the template). Change the company name, palette, copy, nav links, and pricing in that one file, and the entire site updates.
// src/lib/data.ts
export const site = {
name: "Nexus",
tagline: "Ship faster with the all-in-one platform",
nav: [
{ label: "Features", href: "/features" },
{ label: "Pricing", href: "/pricing" },
{ label: "Blog", href: "/blog" },
],
brand: { primary: "#6366f1", accent: "#22d3ee" },
} as const;
Components consume site rather than hardcoding strings. This is the difference between a template a non-developer can use and one only the author understands.
Stack: boring on purpose
-
Next.js 15, App Router — file-system routing, server components by default,
generateMetadatafor per-route SEO. - Tailwind CSS — utility classes keep the design tokens in one place and make rebrands a search-and-replace, not a refactor.
-
TypeScript, strict — every template ships with
tsc --noEmitreturning 0 errors andnext buildreturning 0 errors. That's the bar before it counts as done.
No exotic state libraries, no half-integrated CMS. Boring tech means the buyer can read it on day one.
Multi-page from the start
Each template has at least 5 routes (some have 20+): home, a features/services page, pricing, a blog index with dynamic [slug] posts, and a contact page. The nav and footer live in layout.tsx with an active-link helper so the current page is highlighted — small detail, but it's what separates "a page" from "a site."
// active link in the shared layout
const pathname = usePathname();
const isActive = (href: string) =>
pathname === href ? "text-brand" : "text-muted hover:text-fg";
Forms that actually do something
Every contact form has client-side validation, a success state, and posts to a real /api/contact route handler. Where a template implies a transaction (an e-commerce checkout, a crypto swap), the demo behavior is honestly labeled — e.g. "demo checkout — no real payment" or "not investment advice." A template that pretends to charge a card is a liability, not a feature.
The honesty test
I almost shipped these as single-page landings. A blunt piece of feedback stopped me: a one-page "template" sold as a website feels a little like a scam. So the rule became: if a buyer drops their content in, they should get a real multi-page site, not a glorified hero section. That reframed the whole project.
See them live
All 20 are deployed as live demos (e.g. modern SaaS, AI startup, digital agency). If you want the source, they're available as single templates or a full bundle on my site.
If you are trying to turn a Next.js site into revenue, I also offer a focused audit of the landing, payment path, webhook/access unlock, and launch blockers: https://productized-webdev.vercel.app/audit
Direct template checkout:
- 20-template bundle: https://cengokurtoglu.gumroad.com/l/vuhstz
- AI startup template: https://cengokurtoglu.gumroad.com/l/mmpgds
- Modern SaaS template: https://cengokurtoglu.gumroad.com/l/butotw What would you add to a template before calling it "production-ready"? I'm curious where other people draw the line.
Top comments (0)