<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohammad Rehan</title>
    <description>The latest articles on DEV Community by Mohammad Rehan (@mdrehan991).</description>
    <link>https://dev.to/mdrehan991</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4095730%2F15731a77-47d0-4811-a20b-e94446065c9e.png</url>
      <title>DEV Community: Mohammad Rehan</title>
      <link>https://dev.to/mdrehan991</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mdrehan991"/>
    <language>en</language>
    <item>
      <title>Using AI Coding Agents on Production Code: What Actually Changes</title>
      <dc:creator>Mohammad Rehan</dc:creator>
      <pubDate>Mon, 31 Aug 2026 16:40:29 +0000</pubDate>
      <link>https://dev.to/mdrehan991/using-ai-coding-agents-on-production-code-what-actually-changes-5f2c</link>
      <guid>https://dev.to/mdrehan991/using-ai-coding-agents-on-production-code-what-actually-changes-5f2c</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fys9fmizyyd8dl5zyez4e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fys9fmizyyd8dl5zyez4e.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first experience with AI in the IDE was simple autocomplete.&lt;/p&gt;

&lt;p&gt;You type a function name, wait for the gray ghost text to appear, press &lt;code&gt;Tab&lt;/code&gt;, and move on.&lt;/p&gt;

&lt;p&gt;It was useful for utility functions, regex patterns, boilerplate, and repetitive code.&lt;/p&gt;

&lt;p&gt;Then AI coding agents arrived.&lt;/p&gt;

&lt;p&gt;Instead of operating inside a single file and predicting the next few lines, modern agents can work across a repository. They can inspect multiple files, trace dependencies, plan changes, edit code, run terminal commands, read build errors, and iterate on their implementation.&lt;/p&gt;

&lt;p&gt;When I stopped treating AI as an autocomplete tool and started giving it real repository-level tasks on production code, my workflow changed significantly.&lt;/p&gt;

&lt;p&gt;The interesting part isn't that AI can write code faster.&lt;/p&gt;

&lt;p&gt;It's &lt;strong&gt;what happens to the developer's role when implementation becomes much cheaper.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What Changed in My Workflow
&lt;/h2&gt;

&lt;p&gt;The mental shift is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;You stop being primarily a typist and start acting more like a Tech Lead directing a very fast junior engineer.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The traditional workflow looks something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read Task
   ↓
Find Relevant Files
   ↓
Design Solution
   ↓
Write Code
   ↓
Test
   ↓
Debug
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With an AI coding agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Define Context &amp;amp; Constraints
           ↓
      Direct Agent
           ↓
      Multi-File Work
           ↓
    Verify &amp;amp; Iterate
           ↓
      Review Diff
           ↓
   Validate in Runtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm still responsible for the solution.&lt;/p&gt;

&lt;p&gt;But I spend less time typing repetitive code and more time thinking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture&lt;/li&gt;
&lt;li&gt;Data flow&lt;/li&gt;
&lt;li&gt;Constraints&lt;/li&gt;
&lt;li&gt;Edge cases&lt;/li&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;li&gt;Runtime behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's probably the biggest change I've noticed.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Where AI Agents Actually Save Time
&lt;/h1&gt;

&lt;p&gt;There are three areas where I've found them particularly useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cross-File Refactoring
&lt;/h2&gt;

&lt;p&gt;A seemingly small change can easily span multiple layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API Service
    ↓
Transformation
    ↓
Custom Hook
    ↓
Component
    ↓
Tests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An agent can trace those relationships and make coordinated changes much faster than manually searching through every file.&lt;/p&gt;

&lt;p&gt;For example, instead of spending time finding every reference to a renamed property, I can ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Trace all consumers of this property, update the implementation consistently, and don't change the public API."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The important part is the constraint.&lt;/p&gt;

&lt;p&gt;Without constraints, the agent may solve the problem correctly while also changing things you didn't ask it to change.&lt;/p&gt;




&lt;h2&gt;
  
  
  Debugging and Flow Tracing
&lt;/h2&gt;

&lt;p&gt;Some of the hardest bugs aren't caused by complicated code.&lt;/p&gt;

&lt;p&gt;They're caused by several simple pieces interacting in unexpected ways.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Auth Event
    ↓
Token Refresh
    ↓
Background Operation
    ↓
State Update
    ↓
UI Update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of immediately asking an agent to fix the bug, I often ask it to investigate first:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Trace what happens if &lt;code&gt;refreshAuth()&lt;/code&gt; resolves while &lt;code&gt;fetchNextPage()&lt;/code&gt; is still running. Don't modify the code yet. Identify possible race conditions and lifecycle issues."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That makes the agent useful as a &lt;strong&gt;codebase exploration tool&lt;/strong&gt;, not just a code generator.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test Generation
&lt;/h2&gt;

&lt;p&gt;AI is also very good at generating the first version of repetitive tests.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empty responses&lt;/li&gt;
&lt;li&gt;Missing fields&lt;/li&gt;
&lt;li&gt;Network failures&lt;/li&gt;
&lt;li&gt;Retry behavior&lt;/li&gt;
&lt;li&gt;Boundary conditions&lt;/li&gt;
&lt;li&gt;Rapid unmounts&lt;/li&gt;
&lt;li&gt;Cleanup behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But generated tests still need review.&lt;/p&gt;

&lt;p&gt;A passing test doesn't necessarily mean the right behavior is being tested.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. A Real-World Example
&lt;/h1&gt;

&lt;p&gt;One example from my own workflow was a performance issue in a React Native Android TV application.&lt;/p&gt;

&lt;p&gt;The Home screen contained multiple horizontal content rails. During a background refresh, fresh data had to be merged into the existing UI without unnecessarily rebuilding everything.&lt;/p&gt;

&lt;p&gt;Instead of asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Fix the performance issue."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I asked the agent to first trace the data flow and identify where new object and array references were being created.&lt;/p&gt;

&lt;p&gt;The agent found that the merge path was recreating more of the data structure than necessary.&lt;/p&gt;

&lt;p&gt;The eventual approach was simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update only the rails whose data changed and preserve references for unchanged data.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That part worked well.&lt;/p&gt;

&lt;p&gt;But during the refactor, the agent also changed the keys used by some list items.&lt;/p&gt;

&lt;p&gt;The code was valid.&lt;/p&gt;

&lt;p&gt;The tests passed.&lt;/p&gt;

&lt;p&gt;But on Android TV, the change affected focus behavior because some items were being treated as new components.&lt;/p&gt;

&lt;p&gt;This is the kind of problem that illustrates the current boundary of AI coding agents.&lt;/p&gt;

&lt;p&gt;The agent was good at understanding the &lt;strong&gt;data transformation problem&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It wasn't automatically aware that &lt;strong&gt;component identity was also important to the platform's focus behavior&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A developer familiar with the application and runtime had to catch that.&lt;/p&gt;

&lt;p&gt;And that's an important lesson:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;AI can understand the code without fully understanding the system.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  4. Where AI Agents Fail
&lt;/h1&gt;

&lt;p&gt;Once you use agents on production code, their blind spots become pretty obvious.&lt;/p&gt;

&lt;h2&gt;
  
  
  Over-Engineering
&lt;/h2&gt;

&lt;p&gt;Ask an agent to create a small caching helper and you might get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CacheManager
    ↓
CacheRepository
    ↓
CacheFactory
    ↓
CacheStrategy
    ↓
CacheProvider
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When all you needed was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;getCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;setCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AI tends to generalize.&lt;/p&gt;

&lt;p&gt;Production code often benefits from being boring.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If the problem is simple, the solution should probably be simple too.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Framework-Specific Behavior
&lt;/h2&gt;

&lt;p&gt;AI is very good at common React and JavaScript patterns.&lt;/p&gt;

&lt;p&gt;But production applications often depend on platform-specific behavior.&lt;/p&gt;

&lt;p&gt;In an Android TV application, for example, you may need to reason about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spatial focus navigation&lt;/li&gt;
&lt;li&gt;List virtualization&lt;/li&gt;
&lt;li&gt;Component identity&lt;/li&gt;
&lt;li&gt;JavaScript runtime behavior&lt;/li&gt;
&lt;li&gt;Native bridge costs&lt;/li&gt;
&lt;li&gt;Animation workloads&lt;/li&gt;
&lt;li&gt;Device-specific memory constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generated code can be valid React Native code and still be the wrong solution for the platform.&lt;/p&gt;




&lt;h2&gt;
  
  
  Runtime Performance
&lt;/h2&gt;

&lt;p&gt;AI often optimizes for code that looks clean and idiomatic.&lt;/p&gt;

&lt;p&gt;But performance is contextual.&lt;/p&gt;

&lt;p&gt;For example, multiple array operations aren't automatically bad. The problem is unnecessary allocations when that work happens repeatedly in a performance-critical path.&lt;/p&gt;

&lt;p&gt;A cleaner-looking implementation isn't necessarily a faster one.&lt;/p&gt;

&lt;p&gt;That's why:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Performance should be measured, not assumed.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Native Code and Build Systems
&lt;/h2&gt;

&lt;p&gt;I am particularly cautious when agents modify native code or build configuration.&lt;/p&gt;

&lt;p&gt;Gradle, Kotlin, C++, native modules, SDK versions, and generated code can all interact in ways that aren't obvious from a single file.&lt;/p&gt;

&lt;p&gt;An agent can produce a configuration that looks completely reasonable and still fail because of an environment-level dependency or version mismatch.&lt;/p&gt;

&lt;p&gt;The terminal output is often more useful than the generated code itself.&lt;/p&gt;




&lt;h2&gt;
  
  
  Hidden Architectural Rules
&lt;/h2&gt;

&lt;p&gt;Every mature codebase has rules that aren't necessarily written down.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This state must never be read synchronously during startup."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This component must preserve its identity because focus state depends on it."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Don't introduce another caching layer here."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These rules often live in team knowledge rather than documentation.&lt;/p&gt;

&lt;p&gt;An AI agent can't reliably follow constraints it doesn't know exist.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. How I Use AI Agents Safely
&lt;/h1&gt;

&lt;p&gt;My workflow is fairly simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Context
   ↓
Constraints
   ↓
Small Task
   ↓
Verification
   ↓
Diff Review
   ↓
Runtime Validation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Give it context
&lt;/h3&gt;

&lt;p&gt;Don't immediately ask it to implement the feature.&lt;/p&gt;

&lt;p&gt;First ask it to understand the existing implementation and identify the relevant files.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Set constraints
&lt;/h3&gt;

&lt;p&gt;I explicitly state things like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't add dependencies.&lt;/p&gt;

&lt;p&gt;Don't change the public API.&lt;/p&gt;

&lt;p&gt;Follow the existing architecture.&lt;/p&gt;

&lt;p&gt;Don't modify files outside the requested scope.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Constraints are often more valuable than a longer description of the desired implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Keep tasks small
&lt;/h3&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Implement the entire caching architecture."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Break it down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Analyze the current data flow.
2. Implement the storage utility.
3. Add tests.
4. Integrate it into the existing hook.
5. Validate the behavior.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Small tasks make incorrect assumptions easier to catch.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Let the agent verify its work
&lt;/h3&gt;

&lt;p&gt;If the project has automated checks, let the agent run them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run lint
npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The useful loop is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Implement
   ↓
Run
   ↓
Fail
   ↓
Inspect
   ↓
Fix
   ↓
Run Again
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Review the diff
&lt;/h3&gt;

&lt;p&gt;This is the part I don't skip.&lt;/p&gt;

&lt;p&gt;I review AI-generated changes almost like code from another engineer.&lt;/p&gt;

&lt;p&gt;I ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why did this file change?&lt;/li&gt;
&lt;li&gt;Why was this abstraction introduced?&lt;/li&gt;
&lt;li&gt;Did behavior change outside the requirement?&lt;/li&gt;
&lt;li&gt;Were dependencies added?&lt;/li&gt;
&lt;li&gt;Were new allocations introduced?&lt;/li&gt;
&lt;li&gt;Are timers and listeners cleaned up?&lt;/li&gt;
&lt;li&gt;Did component identity change?&lt;/li&gt;
&lt;li&gt;Was existing state accidentally mutated?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The question isn't only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Does this work?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Why did the agent make these decisions?"&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  6. Validate on real hardware
&lt;/h3&gt;

&lt;p&gt;For applications where runtime behavior matters, tests aren't enough.&lt;/p&gt;

&lt;p&gt;A React Native Android TV application can pass its tests and still:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Drop frames&lt;/li&gt;
&lt;li&gt;Consume too much memory&lt;/li&gt;
&lt;li&gt;Lose focus&lt;/li&gt;
&lt;li&gt;Freeze under load&lt;/li&gt;
&lt;li&gt;Behave differently on low-end hardware&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the final verification loop needs to include the real environment.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. What Developers Need to Get Better At
&lt;/h1&gt;

&lt;p&gt;As AI handles more of the mechanical implementation work, I think several engineering skills become more important.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&gt;

&lt;p&gt;Knowing where code belongs and how systems should interact.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constraints
&lt;/h3&gt;

&lt;p&gt;Being able to define requirements, boundaries, and invariants precisely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging
&lt;/h3&gt;

&lt;p&gt;Understanding why something happens rather than simply changing code until the symptom disappears.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Knowing how to measure memory, CPU, rendering, and runtime behavior.&lt;/p&gt;

&lt;h3&gt;
  
  
  Platform Knowledge
&lt;/h3&gt;

&lt;p&gt;Understanding what happens beneath the framework.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Review
&lt;/h3&gt;

&lt;p&gt;Being able to recognize subtle problems in code you didn't personally write.&lt;/p&gt;

&lt;p&gt;That last one may become especially important.&lt;/p&gt;

&lt;p&gt;If an AI agent can generate hundreds of lines of code in seconds, the ability to &lt;strong&gt;evaluate those lines correctly&lt;/strong&gt; becomes more valuable—not less.&lt;/p&gt;




&lt;h1&gt;
  
  
  7. The New Engineering Loop
&lt;/h1&gt;

&lt;p&gt;I don't think the future looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Human → AI → Code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I think it's closer to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Human defines the problem
          ↓
AI investigates
          ↓
Human validates the approach
          ↓
AI implements
          ↓
AI verifies
          ↓
Human reviews
          ↓
Real-world validation
          ↓
Ship
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The human remains responsible for the outcome.&lt;/p&gt;

&lt;p&gt;The AI accelerates the execution.&lt;/p&gt;

&lt;p&gt;That's a much more useful mental model than:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"AI replaces developers."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;After using AI coding agents on production code, my biggest takeaway isn't that AI writes code faster.&lt;/p&gt;

&lt;p&gt;That's already obvious.&lt;/p&gt;

&lt;p&gt;The more interesting change is that &lt;strong&gt;the bottleneck moves&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Previously, a significant amount of engineering time was spent translating a known solution into code.&lt;/p&gt;

&lt;p&gt;AI can now handle much more of that translation.&lt;/p&gt;

&lt;p&gt;The difficult questions become:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What should we build?&lt;/li&gt;
&lt;li&gt;Where should it live?&lt;/li&gt;
&lt;li&gt;What constraints matter?&lt;/li&gt;
&lt;li&gt;What can break?&lt;/li&gt;
&lt;li&gt;What are the performance implications?&lt;/li&gt;
&lt;li&gt;How do we know the solution is actually correct?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AI coding agents are incredibly useful when you treat them as &lt;strong&gt;implementation and investigation partners&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;They're dangerous when you treat them as autonomous engineers whose decisions don't need review.&lt;/p&gt;

&lt;p&gt;The workflow that works best for me is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Give AI enough context to understand the problem, enough constraints to avoid unnecessary decisions, enough tooling to verify its work, and enough human oversight to catch what it can't see.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The better AI becomes at writing code, the more valuable good engineering judgment becomes.&lt;/p&gt;

&lt;p&gt;And that's probably the biggest change AI coding agents have brought to my workflow.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>reactnative</category>
      <category>agents</category>
    </item>
    <item>
      <title>Supercharging MMKV Debugging in React Native: Bringing Full State Inspection and Diffs to Reactotron</title>
      <dc:creator>Mohammad Rehan</dc:creator>
      <pubDate>Wed, 26 Aug 2026 12:13:33 +0000</pubDate>
      <link>https://dev.to/mdrehan991/supercharging-mmkv-debugging-in-react-native-bringing-full-state-inspection-and-diffs-to-reactotron-3l65</link>
      <guid>https://dev.to/mdrehan991/supercharging-mmkv-debugging-in-react-native-bringing-full-state-inspection-and-diffs-to-reactotron-3l65</guid>
      <description>&lt;p&gt;&lt;em&gt;How we connected MMKV to Reactotron using JavaScript Proxies, operation interception, and state-merging pipelines—without giving up MMKV’s performance.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1ef5mbhvx484dxlseeaa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1ef5mbhvx484dxlseeaa.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem: MMKV Made Our App Faster, but Debugging Harder
&lt;/h2&gt;

&lt;p&gt;At some point, many React Native applications outgrow the convenience of &lt;code&gt;AsyncStorage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As the application grows, persistent storage becomes part of almost every important flow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authentication tokens&lt;/li&gt;
&lt;li&gt;User preferences&lt;/li&gt;
&lt;li&gt;Cached API responses&lt;/li&gt;
&lt;li&gt;Feature flags&lt;/li&gt;
&lt;li&gt;Session information&lt;/li&gt;
&lt;li&gt;Offline data&lt;/li&gt;
&lt;li&gt;Application configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We were using &lt;code&gt;AsyncStorage&lt;/code&gt;, but as our application became more performance-sensitive, especially on low-end Android TV devices, we wanted a faster storage solution.&lt;/p&gt;

&lt;p&gt;That led us to &lt;strong&gt;MMKV&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;MMKV is a high-performance key-value storage library backed by memory-mapped files. The React Native implementation uses JSI, which allows JavaScript to communicate with native code without relying on the traditional asynchronous bridge for every operation.&lt;/p&gt;

&lt;p&gt;The performance improvement was significant.&lt;/p&gt;

&lt;p&gt;Reads and writes became synchronous and extremely fast.&lt;/p&gt;

&lt;p&gt;But there was a catch.&lt;/p&gt;

&lt;h3&gt;
  
  
  We lost our debugging superpowers.
&lt;/h3&gt;

&lt;p&gt;Our team relied heavily on &lt;strong&gt;Reactotron&lt;/strong&gt; during development. With Redux and other state-management tools, Reactotron gave us a convenient place to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inspect application state&lt;/li&gt;
&lt;li&gt;Track state changes&lt;/li&gt;
&lt;li&gt;View actions&lt;/li&gt;
&lt;li&gt;Inspect nested objects&lt;/li&gt;
&lt;li&gt;See before/after values&lt;/li&gt;
&lt;li&gt;Debug state transitions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After moving persistent state to MMKV, a large portion of that visibility disappeared.&lt;/p&gt;

&lt;p&gt;The data was there.&lt;/p&gt;

&lt;p&gt;The application was faster.&lt;/p&gt;

&lt;p&gt;But Reactotron couldn't see what was happening inside MMKV.&lt;/p&gt;

&lt;p&gt;We had effectively traded &lt;strong&gt;developer visibility for runtime performance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We didn't want to make that trade-off.&lt;/p&gt;

&lt;p&gt;So we built &lt;strong&gt;&lt;code&gt;reactotron-plugin-mmkv&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  1. Why a Simple MMKV Listener Wasn't Enough
&lt;/h1&gt;

&lt;p&gt;Our first instinct was to use MMKV's native value-change listener.&lt;/p&gt;

&lt;p&gt;MMKV provides a mechanism that tells you when a stored value changes.&lt;/p&gt;

&lt;p&gt;That sounds like exactly what we need.&lt;/p&gt;

&lt;p&gt;But there is an important distinction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Knowing that a value changed isn't the same as knowing what operation caused the change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For example, imagine these operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;storage.set("theme", "dark")
storage.set("theme", "light")
storage.delete("theme")
storage.clearAll()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A post-write listener can tell us that something changed.&lt;/p&gt;

&lt;p&gt;But Reactotron needs much more useful information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SET
UPDATE
DELETE
CLEAR_ALL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And ideally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;theme

before: "light"
after:  "dark"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The native listener fires after the operation has already happened.&lt;/p&gt;

&lt;p&gt;At that point, we've lost important context.&lt;/p&gt;

&lt;h3&gt;
  
  
  The limitations became clear
&lt;/h3&gt;

&lt;p&gt;A native change listener alone couldn't reliably provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The exact operation type&lt;/li&gt;
&lt;li&gt;The previous value&lt;/li&gt;
&lt;li&gt;A before/after diff&lt;/li&gt;
&lt;li&gt;Delete information&lt;/li&gt;
&lt;li&gt;Read operations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;clearAll()&lt;/code&gt; context&lt;/li&gt;
&lt;li&gt;Operation-specific metadata&lt;/li&gt;
&lt;li&gt;A complete state representation for Reactotron's State tab&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So we needed to intercept operations &lt;strong&gt;before they reached the native layer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That led us to the core idea behind the plugin.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Intercept MMKV at the JavaScript Boundary
&lt;/h1&gt;

&lt;p&gt;Instead of replacing MMKV, we wrapped it.&lt;/p&gt;

&lt;p&gt;JavaScript's &lt;code&gt;Proxy&lt;/code&gt; API gives us exactly the interception layer we needed.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Application
     │
     ▼
┌──────────────────┐
│ MMKV Proxy       │
│                  │
│ set()            │
│ delete()         │
│ clearAll()       │
│ getString()      │
│ getNumber()      │
└────────┬─────────┘
         │
         ▼
   Native MMKV
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application continues using the familiar MMKV API.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But instead of calling the native method directly, the Proxy gets the first opportunity to inspect the operation.&lt;/p&gt;

&lt;p&gt;That gives us enough information to reconstruct the complete state transition.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. How Proxy Mode Works
&lt;/h1&gt;

&lt;p&gt;For a write operation such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the plugin can perform the following sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Intercept set()
2. Check whether "theme" already exists
3. Read the previous value
4. Execute the original MMKV operation
5. Determine SET vs UPDATE
6. Build the operation payload
7. Send the event to Reactotron
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if the key didn't exist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🟢 MMKV SET

theme → "dark"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the key already contained &lt;code&gt;"light"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🟡 MMKV UPDATE

theme
before: "light"
after:  "dark"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for deletion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔴 MMKV DELETE

theme
removed: "dark"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is significantly more useful than simply receiving:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;theme changed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  4. The Operation Pipeline
&lt;/h1&gt;

&lt;p&gt;At a high level, the Proxy follows this decision tree:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Application calls MMKV
                             │
                             ▼
                       Proxy intercepts
                             │
                    ┌────────┴────────┐
                    │                 │
                Ignored key       Supported method
                    │                 │
                    ▼                 ▼
              Native MMKV       Identify operation
                                      │
              ┌───────────────────────┼──────────────────────┐
              │                       │                      │
             set()                 delete()              clearAll()
              │                       │                      │
              ▼                       ▼                      ▼
        Read old value          Read old value         Count keys
              │                       │                      │
              ▼                       ▼                      ▼
        Native operation        Native operation      Native operation
              │                       │                      │
              ▼                       ▼                      ▼
        SET / UPDATE              DELETE                CLEAR_ALL
              │                       │                      │
              └───────────────────────┼──────────────────────┘
                                      ▼
                              Build Reactotron payload
                                      │
                                      ▼
                              Send operation to UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach also lets the plugin optionally observe reads.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;can be logged when read logging is enabled.&lt;/p&gt;

&lt;p&gt;That can be useful when debugging unexpected storage access, although logging every read isn't something we'd recommend enabling by default in performance-sensitive applications.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. Why We Added an Ignore List
&lt;/h1&gt;

&lt;p&gt;Instrumentation itself has a cost.&lt;/p&gt;

&lt;p&gt;If an application performs thousands of storage operations, logging every single one can become noisy and unnecessarily expensive.&lt;/p&gt;

&lt;p&gt;So the plugin supports ignoring specific keys.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;mmkvPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;proxy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;ignoredKeys&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some_high_frequency_key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;temporary_cache&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ignored operations bypass the additional instrumentation and execute directly against the underlying MMKV instance.&lt;/p&gt;

&lt;p&gt;This gives developers control over the observability/performance trade-off.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. The Bigger Challenge: Reactotron's State Tab
&lt;/h1&gt;

&lt;p&gt;Operation logging solved only half the problem.&lt;/p&gt;

&lt;p&gt;We also wanted MMKV to appear inside Reactotron's &lt;strong&gt;State&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;This is where things became more interesting.&lt;/p&gt;

&lt;p&gt;MMKV itself is fundamentally a flat key-value store:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user_token
theme
language
user_settings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But applications often store serialized JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user_settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Alex&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If Reactotron simply displayed the raw value, developers would see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user_settings:
"{\"volume\":80,\"notifications\":true,\"profile\":{\"name\":\"Alex\"}}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's technically correct.&lt;/p&gt;

&lt;p&gt;But it's not a great debugging experience.&lt;/p&gt;

&lt;p&gt;We wanted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user_settings
├── volume: 80
├── notifications: true
└── profile
    └── name: "Alex"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the plugin needed its own state engine.&lt;/p&gt;




&lt;h1&gt;
  
  
  7. Building an MMKV State Engine
&lt;/h1&gt;

&lt;p&gt;The state engine performs several jobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Read MMKV keys
&lt;/h3&gt;

&lt;p&gt;It retrieves the keys stored in the MMKV instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Resolve nested paths
&lt;/h3&gt;

&lt;p&gt;Reactotron can request specific paths rather than the entire state tree.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mmkv
mmkv.user_settings
mmkv.user_settings.profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The plugin resolves those paths dynamically.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Parse JSON values
&lt;/h3&gt;

&lt;p&gt;When a stored string contains valid JSON, the plugin can expose it as a structured object.&lt;/p&gt;

&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"user_settings": "{\"volume\":80}"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reactotron can display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"user_settings": {
  "volume": 80
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Handle problematic values
&lt;/h3&gt;

&lt;p&gt;Debugging tools need to be defensive.&lt;/p&gt;

&lt;p&gt;Large strings, deeply nested structures, and circular references can become surprisingly expensive to render.&lt;/p&gt;

&lt;p&gt;The state engine therefore needs to protect Reactotron from excessively large or problematic payloads.&lt;/p&gt;

&lt;p&gt;The goal isn't simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Send everything to Reactotron."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The goal is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Send enough information to make debugging useful without turning the debugging tool into the performance problem."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  8. The Redux Problem
&lt;/h1&gt;

&lt;p&gt;There was another issue we didn't anticipate initially.&lt;/p&gt;

&lt;p&gt;Our application wasn't using MMKV alone.&lt;/p&gt;

&lt;p&gt;We also had Redux.&lt;/p&gt;

&lt;p&gt;That meant Reactotron could have two different state providers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Redux Plugin
     │
     └── Reactotron State

MMKV Plugin
     │
     └── Reactotron State
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both plugins can potentially respond to Reactotron's state requests.&lt;/p&gt;

&lt;p&gt;And that creates a collision.&lt;/p&gt;

&lt;p&gt;Imagine Reactotron asks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;state.values.request
path: null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Redux plugin responds with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
  &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
  &lt;span class="nx"&gt;cart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MMKV plugin responds with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;mmkv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If those responses aren't coordinated, one can effectively overwrite the other.&lt;/p&gt;

&lt;p&gt;Instead of seeing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;State
├── auth
├── user
├── cart
└── mmkv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you may end up seeing only one side.&lt;/p&gt;

&lt;p&gt;That's not what we wanted.&lt;/p&gt;




&lt;h1&gt;
  
  
  9. Merging Peer Plugin State
&lt;/h1&gt;

&lt;p&gt;The solution was to intercept the Reactotron communication layer and merge state responses.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reactotron requests root state
              │
              ▼
       Redux responds
              │
              ▼
     MMKV interceptor
              │
        ┌─────┴─────┐
        │           │
   Cache Redux   Read MMKV
      state        state
        │           │
        └─────┬─────┘
              ▼
        Merge both trees
              │
              ▼
      Send merged state
              │
              ▼
        Reactotron UI
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resulting tree becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;State
├── auth
├── user
├── cart
└── mmkv
    ├── user_token
    ├── theme
    └── user_settings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was one of the most important parts of the implementation.&lt;/p&gt;

&lt;p&gt;The plugin wasn't just adding another state provider.&lt;/p&gt;

&lt;p&gt;It was making MMKV behave like a &lt;strong&gt;cooperative peer&lt;/strong&gt; alongside existing Reactotron state plugins.&lt;/p&gt;




&lt;h1&gt;
  
  
  10. Handling Standalone MMKV Usage
&lt;/h1&gt;

&lt;p&gt;We also wanted the plugin to work when Redux wasn't installed.&lt;/p&gt;

&lt;p&gt;That creates another edge case.&lt;/p&gt;

&lt;p&gt;If the MMKV plugin waits for another state provider to respond, it could end up waiting forever in a standalone application.&lt;/p&gt;

&lt;p&gt;The solution is a small fallback mechanism.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Root state request
       │
       ▼
Wait briefly for peer response
       │
   ┌───┴────┐
   │        │
Response   No response
   │        │
   ▼        ▼
Merge     Return MMKV
state      state
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows the plugin to work in both environments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Redux + MMKV
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MMKV only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;without requiring developers to configure the application differently.&lt;/p&gt;




&lt;h1&gt;
  
  
  11. The Final Architecture
&lt;/h1&gt;

&lt;p&gt;Putting everything together gives us four major layers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────────────────────────┐
│              React Native App               │
│                                             │
│  Application Code                           │
│       │                                     │
│       ▼                                     │
│  MMKV Proxy                                 │
│       │                                     │
│       ▼                                     │
│  Native MMKV                                │
│                                             │
│  ┌───────────────────────────────────────┐  │
│  │ reactotron-plugin-mmkv                │  │
│  │                                       │  │
│  │ • Operation interception              │  │
│  │ • Diff generation                     │  │
│  │ • JSON parsing                        │  │
│  │ • State tree generation               │  │
│  │ • Path resolution                     │  │
│  │ • State merging                       │  │
│  └───────────────────────────────────────┘  │
│                     │                       │
└─────────────────────┼───────────────────────┘
                      │
                 WebSocket
                      │
                      ▼
┌─────────────────────────────────────────────┐
│              Reactotron Desktop             │
│                                             │
│  Timeline                                   │
│  ├── SET                                    │
│  ├── UPDATE                                 │
│  ├── DELETE                                 │
│  └── CLEAR_ALL                              │
│                                             │
│  State                                      │
│  ├── Redux                                  │
│  └── MMKV                                   │
└─────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is that we didn't modify MMKV itself.&lt;/p&gt;

&lt;p&gt;We added an observability layer around it.&lt;/p&gt;




&lt;h1&gt;
  
  
  12. Using the Plugin
&lt;/h1&gt;

&lt;p&gt;Installation is intentionally simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; reactotron-plugin-mmkv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;-D&lt;/span&gt; reactotron-plugin-mmkv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create your MMKV instance normally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MMKV&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-native-mmkv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rawStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MMKV&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mmkv.default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In development, wrap it with the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;LocalStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rawStorage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__DEV__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mmkvPlugin&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reactotron-plugin-mmkv&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Reactotron&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;reactotron-react-native&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mmkvPlugin&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;proxy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;Reactotron&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;LocalStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LocalStorage&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Application code can then continue using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;LocalStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;LocalStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application doesn't need to know whether the storage instance is instrumented.&lt;/p&gt;




&lt;h1&gt;
  
  
  13. Proxy Mode vs Basic Mode
&lt;/h1&gt;

&lt;p&gt;The plugin provides two approaches depending on how much instrumentation you need.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Mode
&lt;/h3&gt;

&lt;p&gt;Basic mode relies more heavily on MMKV's native change notifications.&lt;/p&gt;

&lt;p&gt;It's useful when you want lightweight monitoring with minimal interception.&lt;/p&gt;

&lt;h3&gt;
  
  
  Proxy Mode
&lt;/h3&gt;

&lt;p&gt;Proxy mode wraps the storage instance and intercepts operations at the JavaScript layer.&lt;/p&gt;

&lt;p&gt;This enables richer information such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SET vs UPDATE&lt;/li&gt;
&lt;li&gt;Previous values&lt;/li&gt;
&lt;li&gt;Delete information&lt;/li&gt;
&lt;li&gt;Operation-specific payloads&lt;/li&gt;
&lt;li&gt;More detailed Reactotron timeline events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your goal is &lt;strong&gt;full debugging visibility&lt;/strong&gt;, Proxy Mode is the more powerful option.&lt;/p&gt;

&lt;p&gt;If your goal is &lt;strong&gt;minimal instrumentation&lt;/strong&gt;, Basic Mode may be more appropriate.&lt;/p&gt;




&lt;h1&gt;
  
  
  14. Keeping Production Builds Clean
&lt;/h1&gt;

&lt;p&gt;Reactotron is a development tool.&lt;/p&gt;

&lt;p&gt;It shouldn't become part of your production runtime.&lt;/p&gt;

&lt;p&gt;That's why the integration is guarded with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__DEV__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Reactotron + MMKV instrumentation&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In production, the application simply uses the original MMKV instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Development:

App → Proxy → MMKV → Reactotron

Production:

App → MMKV
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps debugging concerns separated from the release runtime.&lt;/p&gt;

&lt;p&gt;It's a small architectural decision, but an important one for performance-sensitive applications.&lt;/p&gt;




&lt;h1&gt;
  
  
  15. What We Ended Up With
&lt;/h1&gt;

&lt;p&gt;The final debugging experience looks much closer to what we had with Redux.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🟢 MMKV SET

"user_token"
→ "eyJhbGci..."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🟡 MMKV UPDATE

"theme"
before: "light"
after:  "dark"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🔴 MMKV DELETE

"session_id"
removed: "abc123"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;⚫ MMKV CLEAR_ALL

removed 8 key(s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  State
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;State
├── auth
├── cart
├── user
└── mmkv
    ├── user_token
    ├── theme
    └── user_settings
        ├── volume
        ├── notifications
        └── profile
            └── name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important difference is that MMKV is no longer a black box during development.&lt;/p&gt;

&lt;p&gt;We get the performance benefits of native, synchronous storage while retaining the visibility we expect from a modern debugging workflow.&lt;/p&gt;




&lt;h1&gt;
  
  
  16. The Bigger Lesson
&lt;/h1&gt;

&lt;p&gt;The interesting part of this project wasn't MMKV itself.&lt;/p&gt;

&lt;p&gt;It was the architecture around &lt;strong&gt;observability&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;High-performance systems often hide useful information behind optimized layers.&lt;/p&gt;

&lt;p&gt;That's a good thing for production.&lt;/p&gt;

&lt;p&gt;But during development, those same optimizations can make debugging harder.&lt;/p&gt;

&lt;p&gt;The solution isn't always to sacrifice performance.&lt;/p&gt;

&lt;p&gt;Sometimes the better approach is to introduce a thin instrumentation layer that exists only during development.&lt;/p&gt;

&lt;p&gt;In our case, that layer combines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript &lt;code&gt;Proxy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;MMKV's native change notifications&lt;/li&gt;
&lt;li&gt;Operation classification&lt;/li&gt;
&lt;li&gt;Before/after state inspection&lt;/li&gt;
&lt;li&gt;JSON parsing&lt;/li&gt;
&lt;li&gt;Dynamic state-path resolution&lt;/li&gt;
&lt;li&gt;Reactotron protocol interception&lt;/li&gt;
&lt;li&gt;Peer state merging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each piece solves a different problem.&lt;/p&gt;

&lt;p&gt;Together, they turn MMKV from a fast but opaque storage layer into something developers can actually inspect.&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Moving from &lt;code&gt;AsyncStorage&lt;/code&gt; to MMKV gave us the performance characteristics we wanted.&lt;/p&gt;

&lt;p&gt;But it also exposed an important engineering trade-off:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fast storage is great. Fast storage that you can actually debug is better.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead of giving up Reactotron, we built a bridge between the two.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;reactotron-plugin-mmkv&lt;/code&gt; brings MMKV operations into the Reactotron timeline, exposes MMKV data through the State tab, generates useful before/after information, and allows MMKV to coexist with Redux and other Reactotron state providers.&lt;/p&gt;

&lt;p&gt;The result is a development experience where performance and observability don't have to compete.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explore the project
&lt;/h3&gt;

&lt;p&gt;📦 &lt;strong&gt;NPM:&lt;/strong&gt; &lt;code&gt;[reactotron-plugin-mmkv](https://www.npmjs.com/package/reactotron-plugin-mmkv)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;code&gt;[mdRehan991/reactotron-plugin-mmkv](https://github.com/mdRehan991/reactotron-plugin-mmkv)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you're using MMKV in a React Native application and want better visibility into what's happening inside your persistent storage, give it a try.&lt;/p&gt;

&lt;p&gt;And if you run into an edge case, open an issue or contribute to the project. The most interesting parts of developer tooling often come from problems that initially look too small to solve.&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>javascript</category>
      <category>performance</category>
      <category>reactnative</category>
    </item>
  </channel>
</rss>
