tech, developers, and the code underneath

issue 192· essay·

Vendor lock-in: an honest cost model

Portability is not free and neither is dependence. A framework for deciding how much abstraction to buy.

"Avoid vendor lock-in" is treated as self-evidently good advice. It is not advice, it is a preference, and following it uncritically produces systems that are worse in exchange for optionality nobody will ever exercise.

Here is a way to actually decide.

the cost of lock-in#

Switching cost. How much engineering time to move off, if you had to.

Pricing power. A vendor who knows you cannot leave prices accordingly. This is real and it is usually the largest ongoing cost.

Capability ceiling. You are limited to what they support, on their timeline.

Correlated risk. They have an outage, you have an outage. They change their terms, you comply. They get acquired and sunset the product, you migrate on their schedule.

the cost of avoiding lock-in#

This is the half that gets ignored, and it is frequently larger.

The abstraction layer itself. Code to write, maintain, test, and debug through. It is a permanent tax and it makes stack traces longer.

Lowest common denominator. Your abstraction can only expose what all candidate providers support. You give up the features that made the good option good.

The abstraction is usually wrong anyway. It was designed against one provider's model. When you actually try to swap, you discover the abstraction encoded assumptions that do not hold, and you rewrite it.

Delayed value. Time spent on portability is time not spent on the product.

the framework#

For each dependency, estimate:

  1. Switching cost — engineer-weeks to move.
  2. Probability you switch in the next three years.
  3. Cost of the abstraction — engineer-weeks now, plus ongoing drag.

Then: if switching_cost × probability < abstraction_cost, do not abstract.

The numbers are rough. The exercise still clarifies, because it forces you to state the probability out loud, and stated probabilities are usually much lower than the implied ones people are acting on.

the categories, worked through#

Object storage. Switching cost: low. The S3 API is a de facto standard and every provider implements it. Probability: moderate — people do move for pricing.

Verdict: use the S3 API, do not abstract further. The API is already the abstraction.

Compute. Switching cost: moderate if containerized, high if you use provider-specific serverless. Probability: low.

Verdict: containerize — which is good practice anyway — and use whatever managed service you want. Do not build a compute abstraction layer.

Relational database. Switching cost: high. Probability: low.

Verdict: use the database's features. Teams that avoid stored procedures, database-specific types, and advanced indexing to stay portable are giving up real capability for an event that will not happen. Postgres-specific SQL is fine. You are not going to migrate to a different engine, and if you do, the SQL dialect will be the smallest part of the pain.

Managed queues, streams, and similar. Switching cost: moderate. The semantics differ enough between providers that a thin abstraction genuinely helps.

Verdict: a thin interface — publish, subscribe, ack — is worth it. Not a full abstraction; a boundary.

Authentication. Switching cost: very high — you have to migrate user credentials, sessions, and integrations. Probability: low, but the consequences of being stuck are severe.

Verdict: use standard protocols. OIDC and SAML are the abstraction. A provider that supports them is replaceable in principle; one with a proprietary SDK is not.

AI model providers. Switching cost: low if you kept the interface thin. Probability: high — the market is moving fast and the right choice changes quarterly.

Verdict: definitely abstract. This is the clearest case on the list. A thin interface plus an eval harness in your own repository makes model changes an afternoon. Teams that did this in 2024 have been switching providers casually ever since.

Observability. Switching cost: moderate to high — instrumentation is everywhere in your code. Probability: moderate, usually driven by cost.

Verdict: OpenTelemetry. The instrumentation is vendor-neutral, the collector handles routing, and swapping backends is a configuration change.

the pattern#

Abstract where the switching probability is high and the abstraction is cheap. AI providers, observability backends, object storage.

Do not abstract where switching is unlikely and the abstraction costs you real capability. Databases, compute platforms, managed services you chose for their specific features.

Use standard protocols wherever they exist. OIDC, S3, OpenTelemetry, SQL. A standard is an abstraction someone else maintains, and it is always cheaper than yours.

the thing that actually protects you#

Not an abstraction layer. Your data, in a format you can export, and a documented process for leaving.

Ask, before adopting anything: can I get all my data out, in a usable format, without their cooperation? If yes, you have real optionality regardless of how coupled your code is, because the expensive part of a migration is never the code — it is the data.

If the answer is no, that is a much bigger red flag than any API coupling, and it is the question almost nobody asks during procurement.

get README in your inbox

One dispatch, no noise. Tech and developer news, plus the occasional long piece on the craft.

subscribe →