Choosing a Framework
There is no winner. There are constraints — team, existing code, hiring, rendering strategy, bundle budget, support horizon — and the framework that fits the most of yours.
The intent, the obvious build, and why it breaks
Every lesson starts where the work starts: someone wanted an outcome, and the first implementation that comes to mind has a problem.
Given what my team, my product and my users actually need, how do I choose, and what am I signing up for?
A team is starting something they intend to run for five years. They want to make one decision now that they will not have to unmake in eighteen months.
Compare the benchmarks and the bundle sizes, pick the framework that wins, and get on with it. The technical answer is the answer.
The benchmark measures keyed list reconciliation on a fast machine. Real applications are dominated by data fetching, bundle size, third-party scripts and layout — none of which the benchmark touches (Measure Before Optimising).
- The benchmark measures keyed list reconciliation on a fast machine. Real applications are dominated by data fetching, bundle size, third-party scripts and layout — none of which the benchmark touches (Measure Before Optimising).
- Bundle size comparisons are usually taken at the size no real application has. The runtime floor and the per-component cost trade against each other, and which one dominates depends on how many components you end up with (Bundle Analysis).
- The decision is mostly not technical. Who is available to hire, what your team already knows, what your existing code is written in, and who will maintain this in three years all outweigh a millisecond of update cost.
- It is also not a single decision. Rendering strategy, router, data layer, component library and build tooling are separable choices, and some of them matter more to your users than the framework does (Choosing a Rendering Strategy).
- And it is reversible only in theory. A framework choice propagates into every component, every test, every hire and every library dependency; changing it later is a rewrite priced as a refactor.
What is actually happening
In the browser, not in the framework.
- The criteria that actually predict regret are: what the team already ships, what you can hire for, what your existing code is, what rendering strategy you need, what your bundle budget is, and how long you need this to be supported.
- Team knowledge compounds. A framework the team knows produces working software immediately and produces good decisions six months in. A framework they are learning costs you both, at once, on your first deadline.
- Ecosystem is a risk position. A large ecosystem means an existing answer to most problems and a large surface of unmaintained packages. A small one means fewer answers and more first-party consistency (Third-Party Scripts and the Supply Chain).
- Server rendering is the axis most likely to be decided for you. If the product depends on content being visible to crawlers, to link previews, or to a user on a slow connection before JavaScript arrives, the meta-framework matters more than the view layer (Server-Side Rendering).
- Bundle budget interacts with everything. The framework is one term; the router, the data layer, the component library, the date library and the analytics script are the others, and they are frequently larger (The Real Cost of JavaScript).
- Support horizon is a constraint, not a preference. How long releases are supported, how upgrades have historically gone, and how much of the ecosystem follows are all knowable before you commit (Long-Lived Clients and Version Skew).
What this makes the browser do
And which of it is avoidable.
- Whatever you choose, the browser does the same job: parse and compile the JavaScript, run it, mutate the DOM, then style, layout, paint and composite (The Rendering Pipeline).
- The framework decides how much JavaScript runs per update. The application decides how much JavaScript exists, and that is usually the larger number (The Real Cost of JavaScript).
- Hydration cost is a function of the rendering strategy and the amount of interactive surface, and it is more likely to dominate your loading profile than the update model is (Hydration).
- Third-party scripts do not care which framework you chose, and on many real sites they are the biggest main-thread contributor by a wide margin (Third-Party Scripts and the Supply Chain).
The decision, with the costs attached
Every option below is a defensible choice made by serious teams shipping serious products. The point of the list is not to rank them; it is that each when comes with a cost you are agreeing to, and the choice is which cost you would rather carry.
Note the last two options. "The one your team already ships" is frequently the correct answer and is almost never argued for, because it is not interesting. "No framework" is a real option that is under-considered for small, long-lived, mostly-static surfaces, and over-considered for applications with complex state.
What constraint dominates: hiring, consistency, bundle, update cost, or the code you already have?
when You need the widest hiring pool, the largest library ecosystem, and an existing answer to almost any problem; or you already have React code.
cost Assembling your own stack from an ecosystem with real churn, a re-render model that needs escape hatches at scale, and a large surface of packages that will be abandoned.
when You want strong first-party defaults for routing, tooling and state without an entirely integrated framework, and templates your designers can read.
cost A smaller hiring pool than React in most markets, and two systems — compiler and tracking runtime — to understand when reactivity behaves unexpectedly.
when Bundle size and per-update work matter, the application is small to medium, and you want less framework at runtime.
cost Semantics that live in a build step, a smaller ecosystem and hiring pool, and per-component code that grows with component count.
when The application is update-heavy — a dashboard, an editor, a canvas — and minimal per-update work is worth a stricter reactivity contract.
cost The smallest ecosystem of the five, fewer engineers who have used it, and a model that requires unlearning re-render habits.
when A large or multi-team organisation, a long maintenance horizon, and consistency across many codebases is worth more than flexibility.
cost The largest runtime floor, the most to learn before the first useful commit, and an in-progress transition between two change-detection models.
when You have working code, working knowledge, and a deadline. This is the correct answer far more often than it is chosen.
cost You inherit its constraints, including the ones that prompted the question — so write down what specifically is not working before you overrule this.
when A mostly-static site, a widget embedded in someone else's page, or something that must still work unchanged in ten years.
cost You reimplement routing, state, accessible components and rendering as you need them — including the accessible-component part, which is the expensive one (Accessible Component Patterns).
Constraints, and what each one should actually move
A framework argument goes badly when the participants are weighing different constraints without saying so. Making the weighting explicit converts an argument about taste into a shared decision, and usually shortens it considerably.
Read the last column as the honest one. Several of these constraints should not move your framework choice at all — they should move a different decision, and mistaking which is how teams end up choosing a view layer to solve a delivery problem.
| Constraint | What to ask | What it should move |
|---|---|---|
| Team knowledge | What has this team shipped and maintained before? | The framework choice, more than anything else on this list |
| Existing code | What is already written, and who maintains it? | The framework choice, or the decision not to make one |
| Hiring | Who can we hire where we actually hire, in two years? | The framework choice, weighted by how much you plan to grow |
| Server rendering | Do users need content before JavaScript runs? | The meta-framework and rendering strategy first, the view layer second (Choosing a Rendering Strategy) |
| Bundle budget | What is the total budget, including everything that is not the framework? | A CI budget check. Framework choice is one term of several (Bundle Analysis) |
| Update-heavy UI | Are there high-frequency updates over large collections? | The update model — and virtualisation first, which usually matters more (List Virtualization) |
| Accessibility requirements | What does the component library actually do with keyboard and focus? | The component library, and your testing practice. Not the framework (Accessibility Testing) |
| Support horizon | How long are releases supported, and how have upgrades gone? | The framework choice for anything long-lived (Long-Lived Clients and Version Skew) |
| Ecosystem needs | Does the one hard component we need already exist and work? | The framework choice, if that component is genuinely central |
How this decision actually goes wrong
The failures below are not hypothetical framing devices; they are the recurring shapes of a decision made on the wrong evidence. Each has the same structure: a real signal was measured, and it was not the signal that predicted the outcome.
| Trigger | Symptom | Cause | Response |
|---|---|---|---|
| Chosen on benchmark results | The app is still slow after the rewrite | The bottleneck was data fetching, images and third-party scripts | Profile the existing product first. The framework is rarely the top entry (Measure Before Optimising). |
| Chosen on a hello-world bundle size | The shipped bundle is dominated by everything else | Runtime floor was compared instead of the real application | Prototype the hardest screen and measure the whole bundle (Bundle Analysis). |
| Chosen for team enthusiasm | The first deadline slips on unfamiliar tooling | Learning cost landed on the critical path | Weight existing knowledge explicitly, or buy the learning time before the deadline exists. |
| Chosen without the rendering strategy | Content is invisible to crawlers and slow on first load | The view layer was chosen before the delivery model | Decide the rendering strategy alongside the framework (Choosing a Rendering Strategy). |
| Chosen, then migrated mid-project | Two partial applications, one team, no delivery | The cost of a framework change was priced as a refactor | Finish, then migrate deliberately at a boundary — and price it as the rewrite it is (Micro Frontends). |
| Chosen well, with no bundle or a11y budget | A fast framework inside a slow, inaccessible product | The framework was the only decision anyone reviewed | Put budgets and accessibility checks in CI, where they outlive the decision (Accessibility Testing). |
How to build it
Most important first.
- Write down your constraints before you look at any framework: team, hiring market, existing code, rendering needs, bundle budget, accessibility requirements, support horizon. The list is the decision; the framework is the conclusion.
- Weight team and existing code heavily. They are the constraints most likely to decide whether the project ships, and the ones most often left out of the comparison.
- Decide the rendering strategy alongside the framework, because it determines which meta-framework you are really choosing and it affects users more directly (Choosing a Rendering Strategy).
- Prototype the hardest screen, not the easiest. A todo list tells you nothing; the screen with a virtualised table, a complex form and live updates tells you everything (List Virtualization).
- Check the accessibility story concretely: what the component library actually does with keyboard and focus, what the router does on navigation, and what the testing tools can assert (Accessibility Testing).
- Record the decision and its reasons somewhere durable. In two years the constraints will have changed, and you will want to know which ones you were optimising for.
Keyboard, focus, semantics, announcement
A required field on every lesson in this domain, not a section added when there is room.
- No framework here makes a UI accessible, and every one makes it possible to build an inaccessible one without a single warning (Semantics Before ARIA).
- What differs is the surrounding ecosystem: whether the component library you will actually use has real keyboard support and focus management, and whether the router gives you a place to announce navigation (Accessible Component Patterns).
- Client-side routing is an accessibility decision in every framework. A view swap with no announcement and no focus move is a silent navigation for a screen-reader user (Client-Side Routing).
- Frameworks that replace DOM nodes more aggressively lose focus more often. It is a real difference and it is a smaller one than the difference between a team that tests with a keyboard and one that does not (Focus Management).
- Ask what the testing story is for accessibility before you commit, because an automated check finds a minority of issues in every framework (Accessibility Testing).
What can go wrong
- Choosing for a benchmark and discovering the bottleneck was your data layer, your images and a tag manager.
- Choosing the framework the team is most excited about and paying for it in the ramp-up on the first deadline.
- Choosing for a hiring market that does not exist where you are actually hiring.
- Choosing a view layer and then discovering that server rendering, routing and data loading were the real decisions (Choosing a Rendering Strategy).
- Migrating mid-project, which delivers two half-finished applications and a shared vocabulary problem (Micro Frontends is often proposed here and is a bigger commitment than it looks).
- Choosing correctly and then losing the benefit to a component library with no keyboard support, a chart library that ships a megabyte, and no bundle budget in CI.
- All five escape interpolated text and all five provide a raw-HTML door. The security difference between them is close to zero; the difference between codebases that audit those calls and codebases that do not is large (Cross-Site Scripting).
- The dependency tree is the real exposure, and it grows with ecosystem size and with how much you assemble yourself (Software Supply Chain Security in Security).
- A framework with a first-party stack has a smaller third-party surface by construction, which is a genuine security property and also a constraint on what you can use.
- Server-rendering anything means your component code runs on a server, and every framework here has the same module-scope hazard when it does (Server-Side Rendering).
- "There is a best framework." There is a best fit for a set of constraints, and constraints differ per team, per product and per year. Anyone who answers without asking about your team is answering a different question.
- "Framework choice is the most important frontend decision." Rendering strategy, data layer, bundle budget and third-party scripts each move user-visible numbers more, in most products (Choosing a Rendering Strategy).
- "Popular means correct." Popularity is a real advantage in hiring and libraries and is not an argument about the technology.
- "We can migrate later." A framework choice reaches every component, every test and every hire. Later migration is a rewrite, and it competes with the roadmap for years.
- "Small bundle means fast." Bundle size is one term in loading, and loading is one of three concerns users actually feel (Measure Before Optimising).
Measuring it, and what changes in the field
- Prototype your hardest screen in the two finalists and measure both on a mid-range device — the only benchmark that is about your application (Measure Before Optimising).
- Measure the whole bundle for that prototype, including router, data layer and component library, not the framework in isolation (Bundle Analysis).
- Measure the team: how long to a working feature, how many questions had no findable answer, how much of the code review was about the framework rather than the product.
- Check field data from products already built with each candidate, if you can get it. Real loading and interaction data beats any comparison you can construct (Real User Monitoring).
- For a small team with a deadline, existing knowledge dominates everything else on this list.
- For a large organisation with many teams, consistency and a supported upgrade path dominate, and an opinionated stack becomes an advantage rather than a constraint.
- For a content-heavy product, the rendering strategy and delivery decide what users feel, and the update model barely registers (Loading: Why Content Arrives Late).
- For a highly interactive application — an editor, a dashboard, a canvas tool — the update model genuinely matters, and so does the ecosystem for the specific hard components you need.
- For a long-lived internal application, the support horizon and upgrade cost outrank everything a user will notice.
- Choosing the popular option buys hiring, libraries and answers, and costs you the churn of a large ecosystem and a large surface of packages that will be abandoned.
- Choosing the integrated option buys consistency and a smaller decision surface, and costs flexibility where the first-party answer does not fit.
- Choosing the smallest, newest option buys a model you may genuinely prefer and costs you libraries, examples and the availability of people who have already made your mistakes.
- Choosing nothing — the platform plus a small amount of code — buys minimal dependency and longevity and costs you every convenience you will otherwise reimplement, including the hard ones (Accessible Component Patterns).
Where this applies
Frontend advice ages badly and fragments across engines. These labels say what each claim is specific to, and where a different browser, device or framework would differ.
- GENERALThe criteria — team, existing code, hiring, rendering needs, bundle budget, ecosystem, support horizon — apply to any framework choice, including choosing none. What varies is the weighting, and the weighting is a property of your organisation rather than of the frameworks.
- FRAMEWORK-SPECIFICThe option costs listed below are about the five frameworks in this module as they currently stand: React's ecosystem size and churn, Vue's and Svelte's strong first-party defaults, Solid's smaller ecosystem, Angular's integrated stack and larger runtime floor. Each of those has moved within recent memory and should be re-checked rather than quoted.
- SPEC-EVOLVINGFramework capabilities converge quickly: signals, compilers, server rendering models and streaming have all crossed between these projects in recent releases. A comparison written today is a snapshot, and the criteria outlive the conclusions.
Where the depth lives
This domain teaches the browser-side mechanism and hands the rest off.
- — Software Design — a framework choice is a dependency-direction decision at the largest scale you make one, and the parts of your application that do not depend on it are the parts that survive the next one.
- — Testing & Reliability Engineering — what each candidate lets you test, and how fast, is a constraint that belongs in the comparison and is almost never in it.