I built a time-travel debugger for Zustand — and it caught three bugs I'd already shipped
If you use Zustand, you've had this moment: the UI is wrong, you know a store changed when it shouldn't have, and now you're scattering console.log calls and refreshing, trying to catch the one action that did it. State debugging is detective work — and Zustand, by design, is so minimal that it doesn't give you much to work with. I wanted to see it instead. So I built Zustand DevTools: a Chrome DevTools panel that records every state change in your app and lets you walk back through them. The problem Zustand's whole appeal is that it's tiny and unopinionated — no boilerplate, no context wrappers, no ceremony. The flip side is there's no built-in answer to "what changed, when, and because of which action?" The Redux DevTools middleware exists, but it's Redux-shaped: action-centric, and awkward the moment you have several small stores instead of one big one. What I actually wanted while debugging was boring and specific: a live view of each store's current state, a timeline of every change, labelled with the action name, the exact path that changed (items[1].quantity: 1 → 2), not a whole-object diff I have to eyeball, and the ability to jump back to any point and look around. What it does Two parts. Stores + Timeline (free). Open DevTools, click the Zustand tab, and every registered store shows up live. Every set() becomes a timeline entry with the action name and a path-level diff: [cart] addItem items[1].quantity: 1 → 2 total: 168 → 297 Click any entry to time-travel to that moment — safely, by ID, rather than by replaying a fragile sequence of actions. Trace Sessions (Pro). Record while you reproduce a bug, then inspect the recording: path-level diffs, the likely call-site of each change, compare any two entries, and export a redacted session a teammate can import and inspect view-only. That export is the part I use most. "Here's the recording — drag the playhead to step 4 and you'll see where the total goes wrong" beats a paragraph of Slack every single time. How you wire it up One wrapper per store you want to inspect: import { create } from 'zustand'; import { withDevtoolsBridge } from 'zustand-devtools-bridge'; const useCartStore = create( withDevtoolsBridge( (set) => ({ items: [], addItem: (item) => set((s) => ({ items: [...s.items, item] }), false, 'addItem'), // named in the log }), { name: 'cart' } ) ); Register a store once with a stable name and you get an accurate live view of it from then on. (There's also a zero-setup experimental view that reads hooks directly for a quick look — it's clearly labelled, because it can't always tell Zustand state apart from other hooks.) Two design decisions I care about: It chains the DevTools hook instead of clobbering it. The real React DevTools keeps working right next to it, whichever loads first. A debugging tool that breaks your other debugging tools is worse than nothing. State never leaves your machine. Data flows from the inspected page to your panel and nowhere else — no server, no analytics, no telemetry. Your app state is often the most sensitive thing on the page; it shouldn't phone home just so you can look at it. The honest part I build software by directing AI coding agents, and I don't trust their output by default. The architecture, the naming, the test strategy and the review are mine. There are 96 automated tests across two major framework versions, because a state tool that's subtly wrong is actively dangerous — you'd end up debugging the debugger. And to be straight: after I'd "finished," I did a dedicated review pass over my own code and found three silent failures a green test suite had missed. I fixed them and kept the diffs. If a tool for catching bugs can't survive its own author looking hard at it, it hasn't earned your trust. Try it Free: install the Stores + Timeline tools from the Chrome Web Store, add zustand-devtools-bridge to your app, and wrap a store. Pro: unlimited Trace Sessions for a €9.99 one-time purchase — three full previews free, no subscription, up to 5 devices, 30-day refund. 👉 Try it: https://kubaopoczka.github.io/zustand-devtools-site/ If you use Zustand and React, I'd genuinely like to know where it falls short — what you tried to inspect that it couldn't show you. That's the feedback that makes it better. P.S. — I'm new here: this is my first dev.to post, and honestly still finding my feet sharing work out loud like this. If you've got tips for a newcomer (or thoughts on the tool itself), I'd genuinely love to hear them. 🙏
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to