<?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: titan00001</title>
    <description>The latest articles on DEV Community by titan00001 (@titan00001).</description>
    <link>https://dev.to/titan00001</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%2F870639%2F97a55d45-68a8-43b9-98bb-d4740e7b857a.png</url>
      <title>DEV Community: titan00001</title>
      <link>https://dev.to/titan00001</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/titan00001"/>
    <language>en</language>
    <item>
      <title>"pod install" Fixed My Expo Package Version (And Taught Me the Difference Between "npm install" and "npx expo install")</title>
      <dc:creator>titan00001</dc:creator>
      <pubDate>Thu, 04 Jun 2026 13:21:16 +0000</pubDate>
      <link>https://dev.to/titan00001/pod-install-fixed-my-expo-package-version-and-taught-me-the-difference-between-npm-install-and-11cb</link>
      <guid>https://dev.to/titan00001/pod-install-fixed-my-expo-package-version-and-taught-me-the-difference-between-npm-install-and-11cb</guid>
      <description>&lt;h2&gt;
  
  
  The Problem That Didn't Make Sense
&lt;/h2&gt;

&lt;p&gt;I was working on an Expo-managed React Native application targeting iOS. Everything looked normal until I noticed a version mismatch involving &lt;code&gt;expo-file-system&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My &lt;code&gt;package.json&lt;/code&gt; contained:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^54.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expo-file-system"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^55.0.16"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, the Expo SDK 54 documentation showed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;expo-file-system ~19.0.23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this looked wrong. How could the package be version &lt;code&gt;55.0.16&lt;/code&gt; in my project while the documentation recommended &lt;code&gt;19.0.23&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;The confusion became even greater when I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pod &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Installing ExpoFileSystem 19.0.23 (was 55.0.16)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The build succeeded.&lt;/p&gt;

&lt;p&gt;At that moment I realized I didn't actually understand how Expo packages, native modules, CocoaPods, and version compatibility worked together.&lt;/p&gt;




&lt;h2&gt;
  
  
  My Initial Assumption
&lt;/h2&gt;

&lt;p&gt;Like many JavaScript developers, I assumed:&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;expo-file-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;means:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Install the package and everything needed for it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This mental model works reasonably well for pure JavaScript libraries such as:&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;axios
npm &lt;span class="nb"&gt;install &lt;/span&gt;zod
npm &lt;span class="nb"&gt;install &lt;/span&gt;date-fns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is no native code involved. The package version is the package version.&lt;/p&gt;

&lt;p&gt;Expo modules are different.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the Layers
&lt;/h2&gt;

&lt;p&gt;An Expo package actually exists in multiple worlds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expo SDK
│
├── JavaScript Package
│   └── expo-file-system
│
├── Native iOS Module
│   └── ExpoFileSystem Pod
│
├── Native Android Module
│   └── Gradle Module
│
└── Expo Compatibility Matrix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you use:&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;expo-file-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;npm only knows about the JavaScript package published to npm.&lt;/p&gt;

&lt;p&gt;It does not know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Which Expo SDK you're using&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which React Native version you're using&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which native iOS pod version is compatible&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which Android native implementation should be used&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Its job is simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Install the latest package matching the version range.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nothing more.&lt;/p&gt;




&lt;h2&gt;
  
  
  What &lt;code&gt;npx expo install&lt;/code&gt; Actually Does
&lt;/h2&gt;

&lt;p&gt;Expo provides its own installation command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo &lt;span class="nb"&gt;install &lt;/span&gt;expo-file-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command behaves differently.&lt;/p&gt;

&lt;p&gt;Before installing anything, Expo checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Current Expo SDK Version
          ↓
Compatible Package Version
          ↓
Install That Version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expo SDK 54
        ↓
expo-file-system ~19.0.23
        ↓
Install 19.0.23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of grabbing the newest package available on npm, Expo chooses the version tested and validated against the current SDK.&lt;/p&gt;

&lt;p&gt;This is why Expo documentation almost always recommends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo &lt;span class="nb"&gt;install&lt;/span&gt; &amp;lt;expo-package&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of:&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; &amp;lt;expo-package&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Then Why Did &lt;code&gt;pod install&lt;/code&gt; Fix It?
&lt;/h2&gt;

&lt;p&gt;This was the part that confused me the most.&lt;/p&gt;

&lt;p&gt;I expected CocoaPods to simply install whatever was in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

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

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pod &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expo autolinking runs.&lt;/p&gt;

&lt;p&gt;Autolinking scans installed Expo modules and reads their native configuration files.&lt;/p&gt;

&lt;p&gt;A simplified view 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;node_modules
      ↓
Expo Package
      ↓
Podspec
      ↓
CocoaPods
      ↓
Native Pod Installation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When CocoaPods encountered the Expo File System module, it discovered that the native pod version expected for SDK 54 was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ExpoFileSystem 19.0.23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and corrected the native dependency accordingly.&lt;/p&gt;

&lt;p&gt;That's why I saw:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Installing ExpoFileSystem 19.0.23 (was 55.0.16)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The native side was effectively protecting itself from an incompatible version.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Important Lesson
&lt;/h2&gt;

&lt;p&gt;The successful build was actually misleading.&lt;/p&gt;

&lt;p&gt;The build succeeding does not mean the dependency setup is healthy.&lt;/p&gt;

&lt;p&gt;I still had a mismatch between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JavaScript Layer
expo-file-system 55.x
&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;Native Layer
ExpoFileSystem 19.x
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A future build, CI pipeline, runtime feature, or TypeScript API could easily break because the JavaScript package and native implementation are expecting different things.&lt;/p&gt;

&lt;p&gt;The fact that CocoaPods repaired the native side doesn't mean the project is correctly configured.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Rule I Follow Now
&lt;/h2&gt;

&lt;p&gt;Whenever I add an Expo package:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo &lt;span class="nb"&gt;install &lt;/span&gt;expo-file-system
npx expo &lt;span class="nb"&gt;install &lt;/span&gt;expo-camera
npx expo &lt;span class="nb"&gt;install &lt;/span&gt;expo-location
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever I add a normal JavaScript library:&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;axios
npm &lt;span class="nb"&gt;install &lt;/span&gt;zod
npm &lt;span class="nb"&gt;install &lt;/span&gt;lodash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple way to remember it is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the package belongs to the Expo ecosystem, let Expo decide the version. If it's a pure JavaScript dependency, let npm decide.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A Helpful Command I Learned
&lt;/h2&gt;

&lt;p&gt;If you inherit an existing Expo project and suspect version drift, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--fix&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expo will inspect installed Expo packages and align them with the currently installed SDK.&lt;/p&gt;

&lt;p&gt;Follow it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx expo doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to identify remaining compatibility issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Mental Model
&lt;/h2&gt;

&lt;p&gt;The mental model that finally made everything click for me was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install
    =
Install package

expo install
    =
Find compatible version
+
Install package

pod install
    =
Install native iOS dependencies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The mistake is assuming npm understands Expo SDK compatibility. It doesn't.&lt;/p&gt;

&lt;p&gt;Expo does.&lt;/p&gt;

&lt;p&gt;And that small distinction is the reason a seemingly mysterious &lt;code&gt;pod install&lt;/code&gt; ended up teaching me how Expo's dependency system actually works.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
