When I started building BabyNamePick, I knew I wanted every single name to have its own page. With 1,200+ names, that meant 1,200+ statically generated pages — plus category pages, letter pages, and blog posts.
Here's what I learned about scaling static generation.
The Numbers
Our current build generates:
-
1,269 name pages (
/name/[slug]) -
50+ category pages (
/[category]) -
26 letter pages (
/letter/[letter]) -
85+ blog posts (
/blog/[slug]) - Total: ~3,400+ static HTML pages
All from a single names.json file and a TypeScript blog module.
Lesson 1: Keep Your Data Source Simple
We tried a few approaches:
- SQLite → too much overhead for static generation
- Markdown files → too many files to manage
- JSON file → ✅ simple, fast, version-controlled
// data/names.json - 1,269 entries
[
{
"name": "Elara",
"meaning": "Shining light",
"gender": "girl",
"origin": "greek",
"style": ["celestial", "mythological"],
"popularity": "rising",
"startLetter": "E"
}
]
A single JSON file loads in milliseconds, filters in microseconds, and diffs cleanly in git. For our scale (thousands, not millions), it's perfect.
Lesson 2: generateStaticParams Is Your Friend
Next.js App Router's generateStaticParams makes programmatic page generation trivial:
// app/name/[slug]/page.tsx
export async function generateStaticParams() {
const names = await loadNames();
return names.map(name => ({
slug: name.name.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/-+/g, '-')
}));
}
The key insight: slugification must be deterministic. We normalize all names to lowercase with hyphens, and we do it the same way everywhere — in generateStaticParams, in internal links, and in the sitemap.
Lesson 3: Category Pages Are Filtered Views
Instead of maintaining separate data for each category, our categories are just filter functions:
// categoryData.ts
export const categories = [
{
slug: "celtic-names",
title: "Celtic Baby Names",
filterFn: (n) => ["irish","scottish","welsh"].includes(n.origin),
// ...
},
{
slug: "nature-names",
title: "Nature-Inspired Baby Names",
filterFn: (n) => n.style.includes("nature"),
// ...
}
];
A single name like "Rowan" (origin: irish, style: nature) appears on both the Celtic names page AND the Nature names page. No data duplication.
Lesson 4: Build Times Stay Manageable
With ~3,400 pages, our build takes about 2-3 minutes on Vercel. The secret:
- No external API calls during build — everything reads from local files
- Simple page components — no complex data transformations at build time
- Shared data loading — names load once, not per-page
If we grew to 10,000+ pages, we'd consider Incremental Static Regeneration. But at our scale, full rebuilds are fine.
Lesson 5: Sitemap Generation Matters
With 3,400+ URLs, the sitemap is critical for SEO:
// app/sitemap.ts
export default function sitemap(): MetadataRoute.Sitemap {
const namePages = names.map(n => ({
url: `https://babynamepick.com/name/${slugify(n.name)}`,
lastModified: new Date(),
priority: 0.6,
}));
const categoryPages = categories.map(c => ({
url: `https://babynamepick.com/${c.slug}`,
priority: 0.8,
}));
return [...staticPages, ...categoryPages, ...namePages, ...blogPages];
}
We submit this to Google Search Console and let Google crawl systematically.
Lesson 6: Internal Linking Creates a Web
Every name page links to:
- Its origin category (
/irish-names) - Its style categories (
/nature-names,/mythological-names) - Related names (same origin or style)
- Relevant blog posts
Every category page links to:
- All names in that category
- Related categories
- Relevant blog posts
This creates a dense web of internal links that helps Google understand topical relationships and distributes page authority throughout the site.
Performance Results
Because everything is static HTML served from a CDN:
- Time to First Byte: <100ms globally
- Largest Contentful Paint: <1.5s
- Cumulative Layout Shift: 0
- Lighthouse Score: 95+
No server to manage. No database to maintain. No caching to configure.
When NOT to Use This Approach
This pattern works great for:
- Content that changes infrequently (we add names weekly, not hourly)
- Pages that can be fully rendered at build time
- Sites where SEO matters (static HTML is Google's favorite)
It doesn't work for:
- Real-time data (stock prices, live scores)
- User-generated content at scale
- Sites that need per-user personalization
The Bottom Line
Static site generation at scale isn't scary. With a clean data source, deterministic slugification, and smart internal linking, you can build thousands of fast, SEO-friendly pages with minimal infrastructure.
Our entire stack is:
- Data: One JSON file
- Framework: Next.js App Router
- Hosting: Vercel free tier
- Monthly cost: $0
Check it out at BabyNamePick — browse 1,200+ names, explore 50+ categories, or read our blog.
Questions about scaling static generation? Drop them in the comments.
Top comments (0)