I built a site with 510 free calculation tools — and every single page is statically generated at build time. No database. No server-side rendering. Just Next.js SSG and JSON.
Here's the architecture behind keisan-tools.
The Concept
Japanese users search for specific calculators constantly: BMI, mortgage payments, age calculators. Each query has decent search volume but low competition.
Instead of building 10 tools manually, I built a system that generates tools from configuration files.
Architecture
keisan-tools/
├── data/
│ └── tools.json # 510 tool definitions
├── app/
│ └── [category]/
│ └── [slug]/
│ └── page.tsx # Dynamic route
├── lib/
│ ├── calculator.ts # Calculation engine
│ └── tools.ts # Tool loader
└── next.config.js # SSG configuration
Each tool is defined as a JSON object:
{
"slug": "bmi-calculator",
"category": "health",
"title": "BMI Calculator",
"inputs": [
{ "name": "height", "label": "Height (cm)", "type": "number" },
{ "name": "weight", "label": "Weight (kg)", "type": "number" }
],
"formula": "weight / ((height / 100) ** 2)",
"output_label": "Your BMI"
}
Add a JSON entry, get a fully functional calculator page with SEO metadata, structured data, and responsive UI. No code changes needed.
Static Generation at Scale
Next.js generateStaticParams creates all 510 pages at build time:
export async function generateStaticParams() {
const tools = getAllTools();
return tools.map(tool => ({
category: tool.category,
slug: tool.slug,
}));
}
Build time for 510 pages: ~45 seconds on Vercel. Each page is a static HTML file served from the CDN.
SEO: JSON-LD Structured Data
Every tool page includes structured data:
{
"@context": "https://schema.org",
"@type": "WebApplication",
"name": "BMI Calculator",
"applicationCategory": "UtilityApplication",
"offers": {
"@type": "Offer",
"price": "0"
}
}
This tells Google: "This is a free web application." It helps with rich snippets in search results.
Categories
The 510 tools span 20+ categories:
| Category | Tools | Examples |
|---|---|---|
| Health | 35 | BMI, calories, ideal weight |
| Finance | 68 | Loan, compound interest, tax |
| Math | 45 | Percentage, ratio, statistics |
| Date/Time | 28 | Age, date diff, countdown |
| Unit Conversion | 52 | Length, weight, temperature |
| Real Estate | 22 | Mortgage, rent vs buy |
| Investment | 31 | NISA, iDeCo, dividends |
| Energy | 18 | Solar panel, electricity savings |
Performance
- Lighthouse score: 95+
- First Contentful Paint: < 1s
- Time to Interactive: < 1.5s
- Bundle size: ~80KB gzipped
Static files + CDN = fast everywhere.
Key Takeaway: Configuration Over Code
The biggest lesson: don't build 510 pages, build 1 page that reads 510 configurations.
This pattern works for any content-heavy site:
- Recipe sites (ingredients + steps as JSON)
- Product comparison pages (specs as JSON)
- Documentation sites (API endpoints as JSON)
If your pages share the same layout but different data, SSG + JSON is the answer.
Tech Stack
- Next.js 16 (App Router, SSG)
- TypeScript + Tailwind CSS
- Vercel (hosting, free tier)
- Google Analytics 4
Total monthly cost: $0.
Have you built content-heavy static sites? What patterns have worked for scaling to hundreds or thousands of pages?
Top comments (0)