Migration Guide
Migrating from react-native-device-info to react-native-nitro-device-info.
Overview
React Native Nitro Device Info maintains 80% API compatibility with react-native-device-info while delivering superior performance through JSI. Most code can be migrated with minimal changes.
Key Differences
1. Import Changes
Before (react-native-device-info):
import DeviceInfo from 'react-native-device-info';
After (react-native-nitro-device-info):
import { DeviceInfoModule } from 'react-native-nitro-device-info';
2. Module Name
The module is now called DeviceInfoModule instead of DeviceInfo:
// Before
DeviceInfo.getBrand();
// After
DeviceInfoModule.getBrand();
3. Properties vs Methods
Most methods are now direct property accessors for instant synchronous access:
Before:
const deviceId = DeviceInfo.getDeviceId(); // Method call
const brand = DeviceInfo.getBrand(); // Method call
const model = DeviceInfo.getModel(); // Method call
After:
const deviceId = DeviceInfoModule.deviceId; // Property access
const brand = DeviceInfoModule.brand; // Property access
const model = DeviceInfoModule.model; // Property access
4. Synchronous by Default
Most properties are now synchronous for instant access (<1ms):
Before (everything async or method-based):
const uniqueId = await DeviceInfo.getUniqueId(); // Async
const totalMemory = await DeviceInfo.getTotalMemory(); // Async
const batteryLevel = await DeviceInfo.getBatteryLevel(); // Async
const isTablet = DeviceInfo.isTablet(); // Sync method
After (most properties synchronous):
const uniqueId = DeviceInfoModule.uniqueId; // Sync property now!
const totalMemory = DeviceInfoModule.totalMemory; // Sync property now!
const batteryLevel = DeviceInfoModule.getBatteryLevel(); // Sync method now!
const isTablet = DeviceInfoModule.isTablet; // Sync property
5. Only I/O Operations Are Async
Network and file I/O operations remain asynchronous:
// Still async - requires I/O
const ipAddress = await DeviceInfoModule.getIpAddress();
const carrier = await DeviceInfoModule.getCarrier();
const installTime = await DeviceInfoModule.getFirstInstallTime();
6. Architecture Difference
- react-native-device-info: Uses TurboModule/Bridge (JSON serialization)
react-native-nitro-device-info: Uses Nitro HybridObject (JSI, zero overhead)
Quick Migration Reference
Device Information
| react-native-device-info |
react-native-nitro-device-info |
Notes |
DeviceInfo.getDeviceId() |
DeviceInfoModule.deviceId |
Now a property |
DeviceInfo.getBrand() |
DeviceInfoModule.brand |
Now a property |
DeviceInfo.getModel() |
DeviceInfoModule.model |
Now a property |
DeviceInfo.getSystemName() |
DeviceInfoModule.systemName |
Now a property |
DeviceInfo.getSystemVersion() |
DeviceInfoModule.systemVersion |
Now a property |
await DeviceInfo.getUniqueId() |
DeviceInfoModule.uniqueId |
Now sync property |
DeviceInfo.getManufacturer() |
DeviceInfoModule.manufacturer |
Now property |
DeviceInfo.isTablet() |
DeviceInfoModule.isTablet |
Now property |
System Resources
| react-native-device-info |
react-native-nitro-device-info |
Notes |
await DeviceInfo.getTotalMemory() |
DeviceInfoModule.totalMemory |
Now sync property |
await DeviceInfo.getUsedMemory() |
DeviceInfoModule.getUsedMemory() |
Now sync method |
await DeviceInfo.getTotalDiskCapacity() |
DeviceInfoModule.totalDiskCapacity |
Now sync property |
await DeviceInfo.getFreeDiskStorage() |
DeviceInfoModule.getFreeDiskStorage() |
Now sync method |
Battery Information
| react-native-device-info |
react-native-nitro-device-info |
Notes |
await DeviceInfo.getBatteryLevel() |
DeviceInfoModule.getBatteryLevel() |
Now sync method |
await DeviceInfo.getPowerState() |
DeviceInfoModule.getPowerState() |
Now sync method |
await DeviceInfo.isBatteryCharging() |
DeviceInfoModule.getIsBatteryCharging() |
Now sync method |
Application Metadata
| react-native-device-info |
react-native-nitro-device-info |
Notes |
DeviceInfo.getVersion() |
DeviceInfoModule.version |
Now property |
DeviceInfo.getBuildNumber() |
DeviceInfoModule.buildNumber |
Now property |
DeviceInfo.getBundleId() |
DeviceInfoModule.bundleId |
Now property |
DeviceInfo.getApplicationName() |
DeviceInfoModule.applicationName |
Now property |
DeviceInfo.getReadableVersion() |
DeviceInfoModule.readableVersion |
Now a property |
Network & Connectivity
| react-native-device-info |
react-native-nitro-device-info |
Notes |
await DeviceInfo.getIpAddress() |
await DeviceInfoModule.getIpAddress() |
Still async (I/O) |
await DeviceInfo.getMacAddress() |
await DeviceInfoModule.getMacAddress() |
Still async (I/O) |
await DeviceInfo.getCarrier() |
await DeviceInfoModule.getCarrier() |
Still async (I/O) |
await DeviceInfo.isLocationEnabled() |
await DeviceInfoModule.isLocationEnabled() |
Still async (I/O) |
Step-by-Step Migration
1. Install the New Library
# Remove old library
npm uninstall react-native-device-info
# Install new library
npm install react-native-nitro-device-info react-native-nitro-modules
# iOS
cd ios && pod install && cd ..
2. Update Imports
Find and replace imports across your codebase:
// Before
import DeviceInfo from 'react-native-device-info';
// After
import { DeviceInfoModule } from 'react-native-nitro-device-info';
3. Update Module Name
Replace all DeviceInfo references with DeviceInfoModule:
// Before
const brand = DeviceInfo.getBrand();
// After
const brand = DeviceInfoModule.brand; // Also changed to property
4. Convert Method Calls to Properties
Update method calls that are now properties:
// Before
const deviceId = DeviceInfo.getDeviceId();
const brand = DeviceInfo.getBrand();
const model = DeviceInfo.getModel();
const systemName = DeviceInfo.getSystemName();
const systemVersion = DeviceInfo.getSystemVersion();
const readableVersion = DeviceInfo.getReadableVersion();
// After
const deviceId = DeviceInfoModule.deviceId;
const brand = DeviceInfoModule.brand;
const model = DeviceInfoModule.model;
const systemName = DeviceInfoModule.systemName;
const systemVersion = DeviceInfoModule.systemVersion;
const readableVersion = DeviceInfoModule.readableVersion;
5. Remove Unnecessary await Keywords
Remove await from methods that are now synchronous:
// Before
const uniqueId = await DeviceInfo.getUniqueId();
const totalMemory = await DeviceInfo.getTotalMemory();
const batteryLevel = await DeviceInfo.getBatteryLevel();
// After (no await needed, now sync properties/methods)
const uniqueId = DeviceInfoModule.uniqueId;
const totalMemory = DeviceInfoModule.totalMemory;
const batteryLevel = DeviceInfoModule.getBatteryLevel();
6. Test Your Changes
Run your app and verify:
- All device info calls work correctly
- No runtime errors from async/sync changes
- TypeScript types are correct
Complete Example
Before (react-native-device-info)
import React, { useEffect, useState } from 'react';
import DeviceInfo from 'react-native-device-info';
function DeviceInfoScreen() {
const [deviceId, setDeviceId] = useState('');
const [brand, setBrand] = useState('');
const [uniqueId, setUniqueId] = useState('');
const [totalMemory, setTotalMemory] = useState(0);
const [batteryLevel, setBatteryLevel] = useState(0);
const [ipAddress, setIpAddress] = useState('');
useEffect(() => {
async function loadDeviceInfo() {
// Everything was async or method-based
const id = DeviceInfo.getDeviceId();
const b = DeviceInfo.getBrand();
const uid = await DeviceInfo.getUniqueId();
const mem = await DeviceInfo.getTotalMemory();
const bat = await DeviceInfo.getBatteryLevel();
const ip = await DeviceInfo.getIpAddress();
setDeviceId(id);
setBrand(b);
setUniqueId(uid);
setTotalMemory(mem);
setBatteryLevel(bat);
setIpAddress(ip);
}
loadDeviceInfo();
}, []);
return (
<View>
<Text>Device: {brand} {deviceId}</Text>
<Text>Unique ID: {uniqueId}</Text>
<Text>Memory: {totalMemory}</Text>
<Text>Battery: {(batteryLevel * 100).toFixed(0)}%</Text>
<Text>IP: {ipAddress}</Text>
</View>
);
}
After (react-native-nitro-device-info)
import React, { useEffect, useState } from 'react';
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function DeviceInfoScreen() {
const [ipAddress, setIpAddress] = useState('');
// Sync properties/methods - instant access, no state needed
const deviceId = DeviceInfoModule.deviceId;
const brand = DeviceInfoModule.brand;
const uniqueId = DeviceInfoModule.uniqueId;
const totalMemory = DeviceInfoModule.totalMemory;
const batteryLevel = DeviceInfoModule.getBatteryLevel();
useEffect(() => {
// Only async operations need useEffect
DeviceInfoModule.getIpAddress().then(setIpAddress);
}, []);
return (
<View>
<Text>Device: {brand} {deviceId}</Text>
<Text>Unique ID: {uniqueId}</Text>
<Text>Memory: {totalMemory}</Text>
<Text>Battery: {(batteryLevel * 100).toFixed(0)}%</Text>
<Text>IP: {ipAddress}</Text>
</View>
);
}
Benefits of Migration
1. Performance Improvement
// Old: ~5-10ms per call (async + bridge serialization)
const brand = await DeviceInfo.getBrand();
const model = await DeviceInfo.getModel();
const memory = await DeviceInfo.getTotalMemory();
// New: <1ms total (synchronous properties + JSI)
const brand = DeviceInfoModule.brand;
const model = DeviceInfoModule.model;
const memory = DeviceInfoModule.totalMemory;
2. Simpler Code
No need for async/await for simple getters:
// Old - required async function
async function getDeviceInfo() {
const brand = await DeviceInfo.getBrand();
const model = await DeviceInfo.getModel();
return `${brand} ${model}`;
}
// New - direct access
function getDeviceInfo() {
return `${DeviceInfoModule.brand} ${DeviceInfoModule.model}`;
}
3. Better TypeScript Support
Full type definitions with excellent IntelliSense:
import type { PowerState, BatteryState } from 'react-native-nitro-device-info';
const powerState: PowerState = DeviceInfoModule.getPowerState();
// TypeScript knows: powerState.batteryLevel, powerState.batteryState, powerState.lowPowerMode
4. Future-Proof Architecture
Built on React Native's New Architecture (Fabric + JSI) for long-term support.
React Hooks Migration
React hooks work as drop-in replacements with identical APIs:
Hook Migration Table
| react-native-device-info |
react-native-nitro-device-info |
Notes |
useBatteryLevel() |
useBatteryLevel() |
Identical |
useBatteryLevelIsLow() |
useBatteryLevelIsLow() |
Identical |
usePowerState() |
usePowerState() |
Identical |
useIsHeadphonesConnected() |
useIsHeadphonesConnected() |
Identical |
useIsWiredHeadphonesConnected() |
useIsWiredHeadphonesConnected() |
Identical |
useIsBluetoothHeadphonesConnected() |
useIsBluetoothHeadphonesConnected() |
Identical |
useBrightness() |
useBrightness() |
Identical |
Hook Migration Example
// Before (react-native-device-info)
import { useBatteryLevel, usePowerState } from 'react-native-device-info';
// After (react-native-nitro-device-info)
import { useBatteryLevel, usePowerState } from 'react-native-nitro-device-info';
// Usage remains exactly the same
function BatteryWidget() {
const batteryLevel = useBatteryLevel();
const powerState = usePowerState();
return (
<View>
<Text>Battery: {batteryLevel !== null ? `${Math.round(batteryLevel * 100)}%` : 'Loading...'}</Text>
<Text>State: {powerState.batteryState}</Text>
</View>
);
}
See the React Hooks Guide for detailed hook documentation.
Breaking Changes
Removed Methods
These methods from react-native-device-info are not available:
- Some niche Android-only methods may have different names
- Event listeners for battery/network state changes are not available. Use the provided React hooks (e.g.,
useBatteryLevel, usePowerState) for reactive state monitoring instead.
Behavioral Changes
- Synchronous by default: Most methods no longer return Promises
- Property accessors: Some getters are now properties
- Module name: Must use
DeviceInfoModule instead of DeviceInfo
Troubleshooting
TypeScript Errors After Migration
If you see type errors after migration:
# Clear TypeScript cache
rm -rf node_modules/.cache
yarn install
# Restart TypeScript server in your IDE
Runtime Errors
If you get "Cannot read property" errors:
- Ensure
react-native-nitro-modules is installed as peer dependency
- Run
pod install on iOS
- Clean build (
yarn android / yarn ios with clean)
Missing Methods
If a method is not available:
- Check the API Reference for the correct method name
- Some methods may have been renamed or consolidated
- Open an issue on GitHub if you need a specific method
Migrating from expo-device
If you're migrating from expo-device, many APIs have compatible alternatives in react-native-nitro-device-info.
Key Differences
| Aspect |
expo-device |
react-native-nitro-device-info |
| Architecture |
Expo Module API |
Nitro Modules (JSI) |
| Sync/Async |
Mixed (some async) |
Mostly synchronous |
| Expo Dependency |
Requires Expo |
Works with bare React Native |
| Performance |
Good |
Excellent (<1ms for sync APIs) |
API Migration Reference
| expo-device |
react-native-nitro-device-info |
Notes |
Device.brand |
DeviceInfoModule.brand |
Same |
Device.manufacturer |
DeviceInfoModule.manufacturer |
Same |
Device.modelName |
DeviceInfoModule.model |
Different property name |
Device.modelId |
DeviceInfoModule.deviceId |
Different property name |
Device.designName |
DeviceInfoModule.device |
Android only |
Device.productName |
DeviceInfoModule.product |
Android only |
Device.deviceYearClass |
DeviceInfoModule.deviceYearClass |
Same |
Device.totalMemory |
DeviceInfoModule.totalMemory |
Same |
Device.supportedCpuArchitectures |
DeviceInfoModule.supportedAbis |
Android only |
Device.osName |
DeviceInfoModule.systemName |
Different property name |
Device.osVersion |
DeviceInfoModule.systemVersion |
Different property name |
Device.osBuildId |
DeviceInfoModule.display |
Android only |
Device.osInternalBuildId |
DeviceInfoModule.fingerprint |
Android only |
Device.osBuildFingerprint |
DeviceInfoModule.fingerprint |
Android only |
Device.platformApiLevel |
DeviceInfoModule.apiLevel |
Android only |
Device.deviceName |
DeviceInfoModule.deviceName |
Same |
Device.DeviceType |
DeviceInfoModule.deviceType |
Returns string enum |
Device.getDeviceTypeAsync() |
DeviceInfoModule.deviceType |
Now sync |
Device.getUptimeAsync() |
DeviceInfoModule.getUptime() |
Now sync, returns ms |
Device.isRootedExperimentalAsync() |
DeviceInfoModule.isDeviceCompromised() |
Sync, broader detection |
Device.isSideLoadingEnabledAsync() |
DeviceInfoModule.isSideLoadingEnabled() |
Now sync, Android only |
Migration Example
Before (expo-device):
import * as Device from 'expo-device';
async function getDeviceInfo() {
const deviceType = await Device.getDeviceTypeAsync();
const uptime = await Device.getUptimeAsync();
const isRooted = await Device.isRootedExperimentalAsync();
const canSideload = await Device.isSideLoadingEnabledAsync();
return {
brand: Device.brand,
model: Device.modelName,
yearClass: Device.deviceYearClass,
totalMemory: Device.totalMemory,
deviceType,
uptime,
isRooted,
canSideload,
};
}
After (react-native-nitro-device-info):
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function getDeviceInfo() {
// All synchronous - no async/await needed!
return {
brand: DeviceInfoModule.brand,
model: DeviceInfoModule.model,
yearClass: DeviceInfoModule.deviceYearClass,
totalMemory: DeviceInfoModule.totalMemory,
deviceType: DeviceInfoModule.deviceType,
uptime: DeviceInfoModule.getUptime(),
isRooted: DeviceInfoModule.isDeviceCompromised(),
canSideload: DeviceInfoModule.isSideLoadingEnabled(),
};
}
APIs Not Available
These expo-device APIs do not have direct equivalents:
| expo-device API |
Alternative |
Device.isDevice |
Use !DeviceInfoModule.isEmulator |
Device.getPlatformFeaturesAsync() |
Not available |
Platform-Specific Considerations
Uptime Behavior
- expo-device: Returns uptime in milliseconds (excludes deep sleep)
- react-native-nitro-device-info: Returns uptime in milliseconds (excludes deep sleep)
- iOS: Uses
systemUptime
- Android: Uses
uptimeMillis()
- Both platforms return consistent "active time" matching expo-device behavior
Device Year Class
Both libraries use the same Facebook algorithm for calculating device year class based on RAM and CPU specifications. The year class represents an estimated year that the device's hardware was considered high-end.
Root/Jailbreak Detection
- expo-device:
isRootedExperimentalAsync() - Experimental, basic checks
- react-native-nitro-device-info:
isDeviceCompromised() - Comprehensive detection
- Android: Checks su binaries, root apps, system properties, test-keys
- iOS: Checks Cydia, jailbreak files, sandbox escape, suspicious paths
Migrating from react-native-carrier-info
If you're using react-native-carrier-info for carrier information, you can consolidate into react-native-nitro-device-info.
API Migration Reference
| react-native-carrier-info |
react-native-nitro-device-info |
Notes |
await CarrierInfo.allowsVOIP() |
DeviceInfoModule.carrierAllowsVOIP |
Now sync property |
await CarrierInfo.carrierName() |
DeviceInfoModule.getCarrierSync() |
Now sync method |
await CarrierInfo.isoCountryCode() |
DeviceInfoModule.carrierIsoCountryCode |
Now sync property |
await CarrierInfo.mobileCountryCode() |
DeviceInfoModule.mobileCountryCode |
Now sync property |
await CarrierInfo.mobileNetworkCode() |
DeviceInfoModule.mobileNetworkCode |
Now sync property |
await CarrierInfo.mobileNetworkOperator() |
DeviceInfoModule.mobileNetworkOperator |
Now sync property |
Migration Example
Before (react-native-carrier-info):
import CarrierInfo from 'react-native-carrier-info';
async function getCarrierDetails() {
const carrierName = await CarrierInfo.carrierName();
const allowsVOIP = await CarrierInfo.allowsVOIP();
const isoCountryCode = await CarrierInfo.isoCountryCode();
const mcc = await CarrierInfo.mobileCountryCode();
const mnc = await CarrierInfo.mobileNetworkCode();
const operator = await CarrierInfo.mobileNetworkOperator();
return { carrierName, allowsVOIP, isoCountryCode, mcc, mnc, operator };
}
After (react-native-nitro-device-info):
import { DeviceInfoModule } from 'react-native-nitro-device-info';
function getCarrierDetails() {
// All synchronous - no async/await needed!
return {
carrierName: DeviceInfoModule.getCarrierSync(),
allowsVOIP: DeviceInfoModule.carrierAllowsVOIP,
isoCountryCode: DeviceInfoModule.carrierIsoCountryCode,
mcc: DeviceInfoModule.mobileCountryCode,
mnc: DeviceInfoModule.mobileNetworkCode,
operator: DeviceInfoModule.mobileNetworkOperator,
};
}
Key Benefits
- No async/await: All carrier properties are synchronous
- Single dependency: No need to install separate carrier-info package
- JSI performance: Zero-overhead native access via Nitro Modules
- Unified API: Carrier info alongside 80+ other device properties
Platform Notes
- iOS: Uses
CTTelephonyNetworkInfo and CTCarrier APIs
- Android: Uses
TelephonyManager APIs
- carrierAllowsVOIP: Returns actual value on iOS, always
true on Android (no equivalent API)
- Empty strings: All properties return
"" when no SIM card is present
Need Help?