The Shallow Router: How we made Luma navigation instant
Extending the browser history API to build a zero-latency navigation system that saves money and feels native.

Luma uses the search bar for navigation in a way that is quite distinct from most web apps. We don't rely on complex internal state to track where you are. Instead, the URL itself is the source of truth. Everything is right there for the user to see.
This approach gives Luma massive benefits right out of the box:
- Persistence: When you reload the browser, the location bar stays the same, so you never lose your place.
- Navigation: The browser's native Forward and Back buttons work perfectly without us needing to write a single line of custom history management code.
We don't even need an internal listener to update our state for these actions; the browser does it for us.
The Problem with Standard Routing
However, we ran into a significant hurdle with the standard Next.js router.
By default, when we pushed a new route to the history (like when you click to open a folder), the router would attempt to fetch the page data from the server. While this is great for traditional websites, it was a disaster for a file explorer.
It meant that every time a user navigated to a new folder, we were making a round-trip to the server. This introduced perceptible latency and, more importantly, significantly increased our edge request costs.
We needed a way to use the browser's search bar as our state manager without fetching pages. We needed a router that behaved like a real router, but was actually a "fake" one.
Enter The Shallow Router
Our solution was to build The Shallow Router.
The goal was simple: update the URL and manage history without triggering a server request, while still allowing our React components to react to changes instantly.
Overriding the Browser History
To achieve this, we had to get a little creative with the native window object.
The standard browser methods window.history.pushState and window.history.replaceState update the URL, but they have a limitation: they do not dispatch events. This means our app wouldn't know when the URL had changed unless we polled for it.
So, we wrote a patch to override these native methods.
We wrapped the original history functions so that every time pushState or replaceState is called, we manually dispatch a custom event. This allows us to "listen" to URL changes that normally pass silently.
The "Fake" Router
With the events in place, we built a custom router object that mimics the look and feel of the Next.js router.
We created a hook—similar to a global store—that subscribes to specific query parameters. Because we are controlling the events, we can ensure this subscription is extremely efficient, triggering re-renders only when absolutely necessary.
The Result: Native Speed
This architecture turned out to be one of the best design decisions in Luma.
The app is now super fast. After the initial load, navigation generates zero network requests. It works just like a native OS-level file explorer, but it retains all the powerful navigation capabilities of a modern web browser.
By building the Shallow Router, we achieved the best of both worlds: the persistence and navigability of the web, with the instant, snap-to-response feel of a native application.