How the building happens, and why.
Every tool in the stack is a decision. Here they all are, with versions and rationales, across method64, Climactra, and client work. Plus ten popular tools that are deliberately not used.
Five layers.
From the pixel in the browser to the machine in the datacenter, every layer with the rationale why.
- 01Frontend & UIWhat runs in the browser
- 02API & Backend ServicesWhat sits between browser and database
- 03Data, Auth & PaymentsWhat ends up on disk, and who gets in
- 04AI & MLWhat understands language and computes embeddings
- 05Infrastructure, Observability & DevToolsWhere it runs and how it gets watched
Click to jump to a section. Hover over a tool card to see related tools.
Frontend & UI.
The frontend is the layer with the most micro-decisions, typographic hierarchy, animation easing, loading states, accessibility. Stack choice: uncompromisingly React-centric, because it's the only ecosystem where all capabilities (3D, animation, accessibility, forms, routing) are in one hand. TypeScript everywhere, no "let's just throw a bit of JS in there". Tailwind instead of CSS-in-JS solutions, because it disappears at build time and costs nothing in the browser. Three.js and GSAP only where it's really about interactive 3D or choreographed sequences, otherwise CSS.
Component model that has held up for 12 years. The method64 site itself runs on React 18 with Vite, Climactra and client projects on Next.js with React 19.2, where Concurrent Features and the React Compiler actually pay off.
Strict mode everywhere, a whole class of runtime errors disappears as you type.
Server Components, App Router, built-in routing + i18n. In use wherever SSR or multi-tenancy are required (Climactra), this site gets by with Vite + a prerenderer.
Dev server in under a second, production build in under ten. Webpack tried for five years to deliver this, Vite just did it.
When Vite is used instead of Next.js, React Router is the honest, independent routing, no hidden magic conventions.
Utility-first saves hundreds of custom CSS classes per project. The build output contains only what's actually used.
For component-specific styling outside the Tailwind world, no class collisions, no BEM bureaucracy.
Components as source code, not as an npm package, changeable instead of fighting the API.
For timeline-driven sequences with precise easing, where CSS transitions don't give enough control and JS animation libs have too much overhead.
WebGL without the boilerplate. Used when 3D really makes sense, otherwise it stays out, because it's a bundle heavyweight.
Smooth scroll without the typical native bugs, and with `prefers-reduced-motion` respect out of the box.
Icon family that actually looks consistent. Imported individually, not the whole library bundle.
Plus Jakarta Sans, Inter, JetBrains Mono, Source Serif 4, self-hosted, woff2, font-display:swap. No Google tracking, no third DNS lookup.
API & Backend Services.
The API layer builds contracts, not endpoints. Every route has a Zod schema, every response is typed, frontend and backend speak the same language, guaranteed by the compiler. Fastify instead of Express, because schemas get written anyway and Fastify uses them for performance. Python comes in when ML / embeddings / data pipelines are involved, Node isn't the right tool there.
Default runtime for everything JavaScript-side. LTS branch, no edge-cutting.
When ML, data engineering or embeddings are involved, everything there has a better-maintained Python path than the JS counterpart.
Schema-driven, fast, small. Express replacement, since validation and JSON schemas are written anyway.
One schema definition for validation, TypeScript types and JSON schema export, DRY without a generator pipeline.
SMTP client that has worked precisely for 16 years. Standard SMTP means: changing providers is config, not a rewrite, no lock-in like with Resend or SendGrid and their proprietary HTTP APIs.
i18n in Next.js apps with Server Components support, no separate provider layer in the tree.
Data, Auth & Payments.
The data layer is conservative, because migrations hurt and auth bugs cost trust. Postgres as default, no vendor DB. Prisma as ORM, because the generated types connect frontend to database. pgvector instead of a standalone vector database, one DB per project is enough. Auth.js, because it's auditable and doesn't have to grow into vendor lock-in with Auth0 / Clerk.
A relational DB that has been maturing for around 40 years. JSONB, full-text, pgvector, all in one engine.
Schema as single source of truth, migrations versioned, types generated automatically. Simply the best DX in the Node ecosystem.
Vector search directly in Postgres, no Pinecone pricing model, no second database.
In-memory caching and rate limiting, when Postgres gets too many writes for ephemeral data.
Auth without a vendor account (formerly NextAuth.js). Self-hostable, OAuth-provider-flexible, no pricing cliff at MAU growth. v5 has been stable in the beta channel for months, good enough for production.
Password hashing that doesn't depend on a C lib, runs everywhere, including serverless environments.
Payment layer with the best developer experience. Webhook-first architecture matches the one used here. For Italian customers the bridge to SdI goes via Aruba Fatturazione Elettronica, Stripe charges, Aruba issues the electronic invoice.
PDF and Excel exports generated server-side, Climactra produces six print-ready climate reports and four certification-label exports with this. Templates live in code, not in a designer tool, the same diff-able versioning as the rest of the app.
AI & ML.
Model selection is pragmatic: Claude for long contexts and code, GPT for cheap bulk calls, embeddings from OpenAI because they still deliver the best price-performance semantically. LangChain as glue, not as framework religion, but as a library used selectively when standard patterns repeat. No lock-in to one provider, everything via Anthropic / OpenAI directly, no aggregator in between.
Long-context, code-reasoning and tool-use at a level GPT will be chewing on for a while. Default for everything that needs accuracy over speed.
When latency and cost matter, e.g. bulk classification or simple generation in high volume.
Best embedding quality for RAG, combined with pgvector as storage.
Reranking stage between vector search and LLM. Measurably lifts RAG answer quality, about two dollars per thousand queries, negligible against the LLM costs behind it.
Selectively for standard patterns like retrieval chains. Not as a framework wrap of all LLM calls.
Infrastructure, Observability & DevTools.
Infra is deliberately unspectacular: Docker for reproducibility, Hetzner instead of hyperscalers because the orders of magnitude fit, nginx instead of application routers because it has run without drama for 20 years. Observability in two stages, Sentry for errors with stack trace, Umami for pageviews without cookies. Deploy manually via SSH + git pull + docker compose, at this scale faster than a pipeline, no second provider needed.
Reproducible environments, no "runs on my machine" debates. Compose for local multi-service setups.
Real VMs in German datacenters, half the price of AWS for comparable specs. No vendor lock-in.
Reverse proxy, TLS termination, static hosting, one config, three jobs. Default for the method64 site and any setup where a classic web server is called for.
Reverse proxy with auto-Let's-Encrypt in container setups. In Climactra it saves a config layer, same job as nginx, different trade-off.
Service management without daemon soap opera. Auto-restart, logs in journald, standard on every Linux.
EU-hosted infrastructure for the own mailboxes and DNS records. Established enough that banks and authorities use it. For product volume (Climactra), Amazon SES in eu-central-1 is used depending on scale.
Errors with stack trace, source-map-resolved, problems surface before users report them.
Pageview statistics without cookies, without IP storage, GDPR-compliant. Self-hosted on the own Hetzner server.
Test runner that inherits Vite configs, no double setup. Faster than Jest, same Jest API.
Lint layer that automatically enforces project-wide code conventions, strict rules, no "warning" loopholes.
Run TypeScript files directly from Node, build scripts and migration tools work without a separate ts-compile step.
Ten popular tools deliberately left out.
A stack decision isn't just what's in. Just as important: what stays out, and why.
- WordPressMaintenance overhead for themes, plugins and security patches grows disproportionately with site complexity. For a marketing site that can be served as static prerendered HTML, it's over-dimensioned.
- BootstrapTailwind has been the better tool for utility-oriented styling for years. Bootstrap class sets are rigid, the override effort for a distinctive design is disproportionate.
- jQueryBrowsers now have native APIs for DOM manipulation, event handling and HTTP requests. The ~30 kB footprint no longer pays off.
- Webpack (directly configured)Configuration is involved and build times are noticeably slower than Vite. For new projects, Vite is the more pragmatic choice.
- MongoDBThe schemaless idea just shifts the schema burden from the database to the application layer. Postgres with JSONB columns delivers the same flexibility without the trade-off on transactions and joins.
- Redux / Redux ToolkitGlobal state management is unnecessary in most apps. React state, Context and server-state libraries like TanStack Query solve the same with significantly less boilerplate.
- Vercel (hosting)Very good DX, but edge function pricing scales quickly beyond what a dedicated server costs. Next.js gets deployed directly on own hardware.
- AWS AmplifyAn additional abstraction over AWS services that creates more problems than it solves under real complexity. When AWS is the right call, going directly with the primitive services works better.
- Page-Builders (Webflow / framer.com)Visual drag-and-drop tools make performance optimisation, custom logic and versioning harder. For non-trivial sites that hits limits a code-first approach doesn't have.
- No-code backends (Supabase Auth)Useful for prototypes, but lock-in problems surface quickly in production. Auth logic belongs in own code so it stays auditable and migratable.
Current build metrics for this site, automatically generated on every deploy.