Why htmxr?

htmxr does not replace Shiny — it answers different questions.


Shiny: the reference

Before explaining what htmxr is, it is worth appreciating what Shiny achieved.

Shiny democratized web application development for R users. It handles the browser-to-R communication invisibly, so data scientists can focus entirely on their analysis rather than web infrastructure. What Shiny does remarkably well:

Shiny is the right tool for rich analytical dashboards, scientific interfaces, and internal data exploration tools.


Different problems, different trade-offs

Shiny and htmxr are built on fundamentally different communication models:

Shiny htmxr
Communication WebSocket (persistent connection) HTTP (request/response)
Paradigm Reactive graph Explicit HTTP requests
UI updates Shiny decides what to reload You target the DOM precisely
State R session per user Database or URL
Backend R only Any HTTP server

The practical difference: in Shiny, your server reacts. In htmxr, your browser asks.

Shiny maintains one R session per connected user. That session holds all the reactive state — inputs, outputs, intermediate computations — and Shiny decides when to re-evaluate which outputs. This model is powerful and ergonomic, but it means each user consumes a persistent R process.

htmxr apps are largely stateless. Each HTTP request is independent. The server computes something, returns an HTML fragment, and forgets. State lives in the database, the URL, or the client — not in a long-lived R session.


Why choose htmxr?

Surgical DOM updates

Shiny reloads entire output blocks (uiOutput, renderUI) — sometimes more than strictly necessary. htmx updates exactly the targeted element, nothing more. The result is smoother interfaces, less visual flicker, and a faster perceived experience.

Try the infinite scroll example to see this in practice — 53,940 diamonds loaded progressively, with only the next batch of cards appended to the DOM on each scroll event:

hx_run_example("infinity-scroll")

Scalability and infrastructure cost

Shiny’s persistent session model means memory consumption scales linearly with the number of connected users. A pool of shared plumber2 workers handles far more concurrent users on the same hardware.

Deployment is standard: nginx, Docker, any VPS, any cloud platform. No Shiny Server license required.

Native HTTP: cache, load balancers, SEO

htmxr responses are plain HTML. This means:

Progressive enhancement

An htmxr app can work even when JavaScript is disabled — links and forms remain functional. You can enrich a static HTML page progressively, or add dynamic behaviour to an existing app without rewriting it from scratch.

Interoperability

htmxr generates standard HTML backed by a standard HTTP API. The same plumber2 endpoints that serve your htmxr frontend can be consumed by mobile apps, other services, or scripts in any language — without translation or adaptation.

This is particularly valuable when a proof-of-concept built in R needs to grow into a production system: the business logic stays in R, while other parts of the stack can call the same endpoints.


When to use each

Choose htmxr when:

Choose Shiny when:


Summary

htmxr is not a Shiny replacement. It is a different tool for different problems. If you need reactive, session-based dashboards in R, Shiny is the right choice. If you need scalable, HTTP-native apps that interoperate beyond R, htmxr is the answer.

mirror server hosted at Truenetwork, Russian Federation.