Using Expo Development Builds to Run Custom Native Modules in React Native
Learn how to replace Expo Go with a custom development client that supports any native library, using config plugins and EAS builds.
21 Dec 2025, 05:14 UTC

The problem: Expo Go blocks custom native code
When a React Native project needs a library that touches native code—for example, a Bluetooth peripheral scanner or a custom video codec—the standard Expo Go client cannot run it. Expo Go ships with a fixed set of native modules, so any attempt to import a library that requires linking fails at runtime or during the prebuild step.
Thesis: Development Builds give you a customizable client that keeps the Expo developer experience
By creating a development build with expo-dev-client, you generate your own binary that can include arbitrary native code while preserving fast‑refresh, the developer menu, and over‑the‑air JS updates. This lets you work with any native module without leaving the Expo workflow.
How Development Builds work
The core pieces are:
- expo-dev-client: a library that replaces the Expo Go runtime in your project, enabling the same dev‑client UI.
- Config Plugins: JavaScript functions that automatically edit
Info.plist,AndroidManifest.xml, Gradle files, etc., during theexpo prebuildstep. - EAS or local native tooling: the build step that produces a custom APK/IPA which you install on a device or emulator.
Because the native project is generated from your config, you never need to manually edit the ios/ or android/ folders; the plugins keep them in sync.
Worked example: adding a Bluetooth library
Suppose you want to use react-native-ble-plx, which requires native Bluetooth permissions and linking.
Install the dev client and the library:
# Run in the project root npx expo install expo-dev-client npx expo install react-native-ble-plxYou need read/write access to the project directory; no special OS privileges are required.
Add a config plugin for the library (many libraries ship one; if not, you can create a simple plugin).
// expo.plugins.js module.exports = function ({ config }) { return { ...config, plugins: [ ...(config.plugins ?? []), ['react-native-ble-plx', { /* optional options */ }], ], }; };Prebuild the native projects:
npx expo prebuild --cleanThis step reads the config plugin and generates
ios/andandroid/folders. If you see errors here, they are usually due to missing version conflicts in the plugin; inspect the plugin’s README for required Expo SDK versions.Build the development client. You can use Android Studio/Xcode locally or EAS in the cloud.
# Local Android build (requires Android Studio and JDK 11+) npx expo run:android # Local iOS build (requires Xcode 15+ and macOS) npx expo run:iosExpected check: the command finishes with a success message and installs the app on the connected device/emulator. You should see the Expo developer menu when you shake the device or press Cmd+D (iOS) / Ctrl+M (Android).
Verify the native module works.
import { BleManager } from 'react-native-ble-plx'; const manager = new BleManager(); manager.start({ showAlert: false }); // If no exception is thrown, the native code is linked correctly.Run the app; if the Bluetooth manager initializes without error, the development build successfully includes the native library. The same code would fail in Expo Go with an error like "Native module cannot be null".
Trade‑off and limitation
The main trade‑off is rebuild latency. Any change to native code or to a config plugin requires a new binary build; JS‑only changes still benefit from fast‑refresh. This means you must weigh the frequency of native edits against the time spent waiting for EAS or local builds.
Practical way to check the result: after a native change, rerun the build command and launch the app. If the dev menu appears and your native module initializes without errors, the rebuild succeeded.
Actionable closing
If your project needs a library that Expo Go cannot provide, start by installing expo-dev-client, add any required config plugins, run npx expo prebuild, and produce a development client via EAS or your local IDE. Keep the JS workflow unchanged for rapid iteration, and rebuild only when you touch native code. This approach gives you the best of both worlds: the convenience of Expo’s developer tools and the freedom to use any native module.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.