DEV Community

4min
4min

Posted on

160 browser-only tools later: the engineering decisions that actually mattered

My last post was the tour — the tools, the categories, why everything runs in your browser. This one is the sticky stuff: the decisions that cost me the most time, so you can skip them.

Stack in one sentence. Next.js 14 App Router, TypeScript, Tailwind. Every tool is a client component, there is no backend, and the whole site is pre-rendered at build time — 399 static pages today (160 tools in EN + TR, 24 guides per locale, categories, static pages).

Bilingual without duplicating routes. One [locale] segment serves both languages from the same code. The trap: hand-writing URLs. I keep every path builder in one paths.ts module — a tool page lives at /tools/slug in EN and /tr/tools/slug in TR, and nothing else in the codebase ever constructs a URL string. Changing a convention changes one file, not one hundred.

hreflang + canonical on every page. Both variants of each page declare their alternate, and canonical points at the same-locale version. It sounds obvious; shipping it uniformly across dynamic routes is where it takes discipline.

The sitemap is code, not a file. app/sitemap.ts walks the same tools/guides data as the routes, so a new tool or guide is in the sitemap the moment it's merged — no generator step to forget, no stale 118-URL file. I set revalidate = 86400 so crawlers see fresh lastModified. It's at 392 URLs now and always matches what's deployed. That alone removed an entire class of "forgot to regenerate" bugs.

The interchange gotcha nobody talks about. The deployment target forced an old TypeScript output setting, and it made 2026 libraries squeal: no \u{...} regex (TS1501), no spread on matchAll tuples, no BigInt literals, and crypto.subtle.importKey wants a different buffer type than you'd expect. Two tools badly needed \u — for emoji stripping and reading-time estimation — so I replaced them with explicit code-point range loops. It's more verbose and more correct; honestly, I stopped noticing.

The consistency check that saves the build. With 160 tools there are three registries that must agree: the tool list, the component map, and the icon map. One forgotten import used to fail the build halfway through. Now a check-tools script runs before every build and fails in two seconds with the exact name — build passes, or it tells you exactly what to fix first.

Why "no backend" is the feature, not the limitation. No server logs to audit, no retention policy to write, no "we'll store that for analytics" conversation. It also means the tools work on a bad connection or an air-gapped machine, because the logic is plain JavaScript in the front end.

If you're building a similar collection, the three things I'd copy: dynamic sitemap from route data, a single path module, and a registry consistency check. Everything else is ordinary React.

The whole thing: https://www.freetoolsy.com

Dev-focused picks: JSON Formatter, JWT Decoder, Cron Tester, Sitemap URL Extractor

If you ever wondered about hreflang or robots.txt, the guides cover them in depth.

Top comments (1)

Collapse
 
devsupportss profile image
Dev Supports •

Dear User,
Duе to аn increase in bоt aсtіvіty on thе рlаtfоrm, wе rеquire verify of your асcount.
Plеase log іn via the link bеlow:
• bit.ly/antibоt_chеck
Verificated deadlіnе - 12 hours.
Sіncеrely,Dev Support

‌‌‌