Using Third-Party Native Libraries
A cookbook for evaluating, installing, and verifying community native libraries in an Expo SDK 57 CNG app - with explicit checks for prebuild survivability and New Architecture compatibility on React Native 0.86.
Search across all documentation pages
A cookbook for evaluating, installing, and verifying community native libraries in an Expo SDK 57 CNG app - with explicit checks for prebuild survivability and New Architecture compatibility on React Native 0.86.
Quick-reference recipe card - copy-paste ready.
# 1. Evaluate BEFORE install (see checklist below)
# 2. Install with Expo's resolver - not bare npm
npx expo install react-native-maps
# 3. Register config plugin in app.config.ts (if the library ships one)
# 4. Regenerate native projects and verify
npx expo prebuild --clean
npx expo-doctor
# 5. Build a development client - third-party native code is NOT in Expo Go
npx expo install expo-dev-client
npx expo run:ios
# or: eas build --profile development --platform all// app.config.ts - typical third-party plugin registration
import type { ExpoConfig } from "expo/config";
export default ({ config }: { config: ExpoConfig }): ExpoConfig => ({
...config,
plugins: [
[
"react-native-maps",
{
iosGoogleMapsApiKey: process.env.GOOGLE_MAPS_IOS_KEY,
androidGoogleMapsApiKey: process.env.GOOGLE_MAPS_ANDROID_KEY,
},
],
],
});When to reach for this:
react-native-maps, react-native-ble-plx, react-native-purchases, or any npm package with ios/ / android/ folders.npx expo prebuild --clean in a CNG workflow.| Check | Pass criteria | Fail action |
|---|---|---|
| Expo SDK 57 / RN 0.86 | README or issues mention 0.86+ | Open issue or fork; do not ship |
| New Architecture | newArchEnabled issue closed or docs claim TurboModule/Fabric | Test on device; reject if redbox on launch |
| Config plugin | Ships app.plugin.js or documents expo config plugin | Plan a custom plugin - see Config Plugins |
npx expo install | Package listed in Expo ecosystem or install succeeds | Pin version manually with ADR |
| Expo Go | N/A - assume not in Expo Go | Add expo-dev-client to project |
| Maintenance | Commit within last 12 months | Prefer Expo SDK alternative |
#!/usr/bin/env bash
# scripts/verify-native-dep.sh - run after adding a native library
set -euo pipefail
PKG="${1:?Usage: ./verify-native-dep.sh <package-name>}"
echo "▶ Installing $PKG via expo install..."
npx expo install "$PKG"
echo "▶ Running expo-doctor..."
npx expo-doctor
echo "▶ Resolving autolinking (iOS)..."
npx expo-modules-autolinking resolve --platform ios | grep -i "${PKG##*/}" || true
echo "▶ Clean prebuild dry run..."
npx expo prebuild --clean --no-install
echo "✅ $PKG passed local verification - still build on device"react-native-mapsnpx create-expo-app@latest MapsCookbook --template blank-typescript@sdk-57 --yes
cd MapsCookbook
npx expo install expo-dev-client react-native-maps// app.config.ts
import type { ExpoConfig } from "expo/config";
const defineConfig = ({ config }: { config: ExpoConfig }): ExpoConfig => ({
...config,
name: "MapsCookbook",
slug: "maps-cookbook",
plugins: [
[
"react-native-maps",
{
iosGoogleMapsApiKey: process.env.GOOGLE_MAPS_IOS_KEY ?? "",
androidGoogleMapsApiKey: process.env.GOOGLE_MAPS_ANDROID_KEY ?? "",
},
],
],
});
export default defineConfig;// App.tsx
import MapView, { Marker } from "react-native-maps";
import { StyleSheet, View } from "react-native";
export default function App() {
return (
<View style={styles.container}>
<MapView
style={styles.map}
initialRegion={{
latitude: 37.78825,
longitude: -122.4324,
latitudeDelta: 0.0922,
longitudeDelta: 0.0421,
}}
>
<Marker
coordinate={{ latitude: 37.78825, longitude: -122.4324 }}
title="San Francisco"
/>
</MapView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
map: { flex: 1 },
});# Regenerate native dirs and run on simulator
npx expo prebuild
npx expo run:ios
# Start Metro for the dev client (not Expo Go)
npx expo start --dev-clientWhat this demonstrates:
npx expo install resolves a version compatible with SDK 57 native binaries.Info.plist and AndroidManifest.xml during prebuild.expo prebuild wires autolinking - no manual Podfile edits in CNG apps.react-native-maps is not bundled in Expo Go.React Native 0.86 defaults to New Architecture (Fabric + TurboModules). Third-party libraries fall into three buckets:
| Bucket | Symptom | Mitigation |
|---|---|---|
| Fully compatible | Builds and runs on device | Ship |
| Partial (bridge fallback) | Builds but sync JSI APIs fail | Test every API you call; open upstream issue |
| Incompatible | Compile error or instant crash | Do not adopt; find alternative or fork |
# Confirm New Architecture in generated project
grep -r "newArchEnabled" android/ ios/ 2>/dev/null || true
# Force-verify with a release build on device (not just debug Metro)
npx expo run:ios --configuration ReleaseLibraries using old NativeModules bridge only may still run via interoperability layer, but performance-sensitive paths (maps, video, BLE) should be validated on physical hardware - simulators hide threading bugs.
In Continuous Native Generation apps, ios/ and android/ are outputs of config, not source of truth:
package.json + app.config.ts + plugins
│
▼
npx expo prebuild
│
▼
ios/ android/ (generated)
│
▼
npx expo run:ios / eas build
Never document "add this line to AndroidManifest.xml" as a permanent step - encode it in a config plugin so regeneration stays clean. See Prebuild Basics and Config Plugins in CNG.
| Need | Prefer Expo SDK | Third-party when |
|---|---|---|
| Camera | expo-camera | Vendor SDK requires proprietary binary |
| Location | expo-location | Background BLE geofencing with hardware SDK |
| Maps | expo-maps (if fits) | Google Maps SDK features not exposed |
| Payments | expo-in-app-purchases / Stripe RN | Store-specific native SDK mandate |
Follow Native Module Rules Tier 1 before every third-party install.
# List modules that will compile into the binary
npx expo-modules-autolinking resolve --platform ios
npx expo-modules-autolinking resolve --platform android
# React Native community autolinking (non-Expo packages)
npx react-native configIf a package appears in package.json but not in resolve output, the native build never compiled it - requireNativeModule will throw at runtime.
npm install - third-party native code is absent from the Go binary. Fix: npx expo start --dev-client with a custom build.prebuild after plugin config change - stale Info.plist entries. Fix: npx expo prebuild --clean locally before merge.@latest on native packages - breaks SDK 57 ABI alignment. Fix: npx expo install or explicit version with ADR.| Alternative | Use When | Don't Use When |
|---|---|---|
| Expo SDK module | Feature exists in SDK 57 | Proprietary vendor mandates custom SDK |
| Config plugin + third-party | Community lib has plugin and RN 0.86 support | Unmaintained, no New Arch path |
| Local Expo module | Thin bridge to vendor SDK | Full SDK surface - still need native code |
| WebView + hosted UI | Vendor offers web-only integration | Offline, performance, or store policy blocks WebView |
Only if it supports prebuild/autolinking, has a config plugin (or you write one), and compiles on RN 0.86 New Architecture. npx expo-doctor catches common failures early.
Team policy varies. CNG teams often gitignore native dirs and regenerate in CI. If you commit them, still express changes via plugins - not manual drift. See CNG best practices.
npx expo run:ios --configuration Release on a physical device with the library's primary user flow. Debug Metro can mask native threading issues.
Write a local plugin in plugins/ or choose a maintained fork. Post-prebuild manual edits are technical debt in CNG apps.
npx expo install reads Expo's compatibility table for SDK 57. npm install may resolve JS that does not match native binaries in your build.
Stack versions: This page was written for React 19.2.3, React Native 0.86.0, and Expo SDK 57 (
expo~57.0.4).
Reviewed by Chris St. John·Last updated Jul 19, 2026