Products Web Frameworks

Where Should the Program Run?

Why do web frameworks keep swinging between doing everything on the server and doing everything in the browser?

The web was built for documents, and frameworks have spent thirty years making it behave like software. Every generation has moved the work between the server and the browser, and every move was a correction for the costs of the last one.

A pendulum hangs from the top centre, swinging between a server rack on the left and a browser window on the right, with faint earlier positions marked 1995, 2005, 2013 and 2021.
A pendulum hangs from the top centre, swinging between a server rack on the left and a browser window on the right, with faint earlier positions marked 1995, 2005, 2013 and 2021.

For people who build products

Decisions worth studying

5 decisions from this history, each with the situation, the alternatives, what happened and a verdict. Open one for the full case. The verdict says how a decision turned out, which is not the same as whether it was wise; see moral luck.

  1. 1994–1995 · Rasmus Lerdorf (PHP) Paid off Mix code into HTML pages and make deployment as simple as copying a file The easiest product to start with often wins, even if it is not the cleanest.
    Situation
    Dynamic pages needed CGI programs that were awkward for non-specialists.
    Alternatives
    Separate code from templates in a cleaner architecture.
    What happened
    Much of the early dynamic web, and some of its largest platforms, were built on PHP.
    Verdict
    Purists found it untidy; the low barrier to starting mattered more.

    Pattern Distribution beats elegance

  2. 2004–2005 · Rails and Django Paid off Make the routine decisions once, for everyone (“convention over configuration”) Identify the decisions that do not deserve your users’ attention, and make them for them.
    Situation
    Developers were making hundreds of small decisions repeatedly in every project.
    Alternatives
    Flexible frameworks that let every team configure everything.
    What happened
    Small teams could build web applications quickly, and the frameworks’ opinions became their value.
    Verdict
    Taking choices away saved more time than flexibility ever offered.

    Pattern Taking choices away can be the product

  3. 2013 · Facebook (React) Paid off Describe the interface as a function of state and let the library work out the changes Declarative interfaces win when the system can handle the how reliably.
    Situation
    Developers had to track which data changed and update the page by hand.
    Alternatives
    Two-way data binding and templates, as other frameworks used.
    Numbers
    React was used by 44.7% of respondents in Stack Overflow’s 2025 survey.
    What happened
    React became one of the most used web technologies, and its model spread across frameworks.
    Verdict
    Separating what from how, the same move relational databases made, simplified a hard problem for millions of developers.

    Pattern Hiding the machine wins once the machine is cheap

  4. 2010s · The web industry Mixed Build sites as single-page JavaScript applications Measure the cost of your choices on your users’ worst devices, not your own.
    Situation
    Rich applications needed interactivity that full page reloads could not provide.
    Alternatives
    Render pages on the server and add interactivity selectively.
    Numbers
    The median mobile page loaded 558 KB of JavaScript in 2024, about 44% of it unused.
    What happened
    Responsive applications, but heavy pages that loaded slowly on cheap phones and could be hard for search engines to read.
    Verdict
    The cost was paid by readers’ devices, not by the developers who chose the approach; the industry later swung back toward the server.

    Pattern Making something cheap moves the cost to someone elseComputing swings between the centre and the edge

  5. 2019–2021 · Etsy, Google and Astro Paid off Render pages on the server and hydrate only small “islands” of interactivity When the pendulum swings back, it lands somewhere new; look for what has changed since the last time.
    Situation
    Single-page applications sent far more code than many pages needed.
    Alternatives
    Keep shipping full client-side applications.
    What happened
    Islands, server components and edge rendering became mainstream answers; this site is built that way.
    Verdict
    A return to progressive enhancement, with a server now distributed close to every reader.

    Pattern Computing swings between the centre and the edge

This page is an example of the subject it describes. It was built with a framework called Astro, which turned the essay into plain HTML before anyone asked for it, and it sends almost no JavaScript to your device. The small interactive pieces, the search box and the colour theme switch, are “islands” of code in an otherwise static document. Ten years ago, the fashionable way to build a site like this would have been to send a JavaScript application to your browser and let it assemble the page there. Twenty years ago, a program on a server would have assembled the page on every request. Thirty years ago, it would have been a hand-written file.

Each of those choices was considered best practice in its time, and each was abandoned for reasons that made sense. Web development frameworks have been swinging back and forth between the server and the browser for three decades. To understand why, it helps to see what a framework actually is: a set of answers to two questions. Where should the program run? And who should make the routine decisions, the framework or the developer? Every major framework is a distinct pair of answers, shaped by what was cheap and what was scarce when it was built.

The web was not designed for applications

The World Wide Web was designed for documents. A browser asked a server for a page by its address, the server sent back a file of marked-up text, and the browser displayed it. Links connected pages to other pages. There was no notion of a running application, of a user session, of a button that changed something without loading a new page.

In 2000 Roy Fielding, one of the authors of the HTTP specification, described the architecture that had made the web work in his doctoral dissertation. He called it Representational State Transfer, or REST, and defined it as a set of constraints: a uniform interface, stateless requests, cacheable responses, a layered system. Among them was a principle that would be quoted, argued over and frequently ignored for the next two decades: the interface constraint of “hypermedia as the engine of application state.”1 In plain terms, the state of an interaction lived in the documents themselves. Each page carried the links and forms that said what you could do next.

This matters because almost everything that followed was an attempt to make a document system behave like an application platform. Frameworks are, in large part, the accumulated workarounds and abstractions that made that possible.

When the server did everything

The first step was letting a server compute a page instead of merely retrieving one. The Common Gateway Interface, introduced in 1993, let a web server hand a request to a program, often a small script, and send back whatever HTML the program printed. Search forms, guestbooks, shopping carts and every other dynamic page began here.

PHP grew directly out of this world. Its official history records that Rasmus Lerdorf created it in 1994 as “a simple set of Common Gateway Interface (CGI) binaries written in the C programming language,” originally used “for tracking visits to his online resume,” and named “Personal Home Page Tools.” He rewrote it to support databases and simple dynamic applications “such as guestbooks,” and in June 1995 released the source code to the public.2

PHP’s design reflected its origin. Code and HTML were mixed in the same file; a page was a document with small programs embedded in it. Purists found this untidy. It was also extraordinarily easy to start with: copy a file to a server and it ran. That low barrier is why much of the early dynamic web, and some of its largest platforms, were built on PHP.

The theory of the program in this era was simple. The server held all the state and did all the work. The browser was a display terminal. Each click was a new request and a new page. The costs were visible to every user as the familiar white flash of a page reloading after every action.

Large companies, meanwhile, built web applications with enterprise technologies such as Java servlets and the J2EE platform, which brought powerful abstractions and a reputation for heavy configuration. Frameworks like Spring emerged partly as simplifying reactions to that weight. The pattern of one generation’s framework being a reaction to the previous one’s burden appears again and again.

Frameworks as packaged judgment

By the early 2000s, building a web application meant making hundreds of small decisions over and over: how to name database tables, where to put files, how to map addresses to code, how to protect forms. Two frameworks released within a year of each other turned those decisions into a philosophy.

Ruby on Rails, released in 2004 by David Heinemeier Hansson, was extracted from a working product rather than designed in the abstract. Its later statement of principles, “The Rails Doctrine,” lists nine pillars, beginning with “Optimize for programmer happiness” and “Convention over Configuration.”3 The explanation of the second is blunt. “One of the early productivity mottos of Rails went: ‘You’re not a beautiful and unique snowflake.’ It postulated that by giving up vain individuality, you can leapfrog the toils of mundane decisions, and make faster progress in areas that really matter.” Does it matter, the doctrine asks, whether a database key is called “id,” “postId,” “posts_id” or “pid”? “Is this a decision that’s worthy of recurrent deliberation? No.” Rails, it says, swings “its machete at the thick, and ever growing, jungle of recurring decisions.”3 Another pillar is titled, with a chef’s metaphor, “The menu is omakase”: let the framework choose the dishes.

Django came from a different kitchen with the same insight. Its documentation explains that it “grew from a very practical need: World Online, a newspaper web operation, is responsible for building intensive web applications on journalism deadlines. In the fast-paced newsroom, World Online often has only a matter of hours to take a complicated web application from concept to public launch.” Its developers, Adrian Holovaty and Simon Willison, switched from PHP to Python in 2003 and extracted a framework from their work, releasing it as open source in the summer of 2005.4 Its tagline describes its intended users exactly: “The web framework for perfectionists with deadlines.”

The theory of the developer in these frameworks was new. The developer’s attention was the scarce resource, and much of what consumed it was decision-making that did not deserve it. A good framework would make those decisions once, well, for everyone, and leave the developer free to work on what made their application different. A framework became a product of judgment as much as of code, and its opinions were its value.

The page learns to stay put

The pendulum began to move toward the browser in 2005. Google’s Gmail and Google Maps showed web pages that updated without reloading: mail arrived, maps panned smoothly. In February 2005 the designer Jesse James Garrett gave the approach a name in an essay that became widely cited. “Ajax isn’t a technology,” he wrote. “It’s really several technologies, each flourishing in its own right, coming together in powerful new ways.” An Ajax application “eliminates the start-stop-start-stop nature of interaction on the Web” by introducing a JavaScript engine in the browser that talks to the server in the background while the user keeps working.5

Garrett’s framing is revealing. The problem he named was the web’s defining characteristic, the request-and-reload cycle, and the solution was to put a layer of application logic between the user and the server. Libraries such as jQuery, released in 2006 with the slogan “write less, do more,” smoothed over the differences between browsers and made such techniques available to ordinary developers.

One language, both ends

JavaScript had been tried on servers before. Netscape’s own server products in 1995 supported it.6 But the language was slow, and server developers used other tools. That changed after Google released its V8 JavaScript engine with the Chrome browser in 2008, which made JavaScript fast.

In 2009 Ryan Dahl introduced Node.js, which combined V8 with an event loop and non-blocking input and output. Its own description remains: “As an asynchronous event-driven JavaScript runtime, Node.js is designed to build scalable network applications.” It contrasted itself with the more common model of operating-system threads: “Thread-based networking is relatively inefficient and very difficult to use.” In Node, “almost no function in Node.js directly performs I/O, so the process never blocks except when the I/O is performed using synchronous methods.”7

Node’s practical consequence was as important as its technical one. For the first time, the same language and many of the same libraries could run on both the server and the browser. A package manager, npm, followed in 2010 and grew into one of the largest software repositories in the world. The boundary between front end and back end became, for many developers, a boundary they could cross without changing tools.

The browser becomes the application

The next step moved the application almost entirely into the browser. Frameworks such as Backbone and AngularJS, both from 2010, organised client-side code into models and views. In 2013 Facebook released React, and its introduction stated a sharply different philosophy.

“React isn’t an MVC framework,” wrote Pete Hunt in a June 2013 post explaining why Facebook built it. “React is a library for building composable user interfaces. It encourages the creation of reusable UI components which present data that changes over time.” It did not use templates; it used JavaScript itself to describe the interface. And it changed how updates worked. In traditional applications, developers had to find what data had changed and modify the page to match. React instead re-rendered a lightweight description of the whole view whenever data changed, compared it with the previous one, and applied only the differences, a process it called reconciliation. “Because this re-render is so fast,” Hunt wrote, “the developer doesn’t need to explicitly specify data bindings.”8

The idea underneath is that the user interface is a function of state: describe what the screen should look like for given data, and let the library work out how to get there. It is the same move that relational databases made decades earlier for queries, separating what from how. Vue, released in 2014, and many others adopted variants of the approach.

The single-page application became the dominant model for ambitious web software. The server’s role shrank to providing data through APIs, often JSON over HTTP, which also served the growing number of mobile apps. The browser downloaded a JavaScript application, which fetched data and built every page itself.

The theory of the program had flipped. The browser held the state and did the work. The server became a database with an interface.

The bill arrives on the reader’s device

The single-page model made rich, responsive applications possible. It also moved a cost onto everyone who visited such a site, and onto the device least able to pay it.

The HTTP Archive measures millions of websites every year. Its 2024 report found that the median web page loaded 558 KB of JavaScript on mobile devices, up from 491 KB the year before and from 359 KB in 2019. On mobile, a median of 206 KB of that, around 44 percent, was never used on the page.9 JavaScript is not just downloaded; it must be parsed and executed, and on an inexpensive phone that work takes far longer than on a developer’s laptop. Pages that rendered nothing until their JavaScript arrived could show users a blank screen, and could be difficult for search engines to read.

This is the cost-shifting pattern visible across computing history. The single-page model saved developers effort and servers work. The savings reappeared as work done on readers’ devices, by their processors, on their batteries, over their data plans. The people bearing the cost were not the people making the choice.

The swing back

The response came from inside the frameworks themselves.

Next.js, released in 2016, let React applications render their first page on the server and then take over in the browser, combining fast initial display with client-side interactivity. Static site generators built pages ahead of time and served them from content delivery networks. The technique of “hydration,” sending server-rendered HTML and then attaching JavaScript to make it interactive, became standard, along with its own costs: often the entire application still had to be downloaded and run.

A sharper idea emerged in 2019. Jason Miller, a developer at Google, credited Katie Sylor-Miller, an architect at Etsy, with coining the “component islands” pattern in a meeting that year. “The general idea of an ‘Islands’ architecture is deceptively simple,” he wrote: “render HTML pages on the server, and inject placeholders or slots around highly dynamic regions,” which can then be hydrated on the client “into small self-contained widgets.” He noted that “a closer analog to the ‘islands’ approach would be progressive enhancement,” the old principle of starting with a working document and adding interactivity on top.10 Astro, the framework that built this page, was designed around islands from its release in 2021.

React’s own team moved in the same direction. In December 2020 it previewed “zero-bundle-size React Server Components,” components that render on the server and send no JavaScript of their own to the browser.11 Other projects, such as htmx, returned explicitly to Fielding’s hypermedia: the server sends HTML fragments, and the browser swaps them into the page.

Meanwhile the server itself moved. “Serverless” platforms let code run in response to requests without managing machines, and edge platforms run that code in data centres close to each user. This page is served that way. The pendulum did not simply swing back to 1995; the server it returned to is now distributed around the world, a few milliseconds from the reader.

What the web is built with today

Stack Overflow’s 2025 developer survey shows how the layers of this history coexist. Among respondents who answered the question, the most used web technologies were Node.js (48.7 percent), React (44.7 percent), jQuery (23.4 percent), Next.js (20.8 percent), Express (19.9 percent), ASP.NET Core (19.7 percent), Angular (18.2 percent) and Vue.js (17.6 percent), followed by Python frameworks such as FastAPI and Flask.12

Two features of this list stand out. The first is jQuery’s persistence, two decades after its release and long after newer frameworks made it unnecessary for new projects. Deployed code, like stored data, is sticky: once a technique is embedded in millions of pages, it stays for years. The second is the coexistence of client-heavy and server-heavy approaches. There is no longer a single fashionable answer to where the program should run. There is a spectrum, and choosing a place on it has become one of the main decisions in building for the web.

Understanding the philosophy

Web frameworks are argued about with unusual passion, and the arguments are rarely only about performance. Beneath them lie questions about how much people should have to think about, how communities agree on rules, what a page tells its reader it can do, how a thing stays the same while it changes, who should bear the costs of a design, when to keep old things and when to replace them, and where the truth of an application should live. This section takes these questions one at a time. Each is explained in plain terms, connected to the philosophical tradition that has thought about it most clearly, traced in the history above, tested against its strongest objection, and applied to building for the web today. The connections to named thinkers are interpretations, offered to make the ideas understandable; framework authors mostly did not cite them.

1. Progress by not having to think

The idea in plain terms

A good framework lets developers stop thinking about things that do not deserve thought, so that they can think about things that do. Every routine decision it makes for you is attention returned to you.

The tradition

In An Introduction to Mathematics (1911), the philosopher and mathematician Alfred North Whitehead wrote: “Civilization advances by extending the number of important operations which we can perform without thinking about them.” He was arguing for good notation in mathematics, but the point is general. Skills, habits, institutions and tools all work by turning what once required deliberate thought into something automatic.

Where it shows up

The Rails Doctrine’s pillar “Convention over Configuration” is Whitehead’s principle applied to web development: it swings “its machete at the thick, and ever growing, jungle of recurring decisions,” so that developers can “make faster progress in areas that really matter.”3 Django’s origin in a newsroom with “only a matter of hours” to launch an application is a story about the same need: the routine had to become automatic so that the important could get done.4

The strongest objection

Operations performed without thinking are also operations not understood. Developers who learned only a framework’s conventions may not know why those conventions exist or what to do when they fail. The history of frameworks includes many applications that worked well until they hit a case the framework had not anticipated, at which point no one on the team understood the layer beneath.

What it means today

The healthiest relationship with a framework is to let it carry routine decisions while knowing, roughly, what those decisions are. AI coding tools intensify the trade-off, because they make it possible to produce working code without thinking about almost anything. Whitehead’s principle says that is progress; the objection says it is progress only if someone, somewhere, still understands.

2. Conventions as solutions to coordination problems

The idea in plain terms

Does it matter whether a database key is called id or postId? Not in itself. What matters is that everyone on a team, and every tool they use, agrees. Many of a framework’s rules are valuable not because they are right but because they are shared.

The tradition

In Convention (1969), the philosopher David Lewis gave an influential account of conventions as solutions to coordination problems: situations in which people benefit from acting alike, but where there is more than one way to do so. Driving on the left or the right is the classic example. Neither side is better; what matters is that everyone chooses the same one. A convention, for Lewis, is a regularity that persists because each person expects others to follow it, and it is in everyone’s interest to follow it if others do.

Where it shows up

The Rails Doctrine’s question, whether a primary key is “id,” “postId,” “posts_id,” or “pid,” and its answer, that this is not a decision “worthy of recurrent deliberation,” is a perfect Lewisian case.3 The framework does not claim that id is intrinsically superior. It solves a coordination problem among developers, libraries and tools by picking one answer. The same logic explains file layouts, URL patterns and naming rules across frameworks, and why moving between projects that share conventions is so much easier than moving between projects that do not.

The strongest objection

Some conventions are not arbitrary; they embody genuine design judgements that may be wrong for a given project. Treating every framework rule as a harmless convention can hide real trade-offs. The skill is distinguishing arbitrary conventions, which are worth following, from substantive choices, which are worth examining.

What it means today

Much of the value of popular frameworks lies in their conventions, not their code. That is also why frameworks persist: once a community has coordinated on a set of conventions, the cost of changing them is borne by everyone at once.

3. A page that tells you what you can do

The idea in plain terms

A link says “you can go here.” A form says “you can send this.” A plain web page shows its reader, in its own content, what actions are possible next. Many modern applications hide those possibilities inside code.

The tradition

The psychologist James J. Gibson introduced the term affordance in The Ecological Approach to Visual Perception (1979) to describe what an environment offers an animal: a flat surface affords walking, a handle affords grasping. The designer Don Norman brought the idea into technology design, emphasising that good design makes affordances visible. Roy Fielding’s REST constraint of “hypermedia as the engine of application state” describes the same idea for the web: the representation the server sends contains the links and forms that afford the next steps.1

Where it shows up

Early server-rendered pages were hypermedia in this sense; every possible action was visible as a link or form in the HTML. Single-page applications often moved those possibilities into JavaScript, where buttons and routes are created by code rather than described in the document. The recent revival of hypermedia-oriented tools, and the progressive-enhancement philosophy behind islands, is in part a return to pages that declare their affordances in their own structure.

The strongest objection

Many applications need interactions that links and forms cannot express: drag-and-drop editors, real-time collaboration, rich visualisations. For these, a programmatic interface is not a loss of affordance but the only way to provide it.

What it means today

A useful question for any page is whether its possibilities are visible in its own content, to people, browsers, search engines and assistive technologies alike, or only discoverable by running its code. The more of the first, the more robust and accessible the page tends to be.

4. How a thing stays the same while it changes

The idea in plain terms

When a list on screen updates, which items are “the same” items as before, and which are new? If a user is typing into one item while the list reorders, the framework must decide what counts as the same element, or the user’s typing may jump to the wrong place.

The tradition

This is a very old puzzle. Plutarch described the Ship of Theseus, preserved by the Athenians, whose planks were replaced one by one as they rotted. Philosophers asked whether it remained the same ship, and Thomas Hobbes later added a twist: if someone collected the old planks and rebuilt the ship from them, which ship would be the original? The puzzle concerns identity through change: what makes something the same thing over time.

Where it shows up

React’s central idea, re-rendering a description of the whole interface whenever data changes and reconciling it with the previous one, runs straight into the Ship of Theseus.8 Each render produces a new description; the library must decide which parts of the new description correspond to which existing parts of the page. React’s answer is the key: a stable identifier that tells it “this item is the same item as before, even though everything about it may have changed.” Without keys, React guesses identity by position, and when items move, state can end up attached to the wrong ones. In effect, React requires developers to answer the identity question explicitly.

The strongest objection

This is a technical mechanism, and calling it philosophy may seem grand. But the connection is real rather than decorative: any system that describes the world as a series of states must decide what persists across them. Databases face the same question with primary keys, and the history of the database essay on this site turns on how identity is represented.

What it means today

Declarative interfaces made programmers stop writing instructions for change and start describing states. The price is that identity must be stated explicitly. Understanding that trade explains a large class of subtle interface bugs.

5. Whose computer pays: costs, externalities and fairness

The idea in plain terms

A website sends code to run on its visitors’ devices. If the code is heavy, the visitors pay: in slower pages, drained batteries and data charges. The people who decide how much code to send are rarely the people who pay for it.

The tradition

The economist Arthur Pigou described externalities in The Economics of Welfare (1920): costs or benefits of an activity that fall on people who did not choose it, such as pollution from a factory. Externalities are a classic source of unfairness and inefficiency, because those who decide do not bear the full consequences. The philosopher John Rawls, in A Theory of Justice (1971), proposed a way to think about fairness: choose principles from behind a veil of ignorance, not knowing what position you will occupy in the society they govern.

Where it shows up

The HTTP Archive’s finding that the median mobile page sent 558 KB of JavaScript in 2024, about 44 percent of it unused, describes an externality: a cost generated by builders and borne by readers, many of them on inexpensive phones and limited data plans.9 The swing toward server rendering, islands and zero-bundle components is, in part, an internalisation of that cost. Applying Rawls, a designer who did not know whether they would be visiting the site on a new laptop with fibre or an old phone on a congested network would choose to send far less.

The strongest objection

Rich client-side applications provide real benefits to their users, and many users have powerful devices. Some cost on the client is the price of features people want. The question is proportion, not prohibition.

What it means today

The veil of ignorance is a practical design tool. Testing on the slowest device and connection one’s users actually have, and treating each kilobyte as a cost imposed on someone else, turns an abstract principle of fairness into engineering decisions.

6. When to keep the old and when to replace it

The idea in plain terms

Web development has gone through many frameworks, each promising to fix its predecessors. Some replacements were improvements; some threw away hard-won lessons. Knowing which is which is one of the hardest judgements in the field.

The tradition

In The Thing (1929), G. K. Chesterton described a fence across a road. A reformer proposes to remove it because he sees no use for it. Chesterton’s reply was that one should not remove it until one knows why it was put there; once one knows, one may remove it. This has become known as Chesterton’s fence. Nassim Nicholas Taleb, in Antifragile (2012), popularised the Lindy effect: for non-perishable things such as ideas and technologies, every additional period of survival suggests a longer remaining life expectancy.

Where it shows up

Server rendering was abandoned by much of the industry for single-page applications, then rediscovered when the reasons it existed, fast first loads, readability by search engines, low demands on devices, reasserted themselves. That is a Chesterton’s-fence story. jQuery’s continued use by nearly a quarter of surveyed developers in 2025, two decades after its release, is a Lindy story.12 The Rails Doctrine’s own pillar “Progress over stability” states the opposite priority explicitly.

The strongest objection

Progress requires replacing things whose reasons are not fully understood, because understanding them all would take forever. And the Lindy effect describes survival, not quality; some old technologies survive because they are hard to remove, not because they are good.

What it means today

Before adopting a new framework or rewriting an old system, it is worth stating plainly what problem the existing approach solved and whether the new one still solves it. Many expensive rewrites fail Chesterton’s test.

7. Where the truth of an application lives

The idea in plain terms

If the same piece of data exists both on the server and in the browser, and they disagree, which is right? Every web architecture must decide where the authoritative version lives.

The tradition

An old saying, often called Segal’s law, puts the problem neatly: a person with one watch knows what time it is; a person with two watches is never sure. In epistemology, the question is how to resolve conflicting sources of evidence; in distributed systems, it is how to keep replicas consistent, the subject of the CAP theorem and the consistency debates traced in the database essay.

Where it shows up

Fielding’s REST kept application state in the hypermedia the server sent. Single-page applications copied much of the state into the browser, creating two watches. State-management libraries, caching layers and synchronisation logic proliferated to keep them in agreement. Server components and hypermedia approaches reduce the duplication by keeping more truth on the server. Local-first software, discussed in the note-taking essay, takes the opposite approach, keeping the primary copy on the user’s device and synchronising with mathematical techniques that guarantee replicas converge.

The strongest objection

Duplicated state is not always a mistake. It allows applications to work offline, respond instantly and reduce load on servers. The right answer depends on whether the application must work without a connection and how costly temporary disagreement is.

What it means today

Many confusing bugs in web applications are disagreements between watches. Deciding deliberately where the truth lives, and which copies are merely caches, is one of the most important architectural choices a team makes.

Bringing the threads together

The philosophy of web frameworks turns out to be a philosophy of attention, agreement and responsibility. Frameworks advance by letting developers stop thinking about routine decisions, as Whitehead saw, and they work because communities coordinate on shared conventions, as Lewis explained. Pages are most robust when they show their affordances in their own structure. Declarative interfaces trade instructions for descriptions and must then answer the Ship of Theseus question explicitly. The costs of a design fall on readers who did not choose it, which is why fairness, in Rawls’s sense, belongs in engineering. Old approaches deserve Chesterton’s question before they are removed. And every architecture must decide where its truth lives. The pendulum between server and browser keeps swinging because each position answers some of these questions well and others badly. The frameworks that last are those that answer them deliberately.

Someone else’s computer

Return to the question at the start. Web frameworks keep swinging between server and browser because each position solves the problems of the last while creating costs that only become clear at scale. Server-rendered pages were simple and slow to interact with. Browser applications were responsive and heavy. Server rendering with islands tries to keep the responsiveness while sending less. Each swing has been a correction, and each correction has been informed by measurement of what the previous approach actually cost.

What the history suggests, beneath the swings, is a principle that can guide the next one. A web page runs on someone else’s computer. Every kilobyte of code a site sends is executed on a device the developer does not own, paid for with a battery, a processor and a data plan the developer does not pay for. The frameworks that have aged best are those that treat that device with care: that ask not how much they can do in the browser, but how little they need to. The web began as a document system that let anyone read anything. The best of its frameworks, whichever way the pendulum swings, have remembered that the reader comes first.

Selected bibliography

  • Fielding, Roy Thomas. Architectural Styles and the Design of Network-based Software Architectures. Doctoral dissertation, University of California, Irvine, 2000. Chapter 5, “Representational State Transfer (REST).” ics.uci.edu
  • The PHP Group. “History of PHP.” PHP Manual. php.net
  • Heinemeier Hansson, David. “The Rails Doctrine.” rubyonrails.org/doctrine
  • Django Software Foundation. “FAQ: General.” Django Documentation. djangoproject.com
  • Garrett, Jesse James. “Ajax: A New Approach to Web Applications.” Adaptive Path, 18 February 2005.
  • OpenJS Foundation. “About Node.js.” nodejs.org
  • Hunt, Pete. “Why did we build React?” React Blog, 5 June 2013. legacy.reactjs.org
  • Miller, Jason. “Islands Architecture.” 2020. jasonformat.com
  • Abramov, Dan, Lauren Tan, Joseph Savona, and Sebastian Markbåge. “Introducing Zero-Bundle-Size React Server Components.” React Blog, 21 December 2020.
  • HTTP Archive. Web Almanac 2024, “JavaScript” chapter. almanac.httparchive.org
  • Stack Overflow. 2025 Developer Survey, “Technology.” survey.stackoverflow.co/2025/technology
  • Wirfs-Brock, Allen, and Brendan Eich. “JavaScript: The First 20 Years.” Proceedings of the ACM on Programming Languages 4, HOPL (2020).
  • Whitehead, Alfred North. An Introduction to Mathematics. Williams and Norgate, 1911.
  • Lewis, David K. Convention: A Philosophical Study. Harvard University Press, 1969.
  • Gibson, James J. The Ecological Approach to Visual Perception. Houghton Mifflin, 1979.
  • Norman, Don. The Design of Everyday Things. Basic Books, 1988; revised 2013.
  • Plutarch. Life of Theseus, 23.
  • Pigou, Arthur C. The Economics of Welfare. Macmillan, 1920.
  • Rawls, John. A Theory of Justice. Harvard University Press, 1971.
  • Chesterton, G. K. The Thing. 1929.
  • Taleb, Nassim Nicholas. Antifragile. Random House, 2012.

Research limitations

Garrett’s 2005 essay was consulted through an archived copy of its original page. Dahl’s 2009 conference talk was not available in its original form, so Node’s design is described from the project’s own published description. The HTTP Archive figures are medians over the pages it crawls and say nothing about any particular site. The Stack Overflow figures describe a self-selected population of developers and are not market share. The essay’s description of the server-browser “pendulum” and its explanation by relative costs is the author’s interpretation of the history, not a claim made by the framework authors. This site’s own architecture is mentioned as an illustration, not an endorsement. The philosophical section relates web frameworks to Whitehead, Lewis, Gibson, Norman, Plutarch and Hobbes, Pigou, Rawls, Chesterton and Taleb; these are the author’s interpretive connections, offered to make the ideas understandable, and do not describe what framework authors intended.

Footnotes

  1. Roy Thomas Fielding, Architectural Styles and the Design of Network-based Software Architectures (University of California, Irvine, 2000), §5.1.5 “Uniform Interface.” ↩ ↩2

  2. The PHP Group, “History of PHP,” PHP Manual, section “PHP Tools, FI, Construction Kit, and PHP/FI.” ↩

  3. David Heinemeier Hansson, “The Rails Doctrine,” sections “Optimize for programmer happiness,” “Convention over Configuration,” and “The menu is omakase,” rubyonrails.org/doctrine. ↩ ↩2 ↩3 ↩4

  4. Django Software Foundation, “FAQ: General,” “Why does this project exist?”, Django Documentation. ↩ ↩2

  5. Jesse James Garrett, “Ajax: A New Approach to Web Applications,” Adaptive Path, 18 February 2005; archived at web.archive.org. ↩

  6. Allen Wirfs-Brock and Brendan Eich, “JavaScript: The First 20 Years” (2020), §2.2, which notes that Netscape’s LiveWire server was counting on embedding the language from its first prototype. ↩

  7. OpenJS Foundation, “About Node.js,” nodejs.org/en/about. ↩

  8. Pete Hunt, “Why did we build React?”, React Blog, 5 June 2013. ↩ ↩2

  9. HTTP Archive, Web Almanac 2024, “JavaScript” chapter, sections on bytes, requests and unused JavaScript. ↩ ↩2

  10. Jason Miller, “Islands Architecture,” jasonformat.com/islands-architecture. ↩

  11. Dan Abramov, Lauren Tan, Joseph Savona and Sebastian Markbåge, “Introducing Zero-Bundle-Size React Server Components,” React Blog, 21 December 2020, legacy.reactjs.org. ↩

  12. Stack Overflow, 2025 Developer Survey, “Web frameworks and technologies,” all respondents (23,678 responses to this question). ↩ ↩2

How it evolved

The arc

  1. 1993

    The Common Gateway Interface lets a web server run a program to produce a page. Every request can now be computed.

  2. 1994

    Rasmus Lerdorf writes “Personal Home Page Tools” to track visits to his online résumé. It grows into PHP.

  3. 2000

    Roy Fielding’s dissertation describes REST, the architectural constraints that made the web scale, including hypermedia as the engine of application state.

  4. 2004

    Ruby on Rails is released, extracted from a working product and built on “convention over configuration.” Django follows in 2005 from a newsroom.

  5. 2005

    Jesse James Garrett names Ajax. Web pages start behaving like desktop applications by talking to the server in the background.

  6. 2009

    Node.js brings event-driven JavaScript to the server, so one language can run on both ends.

  7. 2013

    React is introduced as “a library for building composable user interfaces” that re-renders when data changes. The single-page application era peaks.

  8. 2019

    The “islands” pattern is named: render HTML on the server and hydrate only small interactive regions.

  9. 2020

    React’s team previews “zero-bundle-size” Server Components, moving rendering work back to the server.

  10. 2024

    The median mobile page ships 558 KB of JavaScript, 44 percent of it unused, and frameworks compete on how little code they send.

Left open

Questions to sit with

  1. When you build for the web, whose computer are you spending, and have you asked permission?
  2. Is a framework that makes every decision for you a gift of time or a limit on thought?
  3. If the pendulum keeps swinging, what would a framework look like that was designed to move work freely in both directions?

Follow the thread

Where this essay connects

How to cite

Shrikant Kumar. “Where Should the Program Run?.” Essay on Web Frameworks, Telos, published 12 February 2023, updated 22 October 2026. https://shrikantk.com/blog/where-should-the-program-run/

Written by

Shrikant Kumar

A technology enthusiast trying to understand why things are built the way they are.

© 2023 Shrikant Kumar. All rights reserved. Short quotations with a link back are welcome; see copyright and reuse.

↑ ↓ to move↵ to open⌘K to toggle