The browser as operating system — JavaScript’s accidental dominance
JavaScript is the most-deployed programming language in the world. It runs in every web browser; in 2026 it runs on most of the world’s servers through Node.js; it runs inside desktop applications built with Electron and its descendants; it runs inside mobile applications built with React Native; it runs inside embedded systems through various lightweight runtimes. The estimated number of devices on which a JavaScript engine runs is in the billions. The language that achieves this deployment was designed in ten days in May 1995 by Brendan Eich at Netscape, with the constraint that it had to look like Java for marketing reasons, with no formal review of its design, with no expectation that it would become important, and with several specific design choices that its author has since publicly regretted. The accidental nature of JavaScript’s design and the consequential nature of its deployment are not in proportion, and the disproportion has shaped what the web is. This chapter is about that disproportion: how JavaScript arrived, how it became unavoidable, what its dominance has done to the web, and what the consequences have been for the document that the web was originally designed around.
Eich’s ten days
Brendan Eich joined Netscape in April 1995, hired to build a scripting language for the browser. The product context was that Netscape Navigator 2.0 was scheduled to ship in late 1995 with several new features, one of which was to be a programming language for embedding logic in web pages. The marketing context was that Java had just been released by Sun Microsystems in May 1995 and was the most-hyped programming language of the moment. Netscape had a partnership with Sun that included an agreement to bundle the Java runtime in Navigator, but Netscape’s leadership also wanted a scripting language that was easier to use than Java and that did not require the Java runtime for simple scripting tasks. Eich was given approximately two weeks to produce a working prototype, with the constraint that the language should look like Java so that the partnership marketing would make sense.
Eich’s ten days produced what he called Mocha. The language was a small, dynamically-typed, prototype-based scripting language with a syntax that looked superficially like Java’s: curly braces, semicolons, function keyword, var declarations. Underneath the Java-flavored syntax was a different language entirely. Mocha had first-class functions (a feature from Scheme, one of Eich’s preferred languages). It had prototype-based object inheritance (a feature from Self, the Smalltalk variant). It had loose typing and automatic type coercion that produced behavior different from Java’s stricter typing. It had a small set of built-in objects and a string-and-number-centric standard library. It had no module system, no error-handling beyond simple try/catch (which was added later), no proper class system (also added later), and no namespacing of any kind. The whole thing was, in language-design terms, an unholy mashup of incompatible traditions, produced under time pressure with no review and shipped because it had to be.
The language was renamed LiveScript before Navigator 2.0 shipped, and then renamed JavaScript in December 1995 for the announcement of the Netscape-Sun partnership. The naming has caused decades of confusion: JavaScript and Java share a syntactic family but are otherwise unrelated languages, with different semantics, different runtimes, different standard libraries, and different design philosophies. The naming was, by Eich’s own subsequent admission, a marketing decision that the language has had to live with.
The first version of JavaScript shipped in Netscape Navigator 2.0 in March 1996. It could handle form validation, simple animations, dynamic HTML manipulation, and other narrow scripting tasks. Microsoft, watching, reverse-engineered the language and shipped a compatible implementation called JScript in Internet Explorer 3.0 in August 1996. The two implementations differed in some details, and the browser-incompatibility nightmares of the late 1990s included substantial JavaScript-specific issues. The submission to ECMA for standardization happened in November 1996; ECMAScript 1 was published in June 1997. The language had been stabilized externally before its design was reviewed by anyone other than its original author.
The DHTML era and the AJAX inflection
For the first several years of JavaScript’s existence, it was used primarily for what was then called Dynamic HTML or DHTML: small scripts that manipulated the page’s HTML to produce effects that were not possible with static markup alone. Dropdown menus, mouse-over image swaps, form validation, simple animations, the rollover effects that were the early signature of dynamic web pages. DHTML was widely deployed but not, in any deep sense, important. The web was still primarily a document medium with some interactive decoration; JavaScript was the decoration.
The shift came in the early 2000s, slowly at first and then suddenly. Microsoft had added the XMLHttpRequest object to Internet Explorer 5.0 in 1999, originally as a feature for Outlook Web Access. Mozilla, Apple, and Opera implemented compatible versions in their browsers over the next few years. XMLHttpRequest let JavaScript make HTTP requests to the server without reloading the page; the page could update its content in response to user actions by fetching new data from the server in the background. This is a small-sounding capability with large consequences.
The capability was used, beginning around 2003 and 2004, to build web applications that behaved more like desktop applications than like documents. Google Maps, released in February 2005, was the most prominent early example: a map you could drag and zoom continuously, with the map tiles being fetched as needed from the server through XMLHttpRequest, with no page reloads. Gmail, released in April 2004, was another: an email client with a desktop-like interface that lived inside a single web page. Both of these felt, to users of the era, like a different kind of thing than the web they had known.
Jesse James Garrett, a designer at Adaptive Path, coined the term AJAX (Asynchronous JavaScript and XML) in February 2005 to describe the pattern. The term spread quickly. AJAX was the moment the web stopped being a hypermedia document system and started being an application platform. The shift was structural. Pre-AJAX web pages were documents that you navigated; the unit of interaction was the page, and the page was a thing you fetched, looked at, and possibly submitted a form from. Post-AJAX web pages were applications that you used; the unit of interaction was the user action, and the page was a long-lived stateful environment in which actions happened.
The change in the web’s character was not announced. There was no W3C Recommendation that said “the web is now an application platform.” The browser vendors had not, in any coherent way, decided to make this change. It happened because developers found XMLHttpRequest useful, because users responded to applications built with it, because Google’s exemplars proved that the pattern worked, and because the commercial logic of the web rewarded application-like experiences. The shift from document to application was bottom-up, organic, and irreversible.
V8 and the performance era
JavaScript was, through the early and mid-2000s, slow. The implementations were interpreters with limited optimization; performance varied across browsers by an order of magnitude; complex JavaScript applications strained the browsers of the era. The slowness was a real constraint on what could be built. Google Maps and Gmail were impressive precisely because they had been engineered to work around the JavaScript performance limitations, with substantial effort spent on optimizing the application code to fit within what the engines could handle.
Google released the Chrome browser in September 2008. Chrome’s principal innovation was its JavaScript engine, V8, designed by Lars Bak and a team in Aarhus, Denmark. V8 was a just-in-time compiler that produced native machine code from JavaScript source, with optimization techniques borrowed from decades of compiler research in other languages. V8 was, on launch, approximately ten times faster than the JavaScript engines in the other browsers, and the gap forced the other vendors to catch up. Mozilla’s TraceMonkey, Apple’s Nitro (later JavaScriptCore), Microsoft’s Chakra (in Internet Explorer 9) — each was a response to V8, each was a substantial engineering investment in JavaScript performance, and each had cumulative effects on what was possible to build in the browser.
By 2010 or so, JavaScript performance was no longer the primary constraint on what could be built. Applications that would have been impossible in 2005 ran smoothly in 2012. The result was that the application web, which AJAX had made possible at the lower-end, became practical for serious applications. The mature single-page application era — where almost the entire user-facing logic of a web application runs in JavaScript in the browser, with the server providing data through JSON APIs rather than HTML pages — became feasible. The shift had begun with AJAX in 2004; it became dominant practice in the 2010s.
V8 had a second consequence that was, in some ways, larger than its first. Ryan Dahl, an engineer who had been watching the V8 work, realized that the V8 engine could be extracted from the browser and used as a standalone JavaScript runtime. He built Node.js, released in May 2009, which embedded V8 as a server-side JavaScript runtime with a non-blocking I/O model. Node.js was an immediate success in a niche that nobody had quite expected: server-side JavaScript turned out to be a useful tool, both because JavaScript was a language that web developers already knew and because the event-driven I/O model fit naturally with the kinds of network applications web developers were building.
The combination of fast browser engines and Node.js produced, by the mid-2010s, a world in which JavaScript was the lingua franca of both client and server, in which the same language and many of the same libraries could be used on both sides of the network, and in which the package ecosystem (npm, the Node Package Manager) had grown into the largest software library in the world. The npm registry contained, by 2020, more than a million packages, with billions of downloads per week. The scale of the JavaScript ecosystem is genuinely unprecedented; nothing in software history had grown this big this fast.
Frameworks
The application web’s growth produced demand for frameworks: structured ways to organize the code of a JavaScript application that handled common concerns like state management, DOM updates, routing, and component composition. The framework story has been one of rapid succession.
jQuery, by John Resig, was released in August 2006. It was not a framework in the modern sense; it was a library that smoothed over browser incompatibilities and made common DOM manipulation tasks easier. jQuery was, however, the dominant library of the late 2000s and early 2010s, and most JavaScript applications of the period used it. Its eventual decline came as the browsers themselves became more consistent and as more ambitious frameworks emerged.
Backbone.js (Jeremy Ashkenas, 2010) and Knockout.js (Steve Sanderson, 2010) were among the early frameworks that introduced explicit structure for client-side applications, with models, views, and the binding between them. Angular (Misko Hevery and Adam Abrons at Google, 2010, with substantial rewrites in subsequent versions) introduced a more opinionated framework with two-way data binding and dependency injection. Ember (Yehuda Katz, 2011) provided convention-over-configuration in the Rails tradition.
The framework that has had the largest sustained impact is React, released by Facebook in May 2013. React’s principal contribution was a programming model based on declarative component descriptions and a virtual DOM that handled the messy details of updating the actual DOM efficiently. React’s success drove a wave of imitators and complements: Vue.js (Evan You, 2014), Svelte (Rich Harris, 2016), Solid.js, Preact, and many others have built on React’s component model. The component model is now the dominant way of organizing web applications, with most modern web applications structured as trees of components written in JSX or similar syntaxes.
The framework churn has been, depending on perspective, either a healthy ecosystem evolution or a chronic source of pain for working developers. The term “JavaScript fatigue” emerged around 2016 to describe the experience of trying to keep up with the ecosystem’s evolution: new frameworks, new tools, new conventions, new package managers, new build systems, each requiring relearning and rebuilding. The fatigue is real. It is also, in some sense, the price of an ecosystem that has been growing rapidly for two decades, with each generation of practitioners trying to improve on the previous one’s mistakes. The ecosystem’s energy has been one of the web’s structural advantages over slower-moving alternatives; the energy’s downside is the churn.
The document-application inversion
The cumulative effect of JavaScript’s growth is that the web has, slowly, inverted its relationship between document and application. The early web was a document medium with applications as occasional special cases (a search form, a guestbook, a simple shopping cart). The middle web was a document medium with increasingly sophisticated application features layered on top. The contemporary web is, for many of its users most of the time, an application medium with documents as occasional special cases (a Wikipedia article, a static blog post, a documentation page).
The inversion has had structural consequences for the kinds of properties the web exhibits.
A document is addressable. It has a URL. The URL points to the document. Anyone can link to the document. The link will, modulo link rot, retrieve the document. An application’s URL, by contrast, points to the application’s entry point. The user’s experience within the application — what they are looking at, what state the application is in, what they have done — is typically not in the URL. Single-page applications have, to varying degrees, attempted to recover URL-based addressability through history API manipulation and route-based architectures. The recoveries are partial. A URL into the middle of a complex web application is much less reliable, as a citation or a shared link, than a URL into a document.
A document is preservable. You can save it. The Internet Archive can save it. Someone can read it twenty years later by retrieving the saved copy. An application is not easily preservable. The application is the live system: the server, the database, the JavaScript runtime, the network connections to various services. Saving the JavaScript file does not save the application, because the application is more than the file. The Internet Archive saves what it can of web applications, but the saves are dramatically less complete and less useful than the saves of documents.
A document is composable. You can quote from it, link to specific parts of it, embed it in other documents, transform it. An application is much less composable. The application’s content is, often, not visible to anything outside the application’s own runtime. Search engines can crawl it imperfectly, with the help of various server-side rendering techniques. Other applications can call its APIs, with permission. But the easy quote-and-link composition that documents support is not available for applications.
A document is readable in its source. View-source on a document shows you the document. View-source on a modern web application shows you a minified JavaScript bundle and a nearly-empty HTML shell. The learnability that view-source provided in the document era is mostly gone in the application era.
These are real losses. They are not losses anyone has decided to inflict on the web; they are emergent consequences of the inversion from document to application. The recovery efforts treated in Part V are, in part, attempts to recover the document properties — addressability, preservability, composability, source visibility — for parts of the web where they still matter.
The npm ecosystem and its pathologies
The npm registry deserves its own brief treatment, because it has become a significant piece of the JavaScript story and exhibits both the strengths and the pathologies of the ecosystem.
The strengths are real. A working JavaScript developer can, with a few commands, pull in libraries for almost any task they have ever needed to do, from low-level utilities to high-level frameworks. The ecosystem covers an enormous range of needs. The barrier to publishing a package is low; anyone with an account can publish anything. The barrier to using a package is also low; anyone with npm install can pull it in.
The pathologies are also real. The low barriers mean that the registry contains many packages of low quality, many overlapping packages, many abandoned packages, and a substantial population of packages that are essentially trivial. The famous “left-pad” incident in March 2016 — when a single-developer’s removal of a 17-line utility package broke a large fraction of the JavaScript ecosystem because so many other packages depended on it — illustrated how the dense dependency graph of npm could fail catastrophically from very small disturbances. The dependency graphs of modern JavaScript projects are enormous: a typical web application can have thousands of transitive dependencies. The supply-chain security implications are serious; the various attacks on the ecosystem through compromised packages have been a recurring problem.
The npm ecosystem is, in some ways, the most direct artifact of JavaScript’s accidental dominance. A language and ecosystem this large, this dense, and this consequential would, under most circumstances, be governed and curated more carefully than npm is. The npm registry’s open-publishing model is the natural extension of the ethos that produced JavaScript itself: ship it, let the market sort it out, accept the chaos as the price of the growth. The model has been broadly successful and has paid its own price.
WebAssembly
WebAssembly, standardized in 2017 as a W3C Recommendation, is the most recent major addition to the browser’s runtime environment. WebAssembly (often shortened to Wasm) provides a portable bytecode format that browsers can execute at near-native speed. The bytecode can be produced from many source languages — C, C++, Rust, Go, and others have working WebAssembly toolchains — and lets web applications run code that does not need to be JavaScript.
The motivation for WebAssembly was practical. Some applications had performance requirements that JavaScript, even with V8’s optimizations, could not meet. Photoshop on the web, video editing applications, scientific computing applications, games — these benefited from being able to compile from C++ or Rust to a portable bytecode that ran in the browser at near-native speed. WebAssembly has, in the eight years since its standardization, found a real niche. It is not the dominant runtime — JavaScript still is — but it is a meaningful supplement, used in significant applications and growing in adoption.
The WebAssembly story is interesting for what it does and does not change. It does not change the basic architecture of the application web: applications still run in the browser, talk to servers through HTTP, and live inside the broader web’s substrate. It does open the browser to languages other than JavaScript, which has incremental benefits for what kinds of applications are practical and which developers can build for the web. The longer-term consequences are still unfolding; whether WebAssembly becomes a more central piece of the web’s runtime or remains a specialized supplement is, in 2026, still being decided.
The browser as operating system
The cumulative effect of JavaScript, the frameworks, the npm ecosystem, WebAssembly, and the various web APIs is that the browser has become, in functional terms, an operating system. A modern web application is, structurally, similar to a desktop application: it has UI components, persistent state, background processing, network connections, access to device hardware (camera, microphone, location), and a complete runtime environment. The browser provides the abstraction layer between the application and the underlying hardware, in much the way that Windows or macOS does for desktop applications. The web platform’s specification — the full set of APIs that browsers must implement — is, in 2026, comparable in size and complexity to the API surface of a major desktop operating system.
This is not an accident. It is the cumulative consequence of decades of feature addition, each defensible in isolation, that has produced a runtime environment of operating-system scale inside a runtime environment that was designed in 1995 as a way to add interactivity to documents. The browser is the operating system most users actually use for most of their consumer software, and the operating system underneath the browser — Windows, macOS, ChromeOS, iOS, Android — has become, for most consumer purposes, a relatively thin wrapper around the browser.
The shift from “operating system runs applications, one of which is a browser” to “operating system runs a browser, which runs applications” is one of the most important structural changes in computing in the last quarter-century. It has consolidated enormous power in the hands of the browser vendors, who collectively define what is possible in the browser through the W3C/WHATWG process. It has produced economies of cross-platform development that have benefited many developers and many users. It has also, for the argument of this book, completed the document-to-application transformation that the IMG tag started in 1993. The web is no longer, in any meaningful sense, a document system. It is a runtime for distributed applications, on top of which some applications happen to render documents.
What JavaScript’s dominance has cost
A summary of the costs JavaScript’s accidental dominance has produced:
Performance complexity. Web applications now run substantial JavaScript on every page load. The cost of executing the JavaScript falls on the user’s device, with corresponding effects on battery life, mobile data usage, and the experience of users on lower-end hardware. The performance regressions that JavaScript has produced are paid most heavily by users least able to afford them.
Document fragility. Pages that depend on JavaScript to render their content are inaccessible to users without JavaScript, to search-engine crawlers that do not execute JavaScript well, to accessibility tools that work better with static HTML, and to archival systems that cannot easily preserve dynamic content. The fragility is a real loss for the web’s broader social functions.
The application monoculture. The dominance of a single language for the entire web platform has produced an ecosystem of imitation: most web applications look like each other, behave like each other, and have similar failure modes. The diversity of approaches that existed in pre-web hypermedia systems has been narrowed dramatically.
The advertising and tracking infrastructure. JavaScript provides the mechanism by which web pages embed third-party scripts that track users, deliver advertising, and collect behavioral data. The web’s privacy story is, in significant part, a story about what JavaScript has made possible that would not have been possible with static HTML.
Source opacity. As discussed above, the readability of source that view-source provided has eroded. The teaching tradition that view-source supported has weakened correspondingly.
What it has given us
JavaScript’s dominance has also given the web capabilities it would not otherwise have. Interactive applications that work on every platform without separate development. Real-time collaboration tools that descend, ultimately, from Engelbart’s vision. Browser-based video conferencing that was, twenty years ago, impossible. Maps, photo editing, document editing, scientific computing, games — all running in the browser, all written in JavaScript or compiled to WebAssembly, all available to anyone with a browser. The application web’s reach is enormous, and most of the world’s software, by user count, now runs in browsers.
The trade-off is the one this book has been describing throughout. The document properties have been eroded; the application properties have grown. The recovery work in Part V is, in part, work to bring the document properties back without losing the application properties. Whether this can be done is the question Part V tries to answer.
The next chapter takes the institutional consequence of all this: the platform decade in which a small number of companies absorbed most of what the rest of us thought we were building. Google, Facebook, Amazon, and a handful of others became, through the 2010s, the operators of the systems on which the rest of the web depended. The platform story is the political-economic counterpart to the technical story of the application web, and the two together produced the web of the present, which is what Part V is trying to find ways to recover from.