← All writing

Tech Stack · 7 min read

How to Choose a Tech Stack You Won't Regret

Every founder eventually asks which language they should build in, and the question feels like the one that sets the ceiling on everything after it. It almost never is. Any of the stacks in serious contention for your product will do the job. What decides whether you regret the choice in two years has very little to do with the name on the tin.

The decision is worth taking seriously. It is just usually taken up in the wrong shape. Three constraints settle it, and none of them are about elegance.

What actually decides it

01

Who you can hire

A stack is a hiring filter you apply to yourself. Choose something with a thin pool where you operate and every future hire takes longer, costs more, and puts you in competition with companies that pay better than you do. This is measurable before you commit. Open the job boards for the city you hire in, or the time zone you would hire remote from, and count the listings and the candidates for each option on your shortlist. If one of them returns four results, you have your answer, and it arrived without an architecture meeting.

02

What the product physically has to do

Most software is forms, lists, permissions, and reports over a database. Almost anything handles that competently, which is why most stack arguments are unfalsifiable. Some have a hard requirement that narrows the field fast. Processing video on the device, running models locally, holding tens of thousands of open connections, talking to hardware over a serial port. If your product does one of those things, the shortlist shrinks for reasons that have nothing to do with taste.

Name the single hardest thing your system must do, then check that your candidate stack has a well-worn path to it. Not a conference talk. A library that many companies depend on and that received a commit this year.

03

How long you have to live with it

Software you intend to throw away in six months and software you will still be running in eight years deserve different answers. A prototype proving that a market exists can be written in whatever gets it working by Friday. The system that calculates payroll should be written in something that will still be getting security patches after your first engineer has moved on. Long-lived systems reward dull technology with a large installed base. Short-lived ones reward speed, and you are allowed to say out loud which one you are building.

Boring technology is a real advantage

Old technology has one property that new technology cannot buy at any price. Every way it breaks has already broken for somebody else, in public, with a fix somewhere at the bottom of the thread. When your database locks up at two in the morning, you want the error message to have a decade of answers behind it. Novelty gives you a search result with no replies and a maintainer who is asleep.

Dan McKinley's essay on choosing boring technology puts a useful frame on this: you get a small budget for genuinely new things, and every one you spend it on has to earn its place. A stack made of four unfamiliar parts has not made four independent choices. It has made one large bet that all four behave as advertised under conditions nobody on the team has seen yet.

The cost of running something nobody has run before

Reading the documentation is not the same as having been on call for it. A team that has shipped one project in a language knows the happy path. What they do not know is how it behaves under memory pressure, which of the popular libraries were quietly abandoned two years ago, how to read the stack traces, and what the deployment story looks like when something is on fire.

That knowledge takes months, and you acquire it in production, in front of customers. The first month feels fine. Month four is where you meet the problem an experienced hand would have closed in an afternoon and your team spends a week on. The tax is real and it always lands later than the decision that caused it.

When the right answer is whatever your first engineer knows well

For most early products this is the correct answer, and founders resist it because it feels unrigorous. It is not. An engineer working in a language they have used for eight years is dramatically faster than the same engineer in the theoretically better option they picked up last month. At this stage speed matters more than elegance, because the thing most likely to kill the company is spending a year building something nobody wanted.

There is one limit. If your first engineer's preferred tool is genuinely obscure, you are trading their speed today against the ramp-up time of everyone you hire afterwards. That is a fine trade for six months and an expensive one for six years.

The decisions that are genuinely hard to undo

Almost everything in a codebase is cheaper to change than people assume. The two exceptions are where the data lives and what shape it is in.

Moving a live product to a different database means a migration, a period of writing to both systems, and a class of bug that only appears once real data is involved. Changing the data model is harder still, because every part of the system holds an opinion about it, and so does every report anyone has ever run off it. These are the arguments worth having properly, early, with the whole team in the room.

Ask what the data actually looks like. Whether the relationships between things are settled or still moving. Whether you will need to ask questions that cut across the entire dataset. Whether anything here is regulated and has to be retained in a specific form. Then choose the relational default unless one of those answers gives you a concrete reason not to. The burden of proof sits with the exotic option, and it is a heavier burden than it looks at the whiteboard.

What you can change later without much pain

  • Styling. An entire product can be restyled in a couple of weeks without the architecture noticing.
  • Hosting. Painful for a weekend, forgotten by Monday, and mostly a matter of configuration.
  • Most libraries. Anything sitting behind a thin interface of your own is a contained replacement job.
  • The frontend framework. Genuinely tedious to change, and still only a rewrite of the surface.
  • Language versions, build tooling, CI. These move under you whether you plan for it or not.

So spend an afternoon on the database and a week on the data model. Spend very little energy on the rest. Then build in the thing your team can already build in, and go and find out whether anybody wants the product.

Working through something like this?

We spend most of our time on exactly these decisions. Thirty minutes, free, and you talk to an engineer.