TEST ENVIRONMENT
Skip to content

Our tech stack

Opinionated technology choices for a platform that needs to be reliable, fast, and simple to maintain.

No SPA complexity No hydration bugs No bundler No virtual DOM Server-rendered HTML Forms just work

Backend

Server-side, type-safe, boring on purpose

Frontend

A few kilobytes of JavaScript

Infrastructure

Every environment from the same templates

Observability

If it breaks, we can see why

observability

Sentry

Every production error and log lands in Sentry, tagged with the release that caused it. Locally, Serilog, OpenTelemetry and Seq show the same story.

observability

PostHog

Product analytics that show where people get stuck, so we fix the screen rather than guess.

Why Alpine-AJAX over a traditional SPA?

We tried the SPA approach. React, Next.js, client-side routing, state management libraries, API layers, serialisation, hydration, bundle splitting. All to render forms and tables for a business app.

The complexity wasn't justified. We were maintaining two applications (a .NET API and a React frontend) to do the job of one. Every feature required changes in both places. Type safety stopped at the API boundary. Client-side state drifted from the server. And the developer experience (waiting for webpack to rebuild while you tweak a label) was painful.

Alpine-AJAX gives us the UX people expect from SPAs (partial page updates, no full reloads, smooth transitions) without any of that overhead. The server renders HTML. Alpine-AJAX swaps fragments in the DOM. There's no JSON serialisation, no client-side routing, no state management, no virtual DOM diffing.

The result: one codebase, full-stack type safety, server-side validation as the single source of truth, and a frontend that's a few kilobytes of JavaScript instead of a few megabytes. Pages load fast. Forms just work. And we ship features in half the time.

Want to work with this stack?

We use cookies to help improve your experience. Read our cookie policy