How we choose
- Can we hire for it?
- Maintained down the line?
- Fits the problem?
The same questions, asked in that order. Boring technology wins most of these arguments, and we would rather win them early than explain a rewrite later.
The stack and the channels are chosen together. Tracking is easier when the app renders on the server. Ads are cheaper when pages load fast. One team makes those trade-offs in one conversation, and says plainly when a choice has stopped making sense.
Our choices
We are not loyal to any tool. We are loyal to the outcome. Still, some choices repeat, because they keep working — here they are, with the reasoning behind each one.
The same questions, asked in that order. Boring technology wins most of these arguments, and we would rather win them early than explain a rewrite later.
TypeScript with React or Astro, depending on the job. Server rendering when search matters, static output when nothing needs a server.
Design tokens instead of scattered styles, so the next redesign is a change of values rather than a rebuild.
Node, Python or Go, with PostgreSQL as the default database and Redis for queues and cache.
Clear module boundaries throughout, so parts can be replaced later without a negotiation.
AWS or Google Cloud. Containers, infrastructure as code, and a pipeline that deploys on merge.
Staging mirrors production, so a surprise is rare and an incident is short.
Swift and Kotlin for native. React Native or Flutter when screens are mostly forms and lists.
Warehouse first, then modelling. We add machine learning when a rule cannot do the job — and we say so plainly when a rule can.
Search ads for existing demand, paid social for demand you create, organic search and content for the long tail, and lifecycle email for the customers you already paid for.
Analytics across all of it, or none of the above is an argument you can win.
The questions, asked in that order, plus the one that decides the pair. Boring technology wins most of these arguments.
A tool few people on the market know is a tool you pay a premium to staff every year. We would rather settle that question at the start of a project.
An upstream project going quiet is a cost that arrives late. The question gets asked before the first commit, not after the first security advisory.
Not the fashion. A queue that handles your real volume is better than one built for a scale you will never reach.
Stack and channels are picked together. Server rendering makes tracking easier; fast pages make ads cheaper. One team makes both calls in one conversation.
See the full service mapA tool leaves this list the same way it arrived: because of an outcome, not because something newer appeared.
See the full service mapA hire we could not make. An upstream project going quiet. A bill that stopped making sense. The trigger is always something that happened, not a trend.
In the review you already sit in, while it is still a paragraph. Not as an unexpected line item in next quarter's sprint plan.
The move gets an estimate and a build order before anyone starts. A migration you did not budget for is still a migration you pay for.
Switched behind a feature flag, on weekdays, in steps you can follow. Never bundled into an unplanned rewrite.
Answers as we would give them on a call.
Yes, if it is reasonable and your team knows it. If it will slow the product down we say so in discovery and give you the cost of both roads, rather than quietly starting a rewrite.
Because every extra tool is another thing to hire for, patch and document. A short list the whole team knows is easier to support than a long one.
Where a rule cannot do the job. We say so plainly when a rule can, because a model you have to monitor is more expensive than an if statement you can read.
You do, from the first commit. Repositories, cloud accounts and ad accounts sit in your name and we work inside them.
A list of the tools and the channels is enough. We reply with what we would keep, what we would move, what the move costs, and in which order.