skip to content

In a React Native project, when should you reset Metro's cache, which command does it, and what does the reset actually clear?

level: juniorimportance: must knowfreq 60%

answer

  1. stale output after config or dependency changes
  2. npx react-native start --reset-cache
  3. npx expo start --clear (-c)
  4. transform cache plus file map cache
  5. not node_modules, not native builds

basics

~20 s

Reset Metro's cache when bundles show old code or config after a Babel, dependency or branch change. npx react-native start --reset-cache or npx expo start --clear discards the transform and file map caches, not node_modules or native builds.

solid answer

~50 s

Metro caches every transformed file and keeps a cached **file map** of the project, so a warm start skips most work. When the cache no longer matches reality, for example after editing `babel.config.js` in a bare app, upgrading a Babel plugin or switching branches while Metro was running, you see old code or phantom errors. The fix is a clean start: `npx react-native start --reset-cache` in a React Native CLI project, `npx expo start --clear` (or `-c`) in Expo, or `resetCache: true` in the Metro config. It resets the transformer cache in `cacheStores` and the file map cache, so the first bundle afterwards is slow. It does not reinstall `node_modules`, clear Watchman's own watches, touch Gradle or Xcode build output, or change what is installed on the device. Use it deliberately rather than as a ritual on every start.

code

bash · 10 lines
bash
# React Native CLI project
npx react-native start --reset-cache

# Expo project
npx expo start --clear

# Metro's documented escalation when a reset is not enough
watchman watch-del-all
rm -rf node_modules && npm install
rm -rf "${TMPDIR:-/tmp}"/metro-*

go deeper

for a junior

Know the reset command for your project type and recognise the symptom: old code or phantom errors after a Babel, dependency or branch change.

for a middle

Explain that a reset clears the transform cache and the file map cache, and what it leaves alone: node_modules, Watchman and native builds.

for a senior

Treat repeated resets as a signal that an input is missing from the cache key, and fix it with cacheVersion or config rather than a habit.

for a principal

Make cache behaviour predictable for the whole team, so resets become rare and are not part of anyone's daily workflow.

## What Metro caches **Metro**, the bundler React Native and Expo use, keeps two kinds of state between runs: - the **transform cache**: the compiled output of every file, stored by default by a `FileStore` under the operating system's temporary directory (`os.tmpdir()/metro-cache`). A warm start reuses it for every unchanged file; - the **file map**: Metro's index of every file it can see in the project, with metadata, also persisted (by default under `os.tmpdir()`, configurable with `fileMapCacheDirectory`) so a restart does not need to crawl the whole tree from scratch. Both make development fast. Both can go stale when something changes that Metro's cache key or file watcher did not notice. ## When a reset is the right move 1. **After changing Babel configuration in a bare React Native app.** The React Native Babel transformer's cache key covers the preset version, not your `babel.config.js`, so an edited plugin list can keep serving old output. 2. **After upgrading or adding a Babel plugin** whose output depends on something outside the file being compiled. 3. **When a Babel plugin inlines environment variables** and you changed the variable: the file content did not change, so the key did not either. 4. **After a large branch switch or dependency change** that left errors which do not match the files on disk. 5. **When the bundle clearly contains code you have already deleted.** Most other changes, including edits to source files and new files, are handled automatically: the cache key includes each file's content hash, and the watcher updates the file map. ## The commands | Project | Command | Notes | |---|---|---| | React Native CLI | `npx react-native start --reset-cache` | one run only | | Expo | `npx expo start --clear` | `-c` is the short form; `--reset-cache` is accepted as an alias | | Any Metro config | `resetCache: true` | resets on every start; do not leave it committed | | Release bundle | `npx react-native bundle --reset-cache …` | for a one-off clean bundle | Metro's docs list the escalation path when a reset is not enough: clear Watchman's watches with `watchman watch-del-all`, delete and reinstall `node_modules`, then reset the cache again, and as a last resort remove Metro's temporary files (`rm -rf ${TMPDIR:-/tmp}/metro-*`). ## Read the symptom before resetting - **Old code still runs** after a Babel or plugin change: stale transform output, and a reset fixes it. - **A resolution error for a file that exists**: a stale file map, and a restart or reset fixes it. - **A resolution error for a package**: usually a missing install, which a reset cannot fix. - **A native crash or a missing native module**: a native build problem, outside Metro entirely. Matching the symptom first keeps the reset for the cases it can actually solve. ## What a reset does not do - It does **not** reinstall dependencies. A package missing from `node_modules` stays missing. - It does **not** clear Watchman's state; that is `watchman watch-del-all`. - It does **not** clean native builds: Gradle and Xcode keep their own caches, and a new native module still needs a native rebuild. - It does **not** change the app installed on a device beyond serving it a fresh bundle on the next load. ## Costs and habits A reset forces every file to be transformed again, so the next bundle takes much longer. Teams that reset on every start lose the main benefit of the cache and hide the real cause of staleness. Better habits: - reset once after the kinds of change listed above; - when you find yourself resetting after every change of a particular setting, make that input part of the key instead, for example by deriving `cacheVersion` from it; - never commit `resetCache: true`. ## What interviewers listen for A junior answer names the command for the project type and the typical trigger (old code still running after a Babel or dependency change). A stronger answer explains that the reset clears both the transform cache and the file map, and knows what it leaves alone, so it does not reach for `--reset-cache` to fix a missing dependency or a native module that was never built.

  • Why is committing resetCache: true to the Metro config a bad idea?
    It discards the transform cache and file map on every start, so every developer and CI run pays for a full transformation each time. It also hides the underlying problem, an input missing from the cache key, instead of fixing it, for example with `cacheVersion`.
  • A newly installed library with native code crashes the app, and --reset-cache does not help. Why?
    The reset only affects Metro's JavaScript caches. Native code must be compiled into the app, so the app needs a native rebuild, and on iOS usually a CocoaPods install first. No bundler cache can supply native code that is not in the binary.

A restaurant's prep fridge: pre-cooked components save time on every order, but if the recipe changed and nobody relabelled the containers, the kitchen keeps serving the old dish until someone empties the fridge and cooks fresh.

saying these in an interview costs you the question

  • --reset-cache also reinstalls node_modules
  • Resetting the cache on every start is harmless best practice
  • Metro never needs a reset because it notices every change
  • --reset-cache rebuilds native modules for the app
  • Clearing Metro's cache also clears Watchman's watches