<?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: Mehdi Faraji</title>
    <description>The latest articles on DEV Community by Mehdi Faraji (@mehdifaraji).</description>
    <link>https://dev.to/mehdifaraji</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F406300%2F141fd232-ad2e-4133-bd27-e3c59f5a24c1.jpeg</url>
      <title>DEV Community: Mehdi Faraji</title>
      <link>https://dev.to/mehdifaraji</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mehdifaraji"/>
    <language>en</language>
    <item>
      <title>zustand-mmkv-storage: Blazing Fast Persistence for Zustand in React Native</title>
      <dc:creator>Mehdi Faraji</dc:creator>
      <pubDate>Mon, 29 Dec 2025 23:06:04 +0000</pubDate>
      <link>https://dev.to/mehdifaraji/zustand-mmkv-storage-blazing-fast-persistence-for-zustand-in-react-native-3ef1</link>
      <guid>https://dev.to/mehdifaraji/zustand-mmkv-storage-blazing-fast-persistence-for-zustand-in-react-native-3ef1</guid>
      <description>&lt;h1&gt;
  
  
  Persisting State in React Native: Why MMKV + Zustand is the Winning Combo 🚀
&lt;/h1&gt;

&lt;p&gt;If you're building React Native apps, you've probably faced the classic problem: &lt;strong&gt;how do I save user data (theme, auth token, cart, preferences) so it survives app restarts?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React Native gives us a few options for local storage, but not all are created equal. Let's walk through the landscape, why &lt;strong&gt;persistence matters&lt;/strong&gt;, the limitations of the old standard, and why &lt;strong&gt;MMKV&lt;/strong&gt; has become the go-to choice — especially when paired with &lt;strong&gt;Zustand&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Do We Need Persistent State in React Native?
&lt;/h3&gt;

&lt;p&gt;Mobile users expect apps to "remember" them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login tokens should stay valid&lt;/li&gt;
&lt;li&gt;Shopping carts shouldn't empty on app close&lt;/li&gt;
&lt;li&gt;Theme preferences (dark/light) should persist&lt;/li&gt;
&lt;li&gt;Onboarding flow shouldn't replay every time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without persistence, your app feels broken. With good persistence, it feels &lt;strong&gt;native and polished&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Old King: AsyncStorage
&lt;/h3&gt;

&lt;p&gt;For years, &lt;strong&gt;AsyncStorage&lt;/strong&gt; was the default solution. It's simple, works everywhere, and integrates nicely with libraries like Zustand/Redux.&lt;/p&gt;

&lt;p&gt;But it has serious downsides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slow&lt;/strong&gt;: Fully JavaScript-based, serialized bridge calls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async-only&lt;/strong&gt;: Every read/write blocks UI if not careful&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No encryption&lt;/strong&gt; out of the box&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deprecated&lt;/strong&gt; by React Native core team (replaced by community forks)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Benchmarks show MMKV can be &lt;strong&gt;30–100x faster&lt;/strong&gt; than AsyncStorage in real-world scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enter MMKV: The Modern Champion
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/mrousavy/react-native-mmkv" rel="noopener noreferrer"&gt;MMKV&lt;/a&gt;&lt;/strong&gt; (Mobile Key-Value) is a high-performance key-value store developed by Tencent and now maintained by Marc Rousavy (&lt;a class="mentioned-user" href="https://dev.to/mrousavy"&gt;@mrousavy&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Key advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Written in &lt;strong&gt;C++&lt;/strong&gt; with JSI bindings → blazing fast&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous&lt;/strong&gt; reads/writes (no await needed for get)&lt;/li&gt;
&lt;li&gt;Built-in &lt;strong&gt;encryption&lt;/strong&gt; support&lt;/li&gt;
&lt;li&gt;Multi-process mode (safe for app groups/extensions)&lt;/li&gt;
&lt;li&gt;Tiny footprint, Expo-compatible&lt;/li&gt;
&lt;li&gt;Actively maintained and used in production by big apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In short: MMKV is what AsyncStorage should have been in 2025.&lt;/p&gt;

&lt;h3&gt;
  
  
  Zustand + Persistence = Magic
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://zustand-demo.pmnd.rs/" rel="noopener noreferrer"&gt;Zustand&lt;/a&gt; is the most popular lightweight state manager in React Native today. Its &lt;code&gt;persist&lt;/code&gt; middleware makes saving state trivial — &lt;strong&gt;if&lt;/strong&gt; you have a good storage backend.&lt;/p&gt;

&lt;p&gt;That's where most people hit friction: wiring MMKV manually is verbose, error-prone, and doesn't handle instance sharing or encryption cleanly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introducing zustand-mmkv-storage
&lt;/h3&gt;

&lt;p&gt;I built &lt;strong&gt;&lt;a href="https://www.npmjs.com/package/zustand-mmkv-storage" rel="noopener noreferrer"&gt;zustand-mmkv-storage&lt;/a&gt;&lt;/strong&gt; to solve exactly this.&lt;/p&gt;

&lt;p&gt;It's a tiny (&amp;lt;1KB), zero-dependency adapter that lets you use MMKV as the storage backend for Zustand's &lt;code&gt;persist&lt;/code&gt; — with all the modern features you'd expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lazy dynamic import&lt;/strong&gt; → no startup cost&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global instance caching&lt;/strong&gt; → same config = same MMKV instance (efficient &amp;amp; consistent)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Full encryption support&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multiple isolated stores&lt;/strong&gt; (perfect for separating auth, settings, user data)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hydration-ready&lt;/strong&gt; (no flash of empty state)&lt;/li&gt;
&lt;li&gt;Works with Expo &amp;amp; bare React Native&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&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;zustand-mmkv-storage zustand react-native-mmkv
&lt;span class="c"&gt;# or&lt;/span&gt;
yarn add zustand-mmkv-storage zustand react-native-mmkv
&lt;span class="c"&gt;# or&lt;/span&gt;
pnpm add zustand-mmkv-storage zustand react-native-mmkv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Simple Usage
&lt;/h3&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;create&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="s1"&gt;zustand&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createJSONStorage&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="s1"&gt;zustand/middleware&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;mmkvStorage&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="s1"&gt;zustand-mmkv-storage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useBearStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;bears&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;addBear&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;bears&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bears&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;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="s1"&gt;bear-storage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// key in MMKV&lt;/span&gt;
      &lt;span class="na"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;createJSONStorage&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;mmkvStorage&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;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Your &lt;code&gt;bears&lt;/code&gt; count now persists across app restarts — fast and reliably.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advanced: Encrypted &amp;amp; Isolated Storage
&lt;/h3&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;createMMKVStorage&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="s1"&gt;zustand-mmkv-storage&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;secureStorage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMMKVStorage&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="s1"&gt;secure-vault&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;// separate file&lt;/span&gt;
  &lt;span class="na"&gt;encryptionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-secret-2025&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// enables encryption&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useAuthStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;persist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;setToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;token&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;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="s1"&gt;auth-storage&lt;/span&gt;&lt;span class="dl"&gt;'&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="nf"&gt;createJSONStorage&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;secureStorage&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;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now your auth token is encrypted on disk and completely isolated from other data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use Cases
&lt;/h3&gt;

&lt;p&gt;Auth tokens &amp;amp; refresh tokens&lt;br&gt;
User preferences (theme, language)&lt;br&gt;
Shopping carts / offline forms&lt;br&gt;
Onboarding completion&lt;br&gt;
Feature flags / A-B testing&lt;/p&gt;

&lt;p&gt;Try It Today!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i zustand-mmkv-storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/1mehdifaraji/zustand-mmkv-storage" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; - &lt;a href="https://www.npmjs.com/package/zustand-mmkv-storage" rel="noopener noreferrer"&gt;NPM&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If this saves you time or makes your app faster, I'd love a ⭐ on GitHub!&lt;br&gt;
Thanks for reading — happy (and fast) persisting! 🐻✨&lt;/p&gt;

&lt;h1&gt;
  
  
  reactnative #zustand #mmkv #javascript #opensource
&lt;/h1&gt;

</description>
      <category>reactnative</category>
      <category>zustand</category>
      <category>mobile</category>
      <category>mmkv</category>
    </item>
    <item>
      <title>Merge and bundle open api yaml files for swagger</title>
      <dc:creator>Mehdi Faraji</dc:creator>
      <pubDate>Sat, 31 Aug 2024 22:41:07 +0000</pubDate>
      <link>https://dev.to/mehdifaraji/merge-and-bundle-open-api-yaml-files-for-swagger-f5c</link>
      <guid>https://dev.to/mehdifaraji/merge-and-bundle-open-api-yaml-files-for-swagger-f5c</guid>
      <description>&lt;p&gt;Have you ever tried to document your apis with swagger?&lt;/p&gt;

&lt;p&gt;The way you would approach after watching some tutorials and reading &lt;a href="https://swagger.io/specification/" rel="noopener noreferrer"&gt;&lt;strong&gt;OPENAPI&lt;/strong&gt;&lt;/a&gt; official documentation, is to code in a single yaml file and define components, schemas and etc all in one place.&lt;/p&gt;

&lt;p&gt;In the end you will end up with hundreds of lines of code in a single file which is hard to read, not easy to modify or debug after a while.&lt;/p&gt;

&lt;p&gt;And the only way to have a better development experience, is to use openapi's own &lt;a href="https://swagger.io/tools/swaggerhub/" rel="noopener noreferrer"&gt;&lt;strong&gt;SwaggerHub&lt;/strong&gt;&lt;/a&gt; which is not free to use after all.&lt;/p&gt;

&lt;p&gt;Not so good, right?&lt;/p&gt;

&lt;p&gt;The better way to approach this situation is to have nicely named yaml files and folders and export them to use in a single yaml file.&lt;/p&gt;

&lt;p&gt;Basically we will treat each schema or resource as a module and export it and then import each of them in a main file.&lt;/p&gt;

&lt;p&gt;Then we would bundle and merge all files and build a single yaml file for our api documentation.&lt;/p&gt;

&lt;p&gt;The structure I suggest is to create separate folders for parameters, resources, responses and schemas.&lt;/p&gt;

&lt;p&gt;Finally you can bundle all of your yaml files with this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx swagger-cli bundle src/openapi.yaml - outfile _build/openapi.yaml - type yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/APIDevTools/swagger-cli" rel="noopener noreferrer"&gt;&lt;strong&gt;swagger-cli&lt;/strong&gt;&lt;/a&gt; tool merges all of your yaml files into one file inside &lt;strong&gt;_build&lt;/strong&gt; directory.&lt;/p&gt;

&lt;p&gt;To test it out, you can copy the generated build file and paste it in &lt;a href="https://editor.swagger.io/" rel="noopener noreferrer"&gt;&lt;strong&gt;Swagger live editor&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can check how I've demonstrated the bundling on my &lt;a href="https://github.com/1mehdifaraji/swagger-bundle" rel="noopener noreferrer"&gt;&lt;strong&gt;Github repo&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>swagger</category>
      <category>openapi</category>
      <category>node</category>
    </item>
  </channel>
</rss>
