What we build with, and why
A stack chosen for how long the software has to last, not for how it reads on a proposal. Every category below comes with the reasoning behind it.
Frontend
Server-rendered React by default. Next.js lets us decide per route what runs on the server, which is how a site stays fast as it grows rather than despite growing.
React
Next.js
TypeScript
Tailwind CSS
Angular
Vue
Backend
TypeScript end to end, so types and validation are shared rather than reimplemented. NestJS gives structure that holds up when a codebase outlives its original author.
NestJS
Node.js
Bun
tRPC
GraphQL
Python
Mobile
Cross-platform first for most business apps, native where hardware depth genuinely demands it. We recommend based on your team and product, not on what we prefer writing.
React Native
Expo
Flutter
Swift
Kotlin
Data
PostgreSQL for almost everything. It handles relational data, JSON, full-text search, and vectors well enough that most projects never need a second database.
PostgreSQL
Prisma
Drizzle
Redis
MongoDB
Elasticsearch
AI
Model-agnostic by design. Provider APIs where they are the right answer, open-weight models running in your own infrastructure where data residency or cost demands it.
Anthropic
- OpenAI
LangChain
Hugging Face
Ollama
Cloud
We deploy where your constraints point — existing commitments, data residency, or in-house familiarity — rather than pushing one provider on every project.
- AWS
- Azure
Google Cloud
Vercel
Cloudflare
DigitalOcean
DevOps
Automated pipelines and real observability, because the health of a system is measured by how uneventful deploying to it feels.
Docker
Kubernetes
GitHub Actions
Terraform
Sentry
Grafana
Quality
Testing and linting run on every change. Nothing here is optional or added at the end of a project.
- Playwright
Vitest
ESLint
Turborepo
Principles behind the stack
Boring where it matters
We use proven technology for the foundations. Novelty belongs in the parts that differentiate your product, not in your database.
One language where possible
TypeScript across frontend, backend, and mobile means shared types, shared validation, and engineers who can move between layers.
Chosen for maintenance
We pick technologies you can hire for and we can support in three years. A clever choice nobody else knows is a liability you inherit.
Your constraints decide
Existing systems, in-house skills, and data residency requirements shape the stack. We adapt to them rather than asking you to adapt to us.
Questions about our stack
01Can you work with a stack that is not on this list?
Usually yes — particularly for maintenance and modernisation work, where the existing stack is a given. For new builds we will recommend what we are strongest in, and tell you plainly if a stack you are asking for would be a poor long-term choice.
02Why TypeScript everywhere?
Shared types between frontend and backend eliminate a whole class of integration bug, engineers can work across layers, and hiring is simpler. For AI and data-heavy work we use Python where its ecosystem is genuinely the better tool.
03Do you lock us into a cloud provider?
No. We containerise by default, which keeps applications portable. Where we use provider-specific managed services because they are genuinely better, we tell you what that means for portability before committing.
04Which AI models do you use?
Whichever suits the task — the frontier providers for reasoning-heavy work, smaller or open-weight models where cost, latency, or data residency matters. We build behind an abstraction so switching does not mean a rewrite, and we validate any switch against your own evaluation set.
05How do you keep the stack current?
Dependencies are monitored and patched on a cadence. Larger version upgrades are planned as deliberate work rather than deferred until something breaks or a security advisory forces it.
Tell us what you are building.
Share the problem and we will come back with an approach, a rough shape of the work, and what it would take to deliver it.