Why the results appear before the spinner would: how a tracker feels instant
The trick to a fast issue tracker is not a faster server. It is keeping the working set in the client so filtering, sorting, and editing happen locally, and the network catches up in the background. Here is the architecture, and where the honest limits are.
There is a specific feeling you get from a fast tool: you type a filter, and the list is already right. You change a status, and it moves before you have finished letting go of the mouse. There was no spinner, because there was no moment to put one. The work happened where you were looking, and the network sorted itself out afterward.
That feeling is not a faster server. You cannot buy it with a bigger box, and you cannot A/B your way to it after the fact. It comes from one architectural decision made early: keep the working set close to the user, so the common actions do not wait on a round trip to feel done. This post is about how that works, and, just as importantly, where the honest limits are.
#The default architecture makes you wait
Most web apps are built the obvious way. The source of truth lives on a server. The client is a thin renderer. Every meaningful action, filtering a list, editing a field, reordering a board, is a request: send it, wait, receive, re-render. Even when each request is fast, you are paying network latency on every interaction, all day.
We wrote about the extreme version of this in why Jira is so slow: a single ticket that fans out into a cascade of round trips before the page is usable. But you do not need 200 requests to feel the tax. One request per keystroke of filtering is enough. The problem is not the number, it is the shape: the client asks, the server answers, and you wait in between. As long as the data you are working with lives only on the server, the floor on "how fast can this feel" is set by the network, not by your code.
#Keep the working set in the client
The fix is to stop treating the client as a thin renderer and start treating it as the place the working set lives.
When you open a Radial workspace, the issues you are looking at are loaded into a normalized in-memory store on the client (we use zustand; the pattern matters more than the library). From that point on, the interactions that used to be requests become local computations:
- Filtering and sorting run as a predicate over the loaded slice. Narrowing by assignee, priority, or label does not call the server; it re-evaluates a function over data already in memory. That is why the list is right the instant you type.
- Editing is optimistic. When you change a status, the store updates first and the UI reflects it immediately. The write to the database happens in the background, under row-level security. If it fails, the change rolls back and you get a toast. The common case, which is that it succeeds, never made you wait.
- Realtime keeps the working set honest. When a teammate (or a teammate's agent) changes something, the update arrives over a realtime channel and reconciles into the same store, with the app's own echoes suppressed so your optimistic edit does not fight the confirmation of itself.
The through-line: the network is still there, but it moved off the critical path. You act on local state; the server catches up. The spinner has nowhere to live because the moment it would have filled is already over.
#Where this is honest, and where it is not
It is easy to oversell this, so here is the line we hold.
Radial is not local-first software in the Ink & Switch sense: it is not offline-first, it does not use CRDTs, and your data is not primarily on your disk. It is a hosted, multi-tenant app backed by Postgres. What we do is narrower and more mundane: we keep the working set in the client and make the common actions optimistic, so the tool feels instant even though the source of truth is a server you are talking to.
Two consequences follow, and we would rather name them than imply they do not exist:
- Global search is a server call, not a local scan. Typing into the ⌘K palette to find any issue in the workspace hits a database function, because the full corpus is not all in the client. It is fast, but it is a network request, not a local filter. The instant part is filtering and editing the slice you already have loaded, not searching everything you have never opened.
- Staying small is what keeps it fast. This only works because the working set is small enough to live in the client. Radial is deliberately one thing, an issue tracker, with no 50-field forms and no dashboard suite fanning out behind every page. Speed here is a position you hold by saying no, the same discipline behind boring on purpose. Bolt on an everything-app and the working set stops fitting, and the trick stops working.
We also do not publish a latency figure as a measured benchmark, because the only honest claim is the design goal, not a marketing number. The goal is simply that the tool gets out of the way.
#The same idea, from the terminal
The instant-feel is a property of the architecture, not of the web UI specifically, which is why the command line gets the same benefit. The CLI talks to the same fast surface, and every command takes --json, so you can pipe the working set straight into whatever you are already scripting:
radial list -a me --status "in progress" --jsonThat returns your in-progress issues as structured JSON in one call, no page to render, no spinner to watch. Your agent gets the same thing over MCP at mcp.radial.build, and the REST API at api.radial.build is plain JSON, not a GraphQL SDK you have to learn. The point is consistent across every surface: the tool should not make you wait, whether you are looking at a board, typing in a terminal, or driving it with an agent.
#FAQ
#What is local-first software?
Local-first software, as defined by Ink & Switch, is a set of principles where the primary copy of your data lives on your own device rather than a remote server, so the app works offline, stays fast, and keeps you in control of your data even without the cloud. It usually relies on conflict-free replicated data types (CRDTs) to merge changes across devices. Radial is not local-first in this strict sense: it is a hosted app that keeps your active working set in the client for speed, which is a different and narrower technique.
#Does Radial work offline?
No. Radial keeps the issues you are working with in a client-side store so filtering and editing feel instant, but the source of truth is a hosted Postgres database and it needs a connection to sync. It is fast because the working set is local, not because it is offline-capable. If you need a fully offline, on-your-disk tracker, a true local-first or file-based tool is a better fit.
#Why does filtering feel instant but search does not?
Because they work on different data. Filtering and sorting run over the slice of issues already loaded into the client, so they are local computations with no network in the loop. Global search across the whole workspace has to reach issues that are not loaded, so it calls a database function. One is a local predicate; the other is a fast server request. We would rather be precise about that than pretend everything is local.
#How does optimistic editing avoid losing my changes?
Every optimistic mutation snapshots the previous state before applying the change to the client store. The database write then happens in the background under row-level security. If the write fails, the change rolls back to the snapshot and you get a toast, so you always know when something did not stick. Realtime updates from other users reconcile into the same store, with the app's own echoes suppressed so your edit is not double-applied.
#Is a faster tracker actually worth switching for?
If your team touches issues dozens of times a day, the per-interaction wait is a focus tax you pay every day. The value is not a benchmark number; it is that the tool stops interrupting you. A tracker you forget you are using, because it never makes you wait, is the goal.
#The short version
A tool feels instant when the working set lives in the client: filtering and sorting become local computations, editing is optimistic, and the network catches up in the background instead of blocking each action. That is the architecture behind Radial. It is not local-first software, and global search is still a server call, but the common actions do not wait, and that is where the feeling comes from.
See the one flat price on pricing, or wire the same fast surface into your terminal and your agent at /developers.
The team behind Radial, the fast, CLI-first issue tracker that lets your own agents work for free. We write about plain software, speed as respect, and bringing your own agent.
Track issues like it’s 2019. Ship like it’s 2026.
An issue tracker. That’s it. Your agents ride free.
Keep reading
GitHub stores the code, not the decision. Where the "why" should actually live.
An architecture decision record captures one significant technical choice: its context, the decision, and the consequences. Here is what an ADR is, when to write one, and why the decisions that matter most are the ones that never reach a doc/adr folder.
You don't want a git issue tracker. You want issues that live next to your code.
Devs keep reinventing the git-native issue tracker: a .issues folder of Markdown committed to the repo. The instinct is right. Here is the fast, scriptable version that links branches, PRs, and commits to issues without asking you to hand-roll it.
The agile project management tool that is just a fast issue tracker
Most agile project management tools are everything-suites with a board bolted on. Here is the case for the smaller thing: a fast, scriptable issue tracker with real sprints, and nothing you have to grow into.