A local improvement can impose system-wide costs
A framework can improve one team’s work while adding to the burden on everyone around it. Existing applications may become costly to migrate, outside developers may struggle with tooling, publishers may face pressure to adopt, and browsers may have to execute more code. For engineering and marketing leaders, architects, and developers, the question is whether the improvement remains worthwhile once those costs are counted.
Useful technical goals can carry these costs. Offline applications, type safety, maintainable components, modular development, and responsive interfaces all address real needs. Yet incompatible migrations, corporate restrictions on Hypertext Markup Language (HTML), and designs that exceed practical browser limits show how implementation choices can undermine those goals. Enthusiasm for a new framework can make earlier failures easy to overlook.
The seven cases below examine different conditions: agreement among browser vendors, continuity for existing users, usability outside a sponsor’s environment, freedom to adopt, and work assigned to browsers. Each matters to large enterprises, distributed teams, and small and medium development shops. Their importance depends on the project; a technology can suit some settings while imposing serious costs in others. Architecture reviews need to examine those costs throughout implementation, because the sponsoring team’s daily experience may hide them.
Browser standards depend on participation
Web SQL addressed a practical need: applications had to remain useful without a continuous network connection. A relational database in the browser could store data locally, support offline work, and synchronize with an authoritative back-end store. But making that capability available across browsers required agreement among the organizations responsible for implementing it.
Apple promoted Web SQL through an implementation built closely around SQLite, and Google added it to Chrome. Both companies had an interest in adoption of a browser capability they supported, but Mozilla and Microsoft objected to making browser infrastructure depend on one specific C library. Agreement on local relational storage therefore depended on accepting SQLite as its foundation. Web SQL was subsequently deprecated, taking that option away from developers.
Deprecation left the application requirement intact, so developers turned to the less convenient IndexedDB. Later choices included PGLite, which uses WebAssembly (Wasm), a format browsers can execute, and local-first solutions such as PowerSync, which prioritize locally available data. Work on offline applications continued. These alternatives also separate the value of local storage from the fate of one proposed standard.
For teams choosing a browser capability, this history makes participation part of the technical assessment. An implementation can demonstrate usefulness while leaving other browser vendors unwilling to accept its dependencies. So a review should ask whose agreement the design requires and what applications will inherit if that agreement fails. Corporate resources can help build an implementation, but agreement remains a separate requirement.
A project in mind?
Schedule a 30-minute meeting with us.
Senior experts helping you move faster across product, engineering, cloud & AI.
Framework design includes the migration path
Agreement among implementers addresses one adoption barrier; continuity for existing users addresses another. Angular.js led the field in single-page apps (SPAs), which update an interface within an already loaded page. It also had performance bottlenecks and an architecture that had become hard to maintain. Google’s component-based replacement, Angular 2, sought better maintainability, a stronger fit for enterprise development, and higher performance.
Google had an interest in keeping developers on its framework, yet the replacement was incompatible with existing applications. Large enterprise codebases had no clear migration route, so the proposed architectural improvement immediately created an investment problem. Teams had to work out how to reach the replacement while maintaining functioning applications. React benefited from that break in continuity.
The migration route therefore belonged inside the design decision. Even a demanding transition can give users work they can estimate, schedule, and fund; an unclear route leaves them unable to plan continued participation. An architecture review should examine that route alongside the replacement’s technical benefits. Web SQL’s standards dispute and Angular 2’s compatibility break require different remedies, even though both affected adoption.
Tools must work beyond the sponsor’s environment
Existing users need a route forward, and new users need a tool that works in their own development environments. Facebook’s Flow aimed to provide type safety for large JavaScript codebases by detecting incompatible uses of data. Its granular type inference worked out types from code, reducing the annotations developers had to write. Facebook benefited from tooling suited to its own engineering work, but Flow developed within the company’s controlled environment.
Outside Meta, developers encountered bugs, a resource-heavy background server, and crashes on Windows. These operating costs hurt adoption even when developers valued Flow’s inference capabilities. Flow’s development also neglected the wider open-source ecosystem, eroding the advantage of its early position and technical strengths. Microsoft, a competing provider of developer tooling with its own interest in adoption, responded to that opening with TypeScript.
The gap between internal and external use makes the development environment part of the product’s design. A widely used tool needs sustained attention to outside teams’ operating systems, workflows, and constraints. Reviews should ask where the tooling has been tested in practice and whose daily problems shape its development. Success within the sponsor’s environment establishes suitability there; wider adoption requires more work.
Platform pressure changes the adoption decision
A tool’s practical fit matters less when a powerful platform can pressure others to use it. Google AMP emerged as expanding mobile use exposed slow sites, large bundles, and poorly optimized assets produced by practices established over the previous 15 years. AMP, short for Accelerated Mobile Pages, aimed to reduce the HTML, JavaScript, and image data delivered to devices. It also required a universal cache operated through a content delivery network (CDN), which distributes content to users.
Google pushed publishers toward AMP’s restricted, proprietary subset of HTML by threatening search rankings. Its role therefore extended beyond supplying technology: control over search visibility gave Google power over publishers’ adoption decisions. Publishers had to weigh their dependence on Google alongside the technical requirements. Ranking pressure and rigid restrictions made AMP anti-competitive and limited innovation, while giving Google greater influence over how publishers delivered pages.
Community resistance showed that publishers and developers could reject vendor lock-in presented as “performance optimization”. A related authority problem occurs in small and medium shops when management imposes coding standards that generate friction, resentment, and rebellion among developers. The mechanisms differ, but both make freedom to choose relevant to adoption. A review should distinguish a technology’s practical benefits from the influence used to secure its use.
Runtime styling assigns work to the browser
Adoption costs also arise after a team freely chooses a technology, because development convenience can move work onto users’ devices. Runtime CSS-in-JS illustrates that trade-off by generating styles through JavaScript while an application runs. It addressed real difficulties in managing Cascading Style Sheets (CSS): global names can collide, and specificity, the rules that determine which style takes precedence, can make changes hard to predict.
These difficulties become coordination problems when distributed enterprise teams share an application. Keeping styles beside JavaScript component code clarified ownership, kept styling logic within the component, and supported removal of unused code. Developers could change a component and its presentation together, reducing the need to navigate a large shared stylesheet. Those workflow benefits explain the appeal.
The runtime implementation, however, made those benefits depend on additional browser execution. The browser downloaded substantial JavaScript, ran code to calculate styles during rendering, and inserted those styles into the document. So displaying the interface depended on downloading and executing that code. Every user’s device took on work created by the development arrangement.
A five-year period of using this browser-side approach exposed the cost. Browsers already parse native CSS efficiently, whereas runtime calculation and insertion add work to the single-threaded JavaScript engine. Initial loading suffers, and mobile processors spend resources generating styles. The architectural choice therefore affects both how much code users receive and how much computation their devices perform.
These costs prompted renewed use of CSS Modules, modern native CSS, and zero-runtime compilers such as Tailwind. These approaches retain the aims of modularity and maintainability while avoiding the same browser-side style-calculation and insertion process. Reviews should ask where styling work occurs and how much must happen during rendering. Component-level developer experience and user-device performance both belong in that assessment.
Independent front-end teams share one execution environment
Styling can add computation to a page; separating its features into independently delivered applications can add coordination costs as well. Micro front ends apply microservice-style separation to the user interface (UI), assigning different features to different teams. Each team can develop, test, and deploy its part independently, using a smaller codebase and releasing incremental updates. Large organizations gain autonomy and easier maintenance within each team’s area.
The user still needs those separately delivered features to behave as one application. Splitting a previously unified interface can send multiple JavaScript bundles, duplicate dependencies, and even different versions of UI frameworks to the same page. Each team’s delivery choice adds to the browser’s total workload. Deployment independence therefore creates a shared execution problem.
That problem extends to behavior and application state, the data that represents the interface’s current condition. The browser must coordinate separately built features while state can become fragmented across them. Teams then manage both their own features and the interactions between features, increasing architectural complexity and degrading performance. An internal division of responsibility has become an end-user runtime requirement.
This gives teams a practical reason to examine Conway’s Law, the tendency for systems to reflect the organizations that build them. A useful team boundary can influence design without determining how browser code must be packaged and executed. Separation that helps back-end scaling needs its own assessment when applied inside a browser. Reviews should ask whether team autonomy requires independent runtime applications and what dependencies that choice duplicates.
For some designs, ECMAScript Modules, the JavaScript language’s module system, and modern buildless infrastructure offer a proposed alternative to micro-front-end complexity. They provide another way to consider code separation before committing to independently running applications. As complexity grows, teams should revisit the original division and the benefits it delivers. Otherwise, another coordination mechanism can preserve the problem that made coordination difficult.
Responsive interfaces require decisions about state and rendering
Micro front ends divide responsibility among browser-side features; client-side-only SPAs also divide responsibility between the browser and the back end. Their appeal is a rich, native-like interface whose local state updates the display reactively, meaning changes appear as the underlying data changes. JavaScript can show those updates immediately. But once the same data must remain consistent with stored records, responsiveness also requires synchronization.
In a common arrangement, the browser’s JavaScript engine manages local state and exchanges synchronization messages with the back end using JavaScript Object Notation (JSON), a text format for structured data. An architectural layer translates messages between clients and the data store. Much of the business logic runs in the client, leaving the server comparatively passive. Decisions about behavior and data changes are consequently spread across multiple locations.
Spreading those decisions creates distributed-computing problems because each client’s representation must stay coordinated with the back end. Immediate local updates determine where work starts, while synchronization determines how the system maintains consistency afterward. Assigning more state management and business logic to the browser increases the application’s responsibility for coordinating them with the server. A responsive interface can therefore require a substantial synchronization architecture.
The resulting coordination work helps explain the subsequent effort to restore server-side rendering, in which the server produces a page’s initial HTML. Over the last five years, teams built large meta-frameworks, frameworks that organize lower-level framework capabilities into a broader application structure, to bring server execution back into client-heavy applications. Next.js is the full-stack example of this response, spanning browser and server responsibilities. Rich interfaces remained the goal, while substantial development effort went into returning rendering and other work to the server.
Concluding thoughts
The common issue across these cases is where the costs fall. A framework can simplify development while increasing browser workloads, making migrations harder, or creating dependence on a vendor. Those benefits may still justify adoption, but the sponsoring team’s experience alone cannot establish the business case.
For decision-makers, this means evaluating who gains, who takes on additional work, and whether those groups have a practical choice. A proposal should explain how existing applications will migrate, how the technology works outside the sponsor’s environment, and what users’ devices must download and execute. Team autonomy also needs to be weighed against the cost of coordinating the resulting application.
These questions belong in funding and architecture reviews, with ownership assigned to costs that cross team boundaries. Otherwise, individual teams can meet their delivery goals while the organization absorbs growing maintenance, integration, and performance burdens. Reviews should continue after adoption, when actual usage makes those trade-offs clearer.
The aim is to preserve useful improvements without accepting every implementation choice that comes with them. Local storage, type safety, modular components, and responsive interfaces remain valuable goals. A sound technology decision delivers those benefits at a cost the wider organization can understand, sustain, and revisit.
A project in mind?
Schedule a 30-minute meeting with us.
Senior experts helping you move faster across product, engineering, cloud & AI.


