A lightweight tool to automatically configure iOS project settings for React Native projects. Works with any React Native project (Expo, bare React Native, etc.).
When developing React Native apps for iOS, you face a frustrating cycle:
- Every
expo prebuild --cleanwipes your Xcode settings - Team ID, code signing, and other configurations are lost - Manual reconfiguration is tedious - Open Xcode, navigate to signing settings, select team, fix Info.plist values... every single time
- CI/CD pipelines become fragile - Automated builds break when Xcode settings aren't properly configured
| Solution | Limitation |
|---|---|
| EAS Build | Requires Expo account, cloud-based builds, costs money for higher tiers, overkill for simple local builds |
| Fastlane | Heavy Ruby dependency, complex setup, steep learning curve, designed for full CI/CD pipelines |
| Manual Xcode | Time-consuming, error-prone, doesn't survive prebuild, can't be automated |
| Expo Config Plugins | Only works with Expo, requires understanding plugin system, can be complex for simple tasks |
Nexjax takes a different philosophy:
- Zero dependencies - Pure Node.js, no Ruby, no cloud accounts, no external services
- Instant setup - One command:
npx nexjax YOUR_TEAM_ID - Works offline - No internet required, no accounts needed
- Universal - Works with Expo, bare React Native, or any hybrid setup
- Survives rebuilds - Stores config in
ios.config.json, reapply with single command - CI/CD friendly - Simple, predictable, easy to integrate into any pipeline
- Focused scope - Does one thing well: configure iOS project settings
- Developers who prebuild frequently and are tired of reconfiguring Xcode
- Teams who want simple, reliable iOS configuration without cloud dependencies
- CI/CD pipelines that need deterministic, offline-capable builds
- Projects that don't need full EAS/Fastlane but still want automation
- ✅ Auto-configure Team ID - Sets DEVELOPMENT_TEAM in Xcode project
- ✅ Auto-fill Version - Updates CFBundleShortVersionString from app.json (Expo) or package.json (bare RN)
- ✅ Auto-fill Build Number - Updates CFBundleVersion from app.json or config
- ✅ Auto-fill Display Name - Updates CFBundleDisplayName from app.json or package.json
- ✅ iPhone-only Support - Removes iPad orientations automatically
- ✅ Zero Dependencies - Pure Node.js, no external dependencies
- ✅ Works with any RN project - Supports both Expo (app.json) and bare React Native (package.json only)
npm install --save-dev nexjaxnpx nexjax-
Get your Team ID:
- Open Xcode → Settings → Accounts
- Select your Apple ID
- Copy your Team ID (format:
ABC123DEF4)
-
Run the tool:
npx nexjax YOUR_TEAM_ID
Or if installed locally:
npx nexjax YOUR_TEAM_ID
-
Edit
ios.config.json(created automatically):{ "teamId": "YOUR_TEAM_ID", "version": "1.0.0", "displayName": "MyApp", "buildNumber": "1", "iphoneOnly": true, "permissions": { "NSPhotoLibraryUsageDescription": "We need access to your photos...", "NSCameraUsageDescription": "We need access to your camera..." } }Note: For Expo projects, permission strings can also be set in
app.json→expo.ios.infoPlistand nexjax will automatically read them!
For Expo projects, add permissions in app.json:
{
"expo": {
"ios": {
"infoPlist": {
"NSPhotoLibraryUsageDescription": "We need access to your photos...",
"NSCameraUsageDescription": "We need access to your camera..."
}
}
}
}For bare RN projects, add permissions in ios.config.json:
{
"permissions": {
"NSPhotoLibraryUsageDescription": "We need access to your photos...",
"NSCameraUsageDescription": "We need access to your camera..."
}
}After running npx expo prebuild or any iOS build command:
npx nexjaxOr add to your build scripts in package.json:
{
"scripts": {
"ios:build": "react-native run-ios && npx nexjax",
"ios:configure": "npx nexjax"
}
}The tool creates ios.config.json in your project root with these settings:
{
"teamId": "ABC123DEF4",
"bundleIdentifier": "com.example.app",
"version": "1.0.0",
"displayName": "MyApp",
"buildNumber": "1",
"iphoneOnly": true,
"permissions": {
"NSPhotoLibraryUsageDescription": "We need access to your photos...",
"NSCameraUsageDescription": "We need access to your camera...",
"NSMicrophoneUsageDescription": "We need access to your microphone..."
}
}The tool automatically reads from configuration files:
For Expo projects (with app.json):
expo.version→ Used for CFBundleShortVersionStringexpo.name→ Used for CFBundleDisplayNameexpo.ios.buildNumber→ Used for CFBundleVersionexpo.ios.supportsTablet→ Determines iPhone-only settingexpo.ios.infoPlist.*→ Permission strings (all optional)
For bare React Native projects (package.json only):
package.json.version→ Used for CFBundleShortVersionStringpackage.json.name→ Used for CFBundleDisplayName
Nexjax can automatically configure iOS permission strings in Info.plist. Each permission is optional - only add the ones you need.
Configuration Priority:
ios.config.json→permissions(always works, overrides app.json)app.json→expo.ios.infoPlist(Expo projects only)
For Expo projects: Can use either app.json or ios.config.json (or both - ios.config.json overrides)
For bare RN projects: Use ios.config.json → permissions (no app.json available)
Supported permission keys:
NSPhotoLibraryUsageDescription- Photo library accessNSPhotoLibraryAddUsageDescription- Save photos to libraryNSCameraUsageDescription- Camera accessNSMicrophoneUsageDescription- Microphone accessNSLocationWhenInUseUsageDescription- Location when in useNSLocationAlwaysUsageDescription- Location alwaysNSContactsUsageDescription- Contacts accessNSCalendarsUsageDescription- Calendar accessNSRemindersUsageDescription- Reminders accessNSMotionUsageDescription- Motion & FitnessNSHealthShareUsageDescription- Health data readNSHealthUpdateUsageDescription- Health data writeNSBluetoothPeripheralUsageDescription- Bluetooth (deprecated, use NSBluetoothAlwaysUsageDescription)NSBluetoothAlwaysUsageDescription- Bluetooth alwaysNSSpeechRecognitionUsageDescription- Speech recognitionNSFaceIDUsageDescription- Face IDNSAppleMusicUsageDescription- Apple MusicNSSiriUsageDescription- SiriNSUserTrackingUsageDescription- App Tracking Transparency
For all settings (version, displayName, buildNumber, etc.):
ios.config.json- Primary source (can override everything)app.json(Expo) orpackage.json(bare RN) - Source of truth- Command line argument - Overrides Team ID only
For permission strings specifically:
ios.config.json→permissions- Always works (Expo & bare RN)app.json→expo.ios.infoPlist- Expo projects only (if no ios.config.json permissions)
Note:
- If
app.jsonexists, it takes priority overpackage.jsonfor version/name - If no
app.json, nexjax reads frompackage.json(bare RN projects) - Permission strings work the same way:
ios.config.jsonalways works,app.jsonis optional (Expo only)
# Configure with Team ID
npx nexjax YOUR_TEAM_ID
# Re-configure (uses saved Team ID from config)
npx nexjax{
"scripts": {
"prebuild:ios": "cd ios && pod install",
"postbuild:ios": "npx nexjax",
"rebuild:ios": "npm run prebuild:ios && npm run postbuild:ios"
}
}{
"scripts": {
"prebuild:ios": "npx expo prebuild --platform ios --clean",
"postbuild:ios": "npx nexjax",
"rebuild:ios": "npm run prebuild:ios && npm run postbuild:ios"
}
}- Updates
DEVELOPMENT_TEAMinios/*.xcodeproj/project.pbxproj - Preserves across rebuilds
- Updates
CFBundleShortVersionStringinInfo.plist - Updates
CFBundleVersioninInfo.plist
- Updates
CFBundleDisplayNameinInfo.plist
- Removes
UISupportedInterfaceOrientations~ipadfromInfo.plist - Ensures app only runs on iPhone
- Updates permission strings in
Info.plist - Reads from
app.json(Expo) orios.config.json(bare RN) - Only configures permissions that are provided (all optional)
your-project/
├── app.json ← Source of truth (version, name, buildNumber)
├── package.json
├── ios/ ← Generated by expo prebuild
│ ├── YourApp.xcodeproj/
│ │ └── project.pbxproj
│ └── YourApp/
│ └── Info.plist
└── ios.config.json ← Created automatically (Team ID, overrides)
your-project/
├── package.json ← Source of truth (version, name)
├── ios/
│ ├── YourApp.xcodeproj/
│ │ └── project.pbxproj
│ └── YourApp/
│ └── Info.plist
└── ios.config.json ← Created automatically (Team ID, buildNumber, overrides)
- Make sure you're in the React Native project root
- Run from the directory containing
ios/folder
- Make sure you've built the iOS project at least once
- For Expo: Run
npx expo prebuild --platform iosfirst
- The tool will search for Info.plist automatically
- If not found, Team ID configuration will still work
- Make sure
ios.config.jsonhasteamIdset - Run the tool again after rebuilding iOS project
const { configureIOS } = require('nexjax');
// Configure with Team ID
await configureIOS('/path/to/project', 'YOUR_TEAM_ID');
// Re-configure (uses config file)
await configureIOS('/path/to/project');MIT
Contributions welcome! This is a simple tool designed to be lightweight and dependency-free.