ISSUE 2026-09-27SERIES BREC 49TYPE BRIEFgarnetgrid.com
The only question worth arguing about
Insights
Every founding team has the same argument in its first month, and it is almost always the wrong argument. The question is not which language, framework or cloud is best. It is which of these decisions you can undo in an afternoon, and which will still be shaping your product in three years, when you have customers, revenue and no time. Sort the choices into those two piles and most of the debate disappears.
In the reversible pile: your CSS approach, your component library, your CI provider, your error tracker, your hosting region, most of your build tooling. A wrong call there costs a week. You will make several wrong calls, and that is fine.
In the irreversible pile: your primary datastore, your identity and authentication model, your tenancy model, the language your domain logic is written in, and anything that determines the shape of your data. A wrong call there is not a week. It is a migration you cannot schedule, because by the time you notice, you are also selling, supporting and hiring.
So the useful exercise is not benchmarking. It is writing down every technology decision in front of you, marking each one reversible or not, and then spending nearly all of your deliberation on the second list. Timebox the first list. Pick what the team already knows and move on.
Boring by default, and fewer stateful parts than the diagram wants
For the irreversible pile, boring wins, and boring specifically means fewer stateful services.
One application runtime, Postgres and object storage will carry a real product a long way. Postgres holds the relational core; JSONB absorbs the parts of the domain you do not understand yet; its full-text search is good enough for years of product search; SELECT ... FOR UPDATE SKIP LOCKED gives you a durable job queue without introducing a broker; pgvector covers embeddings if you go that way. Most early architecture diagrams contain more boxes than the company has engineers.
My rule, offered as opinion rather than law: every stateful service needs someone who knows its failure mode at three in the morning. Count your engineers. Count your stateful services. If the second number approaches the first, you have bought an outage on credit.
This approach does have limits and I cannot tell you where yours are, because it depends on your write volume and access patterns. You will find out the honest way: a specific query, or a specific queue depth, will be the thing that hurts, and then you will have a real measurement with which to size a replacement. That is a far better position than guessing today.
Managed or self-hosted is a question about who gets paged
This argument is usually conducted as a cost comparison. It is not one. It is a question about where your scarce attention goes.
A managed service charges a margin so that you do not have to carry operational knowledge. Self-hosting is cheaper on the invoice and paid for in attention, upgrades and on-call. With three engineers, attention is the scarcer resource, so the defensible combination is a managed database underneath your own stateless application. The reverse, a hand-rolled database under a fully managed application platform, rarely is.
If you do self-host, understand that installation is not the work. The work is a restore you have actually performed, a version-upgrade path you have rehearsed, and a rota of people who will answer the page. If nobody has restored the backup, you do not have a backup. You have a file.
There is one honest exception, and it is the business we are in, so treat that as a declared interest: if the data cannot leave your control for legal, contractual or risk reasons, the calculation changes completely. You pay the operational cost because the convenient alternative is not actually available to you.
Read the pricing model, not the price
Prices change, they differ by region, and they are renegotiated. The shape of a pricing model is far more stable, and the shape is what will hurt you.
Per-seat pricing is predictable and quietly penalises adoption. When a tool costs money per person, people share logins, and your audit trail stops being true. Per-request and per-invocation pricing tracks your traffic, which is usually what you want. Consumption pricing with egress charges is comfortable until you leave, which is precisely when you can least afford a surprise.
The category to be careful with is the abstract unit: credits, compute units, DBU-style units of work. These are not dishonest, but the vendor defines the unit and can redefine it, and you cannot forecast a unit you do not control.
Here is the test I use. For each paid dependency, can you write a one-line formula from a product metric you already track to that line on the invoice? Signups times something. Documents processed times something. If you cannot write the formula, you cannot forecast the bill, and that is the finding, not the price.
I am deliberately quoting no numbers. Any figure here would be wrong by the time you read it, and wrong differently in your region.
AI features change both the bill and the failure modes
Two things are new once a model is in the product.
First, the bill scales with use, typically per token, so your unit economics now contain a variable cost that moves with user behaviour. Retries, long contexts and any agentic loop multiply the number of calls, and in my experience the multiplier is larger than the estimate, because the failure paths retry too. Instrument tokens per user action on day one. Attributing spend to features after the fact is miserable work.
Second, the failure modes differ. Output is non-deterministic, so tests asserting exact strings will flake; assert on structure and invariants instead. Latency is user-visible and variable, so stream, and design the degraded path deliberately rather than discovering it in production. Providers deprecate models, and your prompt is coupled to whichever model you tuned it against, so keep one interface you own between your product and the model behind it. That boundary is cheap now and expensive to retrofit.
Whether to run models yourself is a genuine trade-off and there is no honest general answer. It turns on data sensitivity, steady-state volume, latency requirements, and whether anyone on the team can evaluate output quality. Self-hosting removes the per-token bill and replaces it with capital, capacity planning and an evaluation burden.
What actually goes wrong
Almost none of the pain I have seen came from picking the wrong framework. It came from a handful of decisions that were made by accident.
What genuinely locks you in
Lock-in is real but narrower than the debate suggests. What actually traps you is data gravity, identity, proprietary query or runtime models sitting at the centre of your domain, and deployment glue that only one person understands.
Using a managed service is not lock-in. Letting its idioms leak into your domain model is. If your core business logic is written in a vendor's dialect, or your entities are shaped by a vendor's storage model, the migration is a rewrite rather than a port.
The counter-discipline is not to abstract everything. A generic wrapper over the database you will never change is a permanent tax against a benefit you will never collect. Put an adapter where you can name a plausible reason to switch: the model provider, the email sender, the peripheral parts of your payment integration, the object store. Leave the rest concrete, and be honest with yourselves that moving the primary datastore will one day be a project with a name and a budget.
Do this before writing more code. List every technology decision in front of you and mark each one reversible or not. Give the reversible ones a single day, collectively, and choose what the team already knows. Then spend real time on the short irreversible list: one runtime, one primary datastore chosen deliberately, a durable queue, one place for logs and traces, and an identity and tenancy model you can live with when you have ten thousand users and an enterprise buyer asking about isolation. For every paid dependency, write the formula from a product metric to the invoice line, and treat a missing formula as the risk it is. If a model is in the product, own the boundary in front of it and measure cost per user action. Then stop tuning the stack. A stack you understand beats an optimal one, and no architecture has ever rescued a product nobody wanted.