The tech stack of your web app doesn't matter

George Bidilica
George Bidilica · · 5 min read
Stack of books

Teams don’t ship slowly because of their stack. They ship slowly because changes aren’t safe to make.

What determines whether you ship is how quickly your team can make changes without breaking things. That has almost nothing to do with whether you picked React or Vue, Express or Fastify, Python or Node. Pick something exotic and the stack does become the constraint, but among mainstream choices, the bottleneck lives somewhere else.

What actually locks you in

Swapping a framework or an ORM is a refactor, one developer can drive it. Redrawing service boundaries is a negotiation, it requires coordination across teams, contracts, and data ownership. The first is expensive but predictable. The second changes what you can build and how fast your team can move.

In a car marketplace, teams rarely regret picking Node over Go. They regret splitting listings, reservations, and payments into separate services before their domain boundaries stabilised. They regret coupling data across those boundaries, or baking a permission model into the database schema before the product found its shape. Stack decisions get debated for weeks because everyone has an opinion. Architecture decisions get made quietly and live forever.

The deeper you integrate with anything, the more teams depend on the assumptions you encoded. Providers, frameworks, ORMs, the lock-in gradient is the same.

Running a Node API in a container? You can move that anywhere. Using managed queues and object storage? Harder, but doable. Building on serverless primitives with provider-specific IAM and event choreography? That’s not a hosting choice anymore, that’s an architecture choice wearing a hosting label.

The same gradient applies to frameworks. Using Express as a thin HTTP layer? Replaceable in a week. Letting one framework own your component lifecycle, state, and routing? That’s a rewrite, not a swap.

You’re rarely locked into a tool. You’re locked into how many teams depend on the assumptions your code encodes. A Cloud Function that assumes a specific execution model, a Pub/Sub topic wired into 6 services with different retry expectations, a Cloud SQL instance that 3 teams query directly instead of through an API. Those are the real lock-in surfaces, not because they’re hard to rewrite, but because changing them requires coordinating everyone who depends on them.

Data constraints persist

Your data model changes constantly, schemas evolve, columns get added, tables get split. But the structural decisions underneath persist much longer than any framework choice.

Relationships between entities persist. Ownership assumptions persist longer. Identity strategy (how you model users, tenants, accounts) persists longest. In a car marketplace, whether a listing “belongs to” a dealership or a seller account is a structural decision that shapes every query, every permission check, and every report for years. The ORM you use to access it is replaceable.

Churn happens at the edges, not the core

Not everything moves at the same speed.

graph TD
    A[Bundlers, build tools, styling] -->|Cheap to change alone| B[Frontend + backend frameworks]
    B -->|Cheap to change as a team| C[Databases, HTTP, queues]
    C -->|Expensive to change across teams| D[Domain boundaries, tenancy, data ownership]

The closer to your domain, the more people need to coordinate to change it, and the more expensive it is to get wrong.

Consistency beats optimality

A mediocre stack used consistently beats a “better” stack used inconsistently across services or teams. Not because the tools are worse, but because every additional stack choice is another place developers have to stop and ask how things work before they can change them.

A team using one language, one framework style, and one deployment model moves faster than a team mixing three “better” tools. A consistent stack reduces onboarding time, reduces debugging scope, reduces integration friction, and makes code transferable between teams.

The cost of switching stacks is rarely technical. It’s cognitive. In a car marketplace, if the listings service uses Express with Knex and the payments service uses NestJS with TypeORM, every developer who crosses that boundary has to context-switch between two mental models of how things work. The services might both be “good” choices in isolation, but together they slow everyone down.

Where the stack does decide

Stack does become the bottleneck in narrow conditions. Latency budgets that no garbage-collected runtime can meet. Regulated environments where the runtime itself has to be on an approved list. Talent pools where the choice locks you out of the hiring market you actually have.

Picture a car marketplace standardising on a niche functional language because the founding engineer prefers it. The founding team ships fast, the codebase stays small and consistent, the stack feels like a competitive advantage. 2 years in, the company needs to hire 8 engineers in 6 months and the local market has 12 candidates with the language on their CV, 3 of whom are willing to consider the salary band. The stack didn’t slow the founders down, it slowed the company down at the moment growth depended on hiring. That’s a real lock-in, not a refactor away. The same shape shows up at the latency end: a real-time bidding service handling 50,000 requests per second is going to feel its language choice in a way a CRUD admin panel never will, and no amount of architectural cleanup compensates for a runtime that can’t meet the budget.

Outside those narrow conditions, stack disagreements are usually proxies for an unresolved question about boundaries or ownership. The new framework promises to fix what’s actually a coupling problem. The “more performant” runtime is offered as a substitute for splitting a service that’s doing too much. Resolve the boundary question first. The stack debate either answers itself or stops mattering.

Teams scale systems, not stacks

As systems grow, the primary constraint shifts from what the stack can do to what teams can change without asking permission. A single-team system can tolerate any mainstream stack. A multi-team system depends on clear ownership, stable contracts, and predictable boundaries.

Most scaling problems are coordination problems long before they are technical ones. The questions that actually predict whether your team ships aren’t about tools:

  • Can we deploy independently?
  • Can we change schemas safely?
  • Can we add features without cross-team coordination?
  • Can we reason about failures locally?
  • Can a new developer make a confident change in their first week?

Stack choice affects these indirectly at best. What affects them directly is how you model your data, where you draw your boundaries, and whether your architecture makes the easy path the safe path.

Pick the stack you can move in today. Spend the architectural budget on the boundaries your team will live with for years. You’re not locked into a tool. You’re locked into who depends on it.