How we pick the right foundation for your product
Every project starts with someone asking which framework we'll use, and it's almost never the question that decides whether the project succeeds. The stack matters far less than whether the team inheriting it can still operate it in three years.
The question behind the question
When a client asks "React or Vue?", what they usually mean is "how do I avoid picking wrong?". That's a reasonable fear, and the honest answer is that both work. The projects we've seen fail didn't fail on framework choice. They failed because the one person who understood the build left, or because the tooling was so unusual that hiring for it took six months.
So we invert the question. Instead of asking what's best, we ask what you can staff, what you can debug at 2am, and what will still be maintained when you next need to upgrade.
That reframing shortens the list faster than any comparison table. Once the test is "what can this team actually operate" rather than "what is technically strongest", most candidates fall away for reasons that have nothing to do with their merits — and what's left is usually obvious enough to settle in an afternoon rather than a fortnight.
Three constraints that actually decide it
Nearly every stack argument we've been pulled into resolves once three questions get honest answers. None of them are technical questions, which is probably why they so rarely come up in the technical debate.
Who maintains this after handoff?
If you have an in-house team, their existing skills outweigh almost every technical argument. Handing a Django team a Node codebase because it benchmarks better is a false economy — you've traded a small performance gain for a large capability gap.
The uncomfortable version of the question is: if we disappeared tomorrow, who runs this? If the answer is a contractor you haven't hired yet, the stack needs to be one that contractor will already know. If the answer is two in-house engineers who write Python, that is the single most important fact about your architecture, and it should outweigh every benchmark on the internet.
What does the product genuinely need?
Real-time collaboration, heavy background processing and offline-first mobile each rule some options out. Most products need none of them, and choosing as though they might need all three is how you end up with infrastructure you pay for and never use.
The test we use is to name the feature that forces the choice. "We need real-time" isn't a requirement, it's a mood. "Two dispatchers need to see the same job board update within a second of each other" is a requirement, and it rules options in and out on its own. If nobody can name the forcing feature, you don't have a constraint — you have a preference, and preferences should lose to maintainability.
How long does this choice have to last?
A prototype validating an idea and a platform meant to run for a decade deserve different answers. Picking the ten-year tool for the six-week prototype is as much a mistake as the reverse.
Be honest about which one you're building, and say it out loud. Prototypes that get promoted to production without anyone deciding to promote them are the most common way a team ends up running something nobody actually chose.
The costs that never make it into the comparison
Stack comparisons tend to weigh what's easy to measure — benchmarks, bundle size, lines of boilerplate — and skip the things that actually consume the budget. Four of them matter more than anything on a benchmark chart.
Hiring depth. A framework with a thin talent pool means every hire takes longer, costs more and carries more risk, and it compounds: the smaller the pool, the more leverage each person who understands your codebase has over your roadmap.
The upgrade treadmill. Some ecosystems ship breaking changes on a yearly cadence and some barely move. Neither is wrong, but one of them is a recurring line item you should budget for rather than discover. A stack that needs a fortnight of migration work every year is a fortnight you aren't shipping features.
Ecosystem maturity. The library you need almost certainly exists in the mainstream ecosystem and quite possibly doesn't in the niche one. Every gap is a component you now own, maintain and test forever — the most expensive code in any codebase is the code you wrote because nothing else existed.
Operational surface. Hosting, observability and CI are part of the choice, not a detail to sort out later. A stack that only runs well on one vendor's platform is a commercial decision wearing a technical costume, and it's worth making that trade knowingly rather than finding it in a renewal quote.
Why we default to boring
Our defaults — Next.js, TypeScript, PostgreSQL, Flutter for mobile — are deliberately unexciting. They're widely used, well documented, and you can hire for them. When something breaks at an inconvenient hour, someone has already had your problem and written it down.
That matters more than any benchmark. The cost of a technology isn't what it takes to build with it, it's what it takes to keep running it. Novel tools front-load the fun and back-load the bill.
"Boring" here doesn't mean old, and it doesn't mean stagnant. The property we're actually buying is that a large number of other teams have already hit your problem in public, and written down what they did. That's a form of documentation no maintainer can produce on their own, and it's the thing you lose the moment you step off the well-trodden path.
What we actually reach for, and why
Stated plainly, so you have something concrete to argue with rather than a philosophy.
Next.js and TypeScript carry the interface and most of the application layer. Server rendering matters when pages have to be indexed or load fast on a mid-range phone, and TypeScript pays for itself the first time someone renames a field. This is the stack behind most of our web app development work, and the reason a handover doesn't require us to be in the room.
PostgreSQL until something proves it wrong. Relational schemas are easier to reason about, easier to query in ways you didn't plan for, and easier to hire around. "We might need to scale" is not a reason to start somewhere else; you will know when you need something else, and the migration will be tractable because the data was well modelled.
Flutter when one codebase genuinely has to cover both platforms, and native when the app lives or dies on platform-specific behaviour. That's a real fork in the road, not a default.
Two decisions sit outside this list because they deserve their own treatment. If you're building multi-tenant software, tenancy and identity are far more consequential than your framework — we go through that in choosing the right backend for a new SaaS build. And if more than a couple of people will be building screens, the component layer needs its own plan, which is the subject of shipping a design system your whole team can use.
When we break our own rule
Sometimes the boring option genuinely can't do the job, and then we take the interesting one deliberately and write down why. The rule isn't "never use new tools", it's "never use one by accident".
A decision recorded with its reasoning is one the next team can revisit. A decision nobody remembers making is one they'll be scared to touch.
A pharmacy management system we built is the tidy version of this. Counter staff needed software that launched like any other desktop application on the pharmacy's own machines, not another browser tab competing for attention. That requirement ruled out the obvious web answer, so it went out as an Electron shell wrapping a React interface — one codebase, modern UI patterns, install-and-launch behaviour. The constraint picked the tool, which is the only order that works.
How to run this decision in a week
None of this needs a quarter-long evaluation, and long evaluations mostly produce documents rather than decisions. Write down who maintains the system after handoff and what they already know. Name the one feature that genuinely constrains the choice, or admit there isn't one. Decide whether you're building a prototype or a platform, and say so where the team can see it.
Then pick the most ordinary tool that satisfies those three answers, and write a paragraph explaining why. That paragraph is worth more than the comparison table — in two years it's the only thing that will tell your successor whether the constraint that drove the choice still holds.
SYS — Common questions
Does our choice of framework affect SEO?
Less than the rendering strategy does. What matters is that pages return real HTML quickly and have stable, crawlable URLs — most modern frameworks can do that, and most can also be configured badly enough that they don't. A client-only single-page app is the one pattern that reliably causes indexing problems, and it's a configuration choice more often than a framework one.
Is it worth rewriting a product that already works?
Usually not as a single project. Full rewrites take longer than estimated, stop feature work while they run, and re-introduce bugs that were quietly fixed years ago. The exception is when the current stack is genuinely blocking hiring or a specific capability you need. Even then, migrating one boundary at a time behind the existing interface is safer than a rewrite with a launch date.
What if our team already disagrees about the stack?
Disagreements about frameworks are almost always disagreements about something else — who will maintain it, how long it has to last, or whose skills the project is being built around. Answer those three questions explicitly and the technical argument usually resolves itself. If it doesn't, the tie-breaker is whichever option the people staying with the codebase know best.
SYS — Keep reading
Choosing the right backend for a new SaaS build
How we decide what a SaaS product actually needs before committing to an architecture — and which decisions are genuinely expensive to reverse.
7 min read
Shipping a design system your whole team can use
Turning a Figma library into production components that don't drift — and knowing when a design system is overhead rather than leverage.
6 min read
Taking AI agents from a working demo to production
The demo is the easy part. What it takes to run an agent against real customers — permissions, evaluation, cost, and the failure modes nobody demos.
8 min read
