Skip to content

Stack

The stack we know — and operate — cold.

These are the technologies we keep coming back to. Not because they're the newest, but because we've built and run them long enough to know where they creak, what they cost to operate, and when to pick something else.

Why this stack

Mature beats new — every time something needs to stay up.

We don't pick technology by trend. We pick it by documentation, community, operational maturity, and how easy it is to hire for in two years. When we test a new technology in an internal project, it typically takes 12-18 months before we'll let it land in a client delivery — so we know where it breaks, not just where it shines.

That doesn't mean we're conservative. We use edge runtimes, server components, and Postgres' newer features. But the core stack is chosen with one thing in mind: it should still be maintainable in 2030. Mature and boring is a feature, not a constraint.

  • Next.js

    Frontend & fullstack framework

    Our default for both websites and customer-facing SaaS frontends. App Router, server components, edge runtime — we use the full palette, but only where it makes sense for your team to maintain afterwards.

    What we use it for

    • Marketing sites with Core Web Vitals in green
    • SaaS dashboards with server components and streaming
    • Multi-tenant customer portals
  • TypeScript

    End-to-end type safety

    Written across frontend, backend, deploy scripts and IaC. Strict mode from day 1. We believe compile-time errors are cheaper than runtime errors — especially in SaaS where customers can't wait for a hot-fix.

    What we use it for

    • Shared types between client and API
    • Generated types from database schemas
    • End-to-end typesafe RPC (tRPC, Hono RPC)
  • Node.js

    Backend runtime and APIs

    Our preferred runtime when Next.js API routes aren't enough. Lightweight HTTP services, background jobs, scheduled tasks. Stays close to the standard library — we avoid heavy frameworks that lock you in.

    What we use it for

    • REST and JSON-RPC backends
    • Webhook receivers and background jobs
    • Scheduled tasks via cron or workflows
  • Python

    Data, scripting and ML pipelines

    When the work is data engineering, ML inference, or integration against libraries that don't exist in the Node ecosystem. Typically FastAPI for services, polars/duckdb for data pipelines.

    What we use it for

    • Data pipelines and ETL
    • LLM services with evaluation and caching
    • Integration against Python-only libraries
  • Vercel

    Edge hosting and preview deployments

    Our default hosting for Next.js. Preview environment on every pull request — that's where our way of working actually lives. We use Vercel when the client wants zero operational overhead on the frontend; AWS or Cloudflare when there are specific requirements.

    What we use it for

    • Preview deploys on every PR
    • Edge functions and middleware
    • ISR and on-demand revalidation
  • Cloudflare

    Edge network, WAF and Workers

    DNS, CDN, WAF, DDoS protection, Workers and R2. Our preferred edge of the internet. We use Cloudflare by default in front of anything that lives in a cloud, and as primary compute when a service can live on Workers.

    What we use it for

    • DNS, CDN and WAF in front of all production
    • Workers for lightweight services and edge logic
    • R2 storage and cache strategies
  • AWS

    Cloud workloads and storage

    When something needs more than edge runtime: long jobs, large data volumes, regulatory requirements. We primarily use ECS, RDS, S3, Lambda, EventBridge — built with IaC from the start, so you can take over.

    What we use it for

    • Compute-heavy backends (ECS, Lambda)
    • Managed databases (RDS, Aurora)
    • Event-driven architectures (EventBridge, SQS)
  • Firebase

    Auth, realtime and mobile backend

    When an MVP needs to ship fast and the main task is auth + a fast data layer — typically for mobile-first or realtime-heavy products. We build it so you can migrate away if you outgrow it.

    What we use it for

    • Auth with social providers and custom claims
    • Realtime data for mobile apps
    • Quick MVP backend without DevOps overhead
  • Supabase

    Postgres, auth and real-time

    Postgres with batteries included. Our preferred start for SaaS where you want to own the database, but don't want to build auth, RLS policies and storage from scratch on day 1. Migratable to standalone Postgres when you grow.

    What we use it for

    • SaaS MVPs with multi-tenant RLS
    • Auth, storage and realtime out of the box
    • Edge functions close to the database
  • PostgreSQL

    The relational database we trust to operate

    Our default database. Almost everything we build lands in Postgres — managed (RDS, Neon, Supabase) or self-hosted depending on requirements. JSONB where it makes sense, RLS for multi-tenant, materialized views for heavy queries.

    What we use it for

    • Multi-tenant data with Row Level Security
    • JSONB for flexible schemas where it makes sense
    • Logical replication and read replicas
  • Tailwind CSS

    Design system and UI

    Our preferred way to build design systems quickly and durably. Combined with CSS variables for theming and a small ui-primitives folder — so you don't inherit a heavy component library you don't own.

    What we use it for

    • Design systems based on CSS variables
    • Durable component primitives
    • Fast design without CSS-in-JS overhead
How we choose

Four criteria — every time.

We don't have one framework. We have a process for picking one.

  • 01

    Operational maturity over feature set

    We ask first: can we operate this for 5 years without hate-forking the library? If the answer is no, we pick something else — no matter how slick it looks in a demo.

  • 02

    Hireable in two years

    If only we can maintain the stack, we've built it wrong. We pick technology you can hire for, or that your own team can pick up without a bootcamp.

  • 03

    Clear exit path

    We don't bind to vendors without a plan B. Postgres over proprietary databases. Standard protocols over vendor SDKs. If you need to leave, you should be able to.

  • 04

    Total cost of ownership

    Hosting price is one thing. Operations time, on-call burden, update frequency, migration friction — that's what it actually costs to run something. We factor in the whole picture.

Talk about your stack

Want us to look at a stack that's already there?

We also pick up existing platforms — you don't need to change stack to work with us. We're happy to look at an architecture and tell you honestly what we'd change.