Skip to main content

On This Page

Scaling to 1,200+ Calculator Pages with Astro: A Data-Driven Approach

2 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

How I built 1,200+ calculator pages in Astro without writing 1,200 templates

Martin Rodriguez developed Hacé Cuentas, a collection of over 4,100 Spanish-language calculators. He utilized a single template and JSON-driven content to manage thousands of routes while keeping the codebase smaller than when he had only 50 pages.

Why This Matters

Traditional page-per-feature architectures create unsustainable maintenance overhead; updating a single CTA or CSS class across thousands of hand-built templates is computationally and operationally expensive. By decoupling structured content (JSON) from business logic (TypeScript) and presentation (Astro), developers can achieve O(1) template maintenance regardless of the number of generated pages.

Key Insights

  • Separation of Concerns: Use JSON for structured content like labels and FAQs, but TypeScript for math logic to maintain type safety (Rodriguez, 2026).
  • Dynamic Route Generation: Implementing getStaticPaths in Astro allows for build-time generation where adding a new page only requires a new JSON file (Build time increase: +8ms per calc).
  • Hybrid Hydration: Static HTML is generated at build time with client-side hydration reserved exclusively for the calculator widget to ensure a First Contentful Paint of 0.3s on 3G.
  • Automated SEO Scaling: A single JSON source can simultaneously populate multiple schema.org blocks including SoftwareApplication, Article, BreadcrumbList, and Dataset.

Working Examples

Example of isolating calculator logic into separate TypeScript modules.

export interface Inputs { capital: number; tna: number; dias: number }
export interface Outputs { montoFinal: number; interesGanado: number; }
export function plazoFijo(i: Inputs): Outputs {
  const interesGanado = i.capital * (i.tna / 100) * (i.dias / 365);
  return {
    montoFinal: Math.round(i.capital + interesGanado),
    interesGanado: Math.round(interesGanado),
  };
}

Dynamic route implementation using Astro’s getStaticPaths.

---
export async function getStaticPaths() {
  const calcs = import.meta.glob('../content/calcs/*.json', { eager: true });
  return Object.values(calcs).map((mod) => {
    const c = mod.default;
    return {
      params: { slug: c.slug },
      props: { calc: c },
    };
  });
}
const { calc } = Astro.props;
---
<Layout title={calc.title}>
<Calculator config={calc} />
<Explanation markdown={calc.explanation} />
<FAQ items={calc.faq} />
</Layout>

Practical Applications

References:

Continue reading

Next article

Reducing SaaS Overhead: Building a Web Component Email Editor to Replace Costly SDKs

Related Content