You've got a back-end that works. Routing, auth, the ORM, and forms nobody wants to touch. And one screen that needs to feel like an app: instant filtering, drag-to-reorder, validation as you type. The two usual answers both cost more than that screen is worth. Rewrite the front-end in React and the back-end becomes an API, months of work before a single pixel ships. Or bolt jQuery onto the templates you have, and watch that screen rot into the part of the codebase nobody owns.

There's a third answer, and Airbnb already tried it. In 2016, faced with a Rails app too big to rewrite, they built Hypernova: a second, tiny process that turned a component name and some data into HTML, on request, from inside the same page Rails was already rendering. I used it on my first client project at madewithlove, and understood exactly why it worked. Airbnb archived it in 2023, once they no longer needed it. Most teams still do.

I went back to it this month to see if the idea holds on a back-end Hypernova was never built for. It does. Rebuilding it meant pointing Claude at Hypernova's own source first, then at how Astro solves the same problem today. That's where nanostores came from: a way for two islands to share a state that Hypernova never needed, because it never had two islands talking to each other. The parts that mattered most only showed up once we stopped reading and started testing in a browser: state leaking between users because a store lived at the module level instead of per request, hydration breaking on state that changed in the gap between render and hydration, and prefetching that served one visitor's page to the next.

A pure function over the network

Call it a render sidecar: a small Node process next to your real back-end that does one thing. Give it a component name and props, and get back HTML. It doesn't know your database, your users, or a single URL, because nothing calls it except your back-end, over a socket the internet never sees.

One line in a Django template marks a region for it:

{% component "SearchBox" filters=filters results_count=results.count %}

Nothing renders yet. It's a placeholder, collected with every other one on the page, sent to the sidecar as a single batch once the page is otherwise built, and swapped back in as HTML before it ships. React rendered the page once, on the server, then got out of the way. Nothing about that line requires the component to be interactive, either: a badge, a table row, a card can be written in React too, rendered once, never touched again. The back-end isn't gaining one clever widget. It's gaining React's component model for the whole page.

One failure, one widget

Hypernova's best idea: a failure belongs to the component, not the page. If the sidecar times out on one widget, that placeholder ships empty and renders client-side instead. Everything Django built directly ships exactly as intended. A page built from 600 components renders in about 2 milliseconds. Whatever's slow on your page, it's rarely this.

Interactive where it needs to be

A search box that filters as you type has to run in the browser. These regions, Astro's word for them, are islands: pockets of interactivity in otherwise static HTML. An island's props travel with it as JSON; in the browser, React hydrates rather than redraws, attaching behaviour to markup that's already there. Everything that was never interactive ships zero JavaScript.

Two islands on the same page can't share React state directly so state that has to travel between them (a filter changing what a counter shows elsewhere) lives in a small atom outside React (nanostores), seeded from the page's own data. Anything a user might want to bookmark or share skips nanostores entirely and lives in the URL itself, still the simplest state manager there is. And once an island is alive, it talks to your back-end directly, through the same server actions Next.js made popular, rebuilt to work without it.

What it costs

Auth, permissions, the ORM, the admin panel: none of it gets rebuilt or duplicated. You add one island to one page and decide later how far this goes, not up front. And the page a user gets is real HTML the first time, no blank div waiting on a bundle.

None of that is free. A second process for deployment and monitoring. One-batch rendering means the page waits for its slowest component, rather than streaming the fast parts first. Every island ships its own JavaScript, and Django's templates and React's components are two languages living on one page that your team has to actually understand. If most of your pages are already app-like, or your team is already mostly JavaScript, skip this and start with Next.js or Astro. This earns its place in one situation: a back-end you like, and a few screens that need to be more than a form post.

The idea outlived the tool

Airbnb didn't retire Hypernova because it was wrong. They retired it because they'd finished the migration it existed for. Most teams haven't. The idea of a decade-old, archived project got right is still the one worth having: you're not rewriting your back-end. You're making one screen better without risking the rest of the app.