This site's /tools section is built to be extended without touching code. A new calculator is a YAML entry plus one math function. Here is how the pieces fit, because the architecture is the product.

The three layers

1. Definitions (YAML). Each tool has a page-level entry — title, slug, SEO description, intro — in a single calculators.yaml:

- id: sqlite-size
  title: "SQLite Database Size Estimator"
  slug: sqlite-size
  meta_description: "Estimate disk usage from rows, row size, and indexes."
  intro: "Planning a SQLite-backed app? Estimate before you build."

2. The math engine (Go). The actual formulas live in a tested Go package. Each calculator is a Def with typed inputs and a Compute function, registered by ID. This is the source of truth.

3. The front-end (JS mirror). The browser needs to recompute as you type. The same math is mirrored in a plain JS file, so pages work with zero backend round-trips.

Why the split matters

  • Server-side defaults for SEO. The Go engine computes results with default inputs at render time, so every tool page ships with real numbers in the HTML — before any JavaScript runs. No-JS users and search engines see a working calculator.
  • Client-side for interactivity. The JS mirror recomputes on every keystroke. Consistency between the two is verified by a test that runs both against the same inputs and compares output line by line.
  • Adding a tool = a bounded change. Write one math function, add one YAML block, restart. No theme edits, no route edits, no new templates.

What I learned

  1. Data-driven beats code-generated. The tool pages were a natural fit for "config + template" once the math was isolated.
  2. Two implementations must be locked together. A "test that compares Go vs JS output" is not optional — it is the only thing that keeps the mirror honest.
  3. Server-side defaults are an SEO feature. Pre-rendered numbers make calculator pages useful and indexable, not just interactive.

If you build a tools-heavy site, this split — config, tested math, JS mirror, server defaults — is the pattern I would repeat. And the /tools section here is the live example.