The Website vs. Web App Dichotomy Doesn't Exist

You don’t need to wade far into web development discourse to hear about the website vs. web app dichotomy. It posits that websites can be grouped into two categories: mostly static “documents” with little user interaction beyond following links, and “applications” that involve rich dynamic behavior. Usually, people invoke it to talk about the use, abuse or avoidance of JavaScript frameworks.

A more nuanced view is that there’s a spectrum between website and web app, and that where a project sits determines which technologies are appropriate to build it. The implication is that at some point, it makes sense to use a JavaScript framework rather than progressively enhanced HTML. Web developers tend to divide themselves into roughly two camps here — and depending on which camp you ask, the location of that inflection point varies widely.

One camp says that everything to the left of Google Docs is a website that should function without JavaScript if possible.

A single horizontal axis with the left side labeled “website” and the right side labeled “web app”. The Google Docs logo sits about 90% of the way the right side; the remaining 10% to its right is labeled “JavaScript framework”, while the vast majority of the graph to its left is labeled “Progressive enhancement”.

The other camp says that anything to the right of a WordPress blog is a web app that should be built with a JavaScript framework.

A single horizontal axis with the left side labeled “website” and the right side labeled “web app”. The WordPress logo sits about 90% of the way the left side; the remaining 10% to its left is labeled “Progressive enhancement”, while the vast majority of the graph to its right is labeled “JavaScript framework”.

Svelte creator Rich Harris speaks to this in his 2021 talk Have Single-Page Apps Ruined the Web? Have Single-Page Apps Ruined the Web? | Transitional Apps with Rich Harris, NYTimes The backlash to modern front end development is gaining steam, with good reason: single-page apps have ruined the web. Can we rescue it without going backwar... youtu.be/860d8usGC0o . His position is that neither camp is fully correct; that most websites span regions of the spectrum rather than single points. He proposes the term “transitional apps” to describe websites that are neither fully “document” nor “application”.

While I agree that most websites defy binary categorization, I don’t buy the overall “website vs. web app” framing. They’re both nebulous terms that attempt to describe what a site is rather than what it does. Moreover, I don’t think a one-dimensional spectrum can sufficiently capture the tradeoffs involved in web development.

I like to think about websites along two axes:

  • Static vs. dynamic — how much of the page updates in response to user interaction?
  • Online vs. offline — how much functionality requires a persistent Internet connection?

Obviously, this is still a pretty crude survey, but I think it broadly captures the most important architectural constraints. Let’s call the intersections informational, transactional, realtime and local. Everyone loves a good quadrant chart!

A graph with two axes that intersect in the exact center, labeled static/dynamic horizontally and online/offline vertically. Clockwise from the intersection of static and offline on the bottom left, the four quadrants are labeled “informational”, “transactional”, “realtime” and “local”.

Informational Websites

We’ll start at the bottom left, at the intersection of static and offline: informational websites.

A graph with two axes that intersect in the exact center, labeled static/dynamic and online/offline vertically. The logos for WordPress, Medium and Wikipedia sit at the extreme corner of the static/offline quadrant labeled “informational”.

I’ve called out WordPress, Medium and Wikipedia, but most of the web lives here: pages of unmoving text and images, connected by hyperlinks. Our measure of static vs. dynamic is how much of the page updates in response to user interaction, and websites in this category tend to just swap the whole thing out at once. Blogs, business sites, newspapers and online courses all fall under this umbrella.1 WordPress alone powers over 40% of all websites!

The key technologies in this quadrant are HTML and CSS. When JavaScript is used, it’s usually for features like animations or interactive visuals that complement the textual content. At that point, people often bring in a JavaScript framework — vastly overpowered for the majority of the website — to accommodate the most dynamic parts of the page. More on this later.

One observation about this quadrant is that even though it doesn’t require an Internet connection to be usable, precious little of it is actually available offline.2 When you’re off the grid, each browser tab teeters precariously on the brink of annihilation. One errant refresh and it’s gone until you reconnect!

Transactional Websites

If we move up to the intersection of static and online, we get transactional websites.

These are so named because interaction mostly takes the form of transactions with a web server: the user clicks a button or submits a form, an HTTP request triggers a state change on the server and the whole page updates to reflect the new state. For websites in this quadrant, the server is a necessary component of all meaningful interaction.

A graph with two axes that intersect in the exact center, labeled static/dynamic and online/offline vertically. The logos for Amazon and Google sit at the extreme corner of the static/online quadrant labeled “transactional”.

Any service that involves literal financial transactions — like Amazon, or your bank’s website — probably lives here. So do social networks and search engines. In fact, when we exclude informational websites, most remaining websites are transactional.

This quadrant tends to be the most contentious. When the JavaScript community talks about web apps, they’re often referring to transactional websites — even though many are every bit as static as this blog.

Maybe that’s why the JavaScript community has spent the past couple years pouring resources into improving the user experience in this quadrant. At this point, every major frontend framework includes server-side rendering out of the box. Newer features like React Server Components React Labs: What We've Been Working On – March 2023 – React The library for web and native user interfaces react.dev/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components and Qwik’s resumability Resumable | Concepts 📚 Qwik Documentation No hydration, auto lazy-loading, edge-optimized, and fun 🎉! qwik.builder.io/docs/concepts/resumable/ push even further, blending client-side and server-side code to more easily express behavior that spans network boundaries.

At the same time, a more traditional approach to building transactional websites is becoming en vogue again, treating HTML as a hypermedia Hypermedia - Wikipedia en.wikipedia.org/wiki/Hypermedia that describes interactions rather than just as a rendering target for JavaScript. In the essay When Should You Use Hypermedia? </> htmx ~ When Should You Use Hypermedia? htmx.org/essays/when-to-use-hypermedia/ , htmx creator Carson Gross describes the ideal use case as “text-and-image heavy, with coarse-grain [UI] updates”. That certainly describes most transactional websites, where more immersive multimedia is rare and it’s common to update large swaths of the page at once.

Realtime Websites

At the intersection of dynamic and online, we have realtime websites.

These are websites that require faster and more fine-grained updates than HTTP requests to a web server can reasonably accommodate.

A graph with two axes that intersect in the exact center, labeled static/dynamic and online/offline vertically. The logos for Zoom, Discord and RuneScape sit at the extreme corner of the dynamic/online quadrant labeled “realtime”.

In 2024, the realtime website with which we’re all most familiar is probably Zoom. Another popular one is Discord. In the extreme top right corner is RuneScape The world of RuneScape Welcome to the world of RuneScape - One world, two amazing games! RuneScape is the original game that's been evolving for over 20 years! Old School RuneScape is the game as you remember it from 2007 - improved and expanded! play.runescape.com , a massively multiplayer online 3D video game playable in a browser.

Realtime websites often use persistent bidirectional connections like websockets or WebRTC in addition to the request/response model. The server’s responsibility is mostly to transmit updates between clients and to ensure that its central database remains consistent.

Whereas informational and transactional websites can get by without JavaScript if they really want to, realtime websites don’t have that option: they are client-side apps by necessity, and JavaScript is the only game in town. This is where frontend frameworks shine, and I think even their most hardened critics would acknowledge that it’s a justified use case.

Local Websites

The final quadrant is at the intersection of dynamic and offline: local websites.

Before the Internet, these were just normal apps: programs where all computation happened on your computer, operating on data also stored on your computer. Infeasible before JavaScript became a powerful programming language, local websites are the newest quadrant. These are the true single-page apps: everything happens on one page, because there’s no web server at all.3

A graph with two axes that intersect in the exact center, labeled static/dynamic and online/offline vertically. The logo for Photopea sits at the extreme corner of the dynamic/offline labeled “local”.

Believe it or not, these website are everywhere. Every counter app and todo list made to demo a JavaScript framework is a local website. Although they’re harder to monetize, they share the same advantages that informational apps enjoy: namely, that the lack of outside infrastructure makes them cheaper and easier to maintain.

In the age of software as a service, prominent local websites that aren’t tech demos are harder to find. One fun example is Wordle Wordle - A daily word game Guess the hidden word in 6 tries. A new puzzle is available each day. www.nytimes.com/games/wordle/index.html ! Everything from the gameplay to the word list to the share functionality runs without a server.4 Another is Photopea Photopea | Online Photo Editor Photopea Online Photo Editor lets you edit photos, apply effects, filters, add text, crop or resize pictures. Do Online Photo Editing in your browser for free! www.photopea.com , a Photoshop-esque raster image editor that runs entirely in a web browser.

Local websites are closely related to progressive web apps What are Progressive Web Apps?  |  Articles  |  web.dev An introduction to Progressive Web Apps (PWAs) and the three pillars that separate them from other web apps. web.dev/articles/what-are-pwas — a loose term for websites that can be installed on a device, work offline and integrate more deeply with operating system features. The promise was that these websites would combine the capabilities of native apps with the reach of web apps. In practice, though, the buzz has far outstripped actual adoption, and local websites remain a marginal category compared to the other three.

Declarative Dynamism

From a more traditional point of view, you’d reach for a JavaScript framework to build websites in this area of the chart:

The chart with the dynamic side (the realtime and local quadrants) shaded and labeled “JavaScript framework”.

If you consider yourself a JavaScript developer, the area for which you’d use a JavaScript framework might look more like this:

The chart with all quadrants except the bottom left corner of informational shaded and labeled “JavaScript framework”.

Either way, it’s clear that dynamism — real or perceived — is a driver of JavaScript framework adoption.5 Increasingly, though, we’re seeing people experiment with ways to express more dynamic interactions declaratively in HTML and CSS.

The foremost example here is probably htmx </> htmx - high power tools for html htmx.org , which extends HTML with attributes for controlling network exchanges with a web server. By making it easy to replace smaller regions of a page with new content, htmx allows developers to add more dynamic interactions to their websites without replacing the entire stack.

There’s also precedent for how this hypermedia approach might extend to local interactions. One example is Lea Verou’s Mavo Mavo: A new, approachable way to create Web applications mavo.io , which lets developers use HTML attributes to create reactive single-page web apps. In a similar vein, the Invokers proposal The Invokers Are Coming Yet another game changer that will make building interactive UI on the web oh so much easier. thathtml.blog/2023/11/invokers-are-coming/ — which has been experimentally implemented by all three major browsers — defines a declarative way to trigger events on HTML elements such as <dialog> and <audio>.

Moving even further toward the dynamic side of the chart, an architecture called islands is picking up steam. Coined by Katie Sylor-Miller Katie Sylor-Miller (@[email protected]) 421 Posts, 304 Following, 831 Followers · Frontend Architect @ Etsy, Fairy Gitmother @ ohshitgit.com, Pronouns are she/her. opinions are my own front-end.social/@ksylor and popularized by the Astro web framework Astro Islands Astro Islands (aka Component Islands) are a pattern of web architecture pioneered by Astro. “Islands architecture” was first coined by Etsy's frontend architect Katie Sylor-Miller in 2019, and expanded on by Preact creator Jason Miller. docs.astro.build/en/concepts/islands/ , islands are self-contained dynamic areas within a static HTML document.

The most commonly cited example of islands architecture is probably GitHub, which embeds dynamic widgets such as rich text areas in server-side rendered pages. But the pattern shows up all over the web. The Svelte framework was originally created for building interactive visualizations within New York Times articles. Even the interactive demos on this blog Web Components Will Outlive Your JavaScript Framework | jakelazaroff.com If we're building things that we want to work in five or ten or even 20 years, we need to avoid dependencies and use the web with no layers in between. jakelazaroff.com/words/web-components-will-outlive-your-javascript-framework/ are examples of islands architecture!

One technology driving adoption of the islands architecture is web components, which let people create their own HTML elements. Custom behavior is implemented in JavaScript and controlled using attributes and browser events. That mirrors how built-in HTML elements are implemented with native languages — after all, deep in the belly of the browser, it’s all imperative code.

Web components significantly lower the bar to adding dynamism to HTML without imposing additional architectural constraints. As I wrote in Web Components Eliminate JavaScript Framework Lock-in Web Components Eliminate JavaScript Framework Lock-in | jakelazaroff.com Web components can dramatically loosen the coupling of JavaScript frameworks. To prove it, we're going to do something kinda crazy: build an app where every single component is written in a different JavaScript framework. jakelazaroff.com/words/web-components-eliminate-javascript-framework-lock-in/ , they can act as a glue layer that allows framework code to be embedded without directly using the framework itself — in effect, turning them from competing technologies into complementary ones.

Ironically, one of the most compelling examples of declarative dynamism is a React library: React Three Fiber React Three Fiber Documentation React-three-fiber is a React renderer for three.js docs.pmnd.rs/react-three-fiber/getting-started/introduction , which lets people create 3D scenes by using JSX to control the imperative Three.js Three.js – JavaScript 3D Library threejs.org library. In spirit, React Three Fiber is an example of islands architecture — a <canvas> island rendering 3D visuals within a DOM-based React app. Indeed, we’re starting to see similarly ambitious web components, such as Lea Rosema’s <shader-art> GitHub - shader-art/shader-art: web component that creates a WebGL canvas for running GLSL shaders web component that creates a WebGL canvas for running GLSL shaders - GitHub - shader-art/shader-art: web component that creates a WebGL canvas for running GLSL shaders github.com/shader-art/shader-art .

Async; Await Optional

One common thread in the top right corner of the chart is the replication of existing desktop apps with added multiplayer capabilities.

The most prominent example here is Figma: a vector graphics editor with live collaboration. In contrast to realtime websites, this collaboration is often asynchronous. In fact, the editing itself can happen offline, with changes synced to the server when the user regains their Internet connection.

Such apps are often referred to as local-first software. Coined by Ink & Switch in a paper of the same name Local-first software: You own your data, in spite of the cloud A new generation of collaborative software that allows users to retain ownership of their data. www.inkandswitch.com/local-first/ , local-first describes a set of principles embodying the idea that we — not our software — should own our work. Computation must take place on our own computers, with the network being relegated to an optional syncing service rather than a critical component of the system as a whole.

Through this lens, apps like Figma that depend on a network service for core functionality are not true local-first software. Let’s call apps that follow local-first principles other than data ownership asynchronous — communicating with a server can be deferred, but it must happen at some point. Whether an app is local-first or asynchronous is usually a business decision rather than a technical constraint.

It’s not just highly dynamic websites that can work this way. Linear is a transactional project management app known for its offline sync capabilities Realtime sync and offline - Linear Docs Our application isn't just fast – it works offline from our desktop app, any browser or the mobile web app. linear.app/docs/offline-mode . This introduces tension within the quadrant: transactional websites tend toward coarse-grained updates via network exchanges with a web server, which makes them a good fit for hypermedia rather than imperative implementation. But right now, offline functionality is difficult to introduce even using a JavaScript framework — let alone declaratively in HTML!

Local-first websites are even less common. They’re the most difficult to build, since collaboration features require distributed clients to resolve conflicts with no central server enforcing data integrity. Often, they take the form of creative tools that operate on local files and monetize with subscriptions for multiplayer collaboration. Two examples are Muse Inspired & focused thinking with Muse Muse is a canvas for thinking that helps you get clarity on things that matter. Think in private or collaborate with others. Available for iPad and Mac. museapp.com — created by the same Ink & Switch that coined the local-first moniker — and Excalidraw Excalidraw — Collaborative whiteboarding made easy Excalidraw is a virtual collaborative whiteboard tool that lets you easily sketch diagrams that have a hand-drawn feel to them. excalidraw.com .

People are starting to chip away at the problem space. One particularly promising technology is the Conflict-free Replicated Data Type An Interactive Intro to CRDTs | jakelazaroff.com CRDTs don't have to be all academic papers and math jargon. Learn what CRDTs are and how they work through interactive visualizations and code samples. jakelazaroff.com/words/an-interactive-intro-to-crdts/ , or CRDT: a kind of data structure that can consistently sync edits made by multiple peers with no central server. Many technologies in this area are either based on or inspired by CRDTs, and there’s a burgeoning community Local-First Web Development A fresh way to think about building web applications. localfirstweb.dev/ that has emerged to provide the building blocks for asynchronous and local-first functionality.

These are subcategories I would love to see flourish — especially local-first, which is a fundamentally more empowering paradigm (as opposed to asynchronous, which is merely more convenient). Today, building local-first means leaning heavily on JavaScript frameworks; looking further ahead, we again see hints of how such websites might be built declaratively in Mavo, which can store data locally or in cloud services.

What Next?

Some thoughts about the future:

  • As new W3C standards, web components and libraries like htmx make HTML more powerful, I hope to see more declarative ways to build dynamic interactions without the need to fully buy into a JavaScript framework.
  • The last point notwithstanding, I hope to see more JavaScript usage for functionality that is difficult or impossible to replicate without it, such as robust offline support.
  • There’s no technical reason that most informational and local websites should require an Internet connection; I hope more websites use service workers and that browsers start prioritizing offline use.
  • Local-first software has the potential to give us real data ownership in the age of cloud computing, and I hope we see a lot more movement there.

The website vs. web app dichotomy doesn’t exist. But I don’t think any one way of building websites is going to swallow all the rest. If there’s one takeaway from all this, it’s that the web is a flexible medium where any number of technologies can be combined in all sorts of interesting ways.

Footnotes

  1. From a reader’s point of view, that is. For instance, while reading a blog post on Medium can be done offline, an Internet connection is required to publish it. Many websites actually have multiple use cases which exist in separate places on the chart.

  2. Technology exists to make inroads into solving this problem. Chris Ferdinandi’s article Offline First with Service Workers and Vanilla JS Offline first with service workers and vanilla JS So far this week, we’ve looked at how to write your first service worker, and how to cache pages for offline viewing. Today, we’re going to look at a strategy called “offline-first.” (If you haven’t read the first two articles in this series, you should go do that first or today’s article won’t make much sense.) What is offline-first? Up to this point, we’ve used our service worker cache to serve files if the network can’t be reached (as in, if the user is offline). gomakethings.com/offline-first-with-service-workers-and-vanilla-js/ outlines a strategy for building more offline-friendly informational websites.

  3. I mean, sure: technically there’s a web server to serve the static files. But once you have those, there’s no additional infrastructure needed to run the app.

  4. Or at least it did, before the New York Times bought it; I’m not sure how much of it requires an account now.

  5. A looser definition of “dynamism” might include server-side changes as well, which is why for some people JavaScript frameworks annex the transactional app quadrant.