Note: Make sure you have completed the React Native environment setup before testing this project.
This guide explains how to configure multiple environments (Staging and Production) in a React Native project. It supports environment-specific builds and configurations for both Android (using flavors) and iOS (using targets). Additionally, it demonstrates how to use environment variables natively in both platforms.
- Overview
- Prerequisites
- Environment-Specific Configuration Using
react-native-config
- Android Setup (Flavors)
- iOS Setup (Targets)
- Helpful Scripts for Building and Running Apps
- Using Environment Variables in Native Code
- Switching Between Environments
- References
- Test and build distinct app versions for staging and production.
- Use environment-specific configurations (e.g., API endpoints, Firebase configurations, feature flags).
- Streamline debugging and deployment workflows.
- React Native project initialized:
npx react-native init MyProject
- Install
react-native-config
for managing environment variables:npm install react-native-config
-
Create separate
.env
files for each environment:.env.staging
.env.production
Example content for
.env.staging
:API_URL=https://staging.api.myapp.com APP_NAME=MyApp Staging BUNDLE_IDENTIFIER=com.myapp.staging
-
Add
.env
files to.gitignore
:.env*
-
Verify
react-native-config
integration:import Config from 'react-native-config'; console.log(Config.API_URL); // Logs API URL from selected .env file
-
Define Flavors in
android/app/build.gradle
: Use the following configuration:flavorDimensions "environment" productFlavors { staging { applicationId project.env.BUNDLE_IDENTIFIER dimension "environment" applicationIdSuffix ".staging" versionNameSuffix "-staging" resValue "string", "build_config_package", project.env.BUNDLE_IDENTIFIER resValue "string", "app_name", project.env.APP_NAME } production { applicationId project.env.BUNDLE_IDENTIFIER dimension "environment" versionNameSuffix "-production" resValue "string", "build_config_package", project.env.BUNDLE_IDENTIFIER resValue "string", "app_name", project.env.APP_NAME } }
-
Build and Run with Flavors: Use the
--mode
flag:# Staging npx react-native run-android --mode stagingDebug # Production npx react-native run-android --mode productionDebug
- Duplicate your main app target for each environment:
MyApp-Staging
MyApp-Production
.
To do this, in Xcode:
- Open your project.
- Right-click your main target under the Targets section and select Duplicate.
- Rename the duplicated target appropriately (e.g.,
MyApp-Staging
andMyApp-Production
).
- Go to Product > Scheme > Manage Schemes.
- Create schemes for
MyApp-Staging
andMyApp-Production
. - Assign the correct target to each scheme (e.g.,
MyApp-Staging
for the Staging scheme).
-
For each target (e.g.,
MyApp-Staging
,MyApp-Production
), you will need a separateInfo.plist
file. -
Duplicate your main
Info.plist
file and rename them according to the environment:Info-Staging.plist
Info-Production.plist
-
Assign the correct
Info.plist
to each target in Xcode:- Select the target (e.g.,
MyApp-Staging
). - Go to the Build Settings tab.
- Search for Info.plist File.
- Set the Info.plist File path to the correct file for each target:
MyApp-Staging/Info-Staging.plist
MyApp-Production/Info-Production.plist
- Select the target (e.g.,
This way, each environment will use its respective configuration, such as app name, bundle identifier, and Firebase configuration.
In each Info.plist
file, you can configure environment-specific settings like API_URL
, Firebase keys, app version, etc., specific to the target.
For example:
-
Info-Staging.plist:
<key>API_URL</key> <string>https://staging.api.myapp.com</string> <key>FIREBASE_CONFIG</key> <string>google-services-staging.json</string>
-
Info-Production.plist:
<key>API_URL</key> <string>https://api.myapp.com</string> <key>FIREBASE_CONFIG</key> <string>google-services-production.json</string>
To run the app with the desired environment, specify the scheme for the correct target:
# Staging
ENVFILE=.env.staging react-native run-ios --scheme MyApp-Staging
# Production
ENVFILE=.env.production react-native run-ios --scheme MyApp-Production
When building with a specific target, the corresponding Info.plist
file (e.g., Info-Staging.plist
or Info-Production.plist
) will be used, ensuring that each environment has its own configuration.
Add the following scripts to your project's package.json
under the scripts
section for easy environment-specific builds:
"scripts": {
"ios:stag:run": "npm run clean && ENVFILE=.env.staging XCODE_BUILD_CONFIGURATION=Debug react-native run-ios --scheme CustomENVRN-Staging",
"ios:prod:run": "npm run clean && ENVFILE=.env.production XCODE_BUILD_CONFIGURATION=Debug react-native run-ios --scheme CustomENVRN-Production",
"ios:stag:build": "ENVFILE=.env.staging xcodebuild -workspace CustomENVRN.xcworkspace -scheme CustomENVRN-Staging -configuration Debug -sdk iphoneos -derivedDataPath ios/build",
"ios:prod:build": "ENVFILE=.env.production xcodebuild -workspace CustomENVRN.xcworkspace -scheme CustomENVRN-Production -configuration Debug -sdk iphoneos -derivedDataPath ios/build",
"android:stag:run:release": "ENVFILE=.env.staging react-native run-android --mode=stagingRelease --appIdSuffix=staging",
"android:prod:run:release": "ENVFILE=.env.production react-native run-android --mode=productionRelease",
"android:stag:build": "ENVFILE=.env.staging cd android && ./gradlew assembleStagingRelease",
"android:prod:build": "ENVFILE=.env.production cd android && ./gradlew assembleProductionRelease",
"clean": "cd android && ./gradlew clean && cd ../ios && rm -rf build && rm -rf ~/Library/Developer/Xcode/DerivedData && xcodebuild clean && pod install --repo-update && cd ..",
"install": "npm install && cd ios && pod install && cd ..",
"reset": "rm -rf node_modules && rm -rf ios/build && npm run clean && npm install"
}
These scripts streamline building and running your app for specific environments.
-
Access variables in native Java/Kotlin code:
import com.myapp.BuildConfig; String apiUrl = BuildConfig.API_URL;
-
Ensure variables are added in
android/app/build.gradle
underresValue
:resValue "string", "API_URL", project.env.API_URL
-
Access variables in native Objective-C/Swift code:
if let apiUrl = Bundle.main.infoDictionary?["API_URL"] as? String { print("API URL: \(apiUrl)") }
-
Add variables to the
.xcconfig
files for each target:We can follow the steps of react-native config here. And using the scripting to automatically write the tmp env file. Add the script in the build phase (pre-script)
# Type a script or drag a script file from your workspace to insert its path. cp "${PROJECT_DIR}/../.env.staging" "${PROJECT_DIR}/../.env" # replace .env.staging for your file "${SRCROOT}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb" "${SRCROOT}/.." "${SRCROOT}/tmp.xcconfig" # Print the contents of the tmp.xcconfig file to verify the environment variables echo "=== Contents of tmp.xcconfig ===" cat "${SRCROOT}/tmp.xcconfig" echo "=== End of tmp.xcconfig ==="
- React Native Config Medium Guide
- Sample Gradle Configuration
- Firebase Configuration for Multiple Schemes
- Environment Setup for React Native
This is the core process for running and modifying your React Native app with custom ENV setup and apps.