By Damon Yuan


2015-10-14 05:26:38 8 Comments

I am using react-native to build a cross-platform app, but I do not know how to set the environment variable so that I can have different constants for different environments.

Example:

development: 
  BASE_URL: '',
  API_KEY: '',
staging: 
  BASE_URL: '',
  API_KEY: '',
production:
  BASE_URL: '',
  API_KEY: '',

14 comments

@Jack Zhang 2017-06-07 19:34:26

I use babel-plugin-transform-inline-environment-variables.

What I did was put a configuration files within S3 with my different environments.

s3://example-bucket/dev-env.sh
s3://example-bucket/prod-env.sh
s3://example-bucket/stage-env.sh

EACH env file:

FIRSTENV=FIRSTVALUE
SECONDENV=SECONDVALUE

Afterwards, I added a new script in my package.json that runs a script for bundling

if [ "$ENV" == "production" ]
then
  eval $(aws s3 cp s3://example-bucket/prod-env.sh - | sed 's/^/export /')
elif [ "$ENV" == "staging" ]
then
  eval $(aws s3 cp s3://example-bucket/stage-env.sh - | sed 's/^/export /')
else
  eval $(aws s3 cp s3://example-bucket/development-env.sh - | sed 's/^/export /')
fi

react-native start

Within your app you will probably have a config file that has:

const FIRSTENV = process.env['FIRSTENV']
const SECONDENV = process.env['SECONDENV']

which will be replaced by babel to:

const FIRSTENV = 'FIRSTVALUE'
const SECONDENV = 'SECONDVALUE'

REMEMBER you have to use process.env['STRING'] NOT process.env.STRING or it won't convert properly.

@Steven Yap 2017-10-02 03:46:59

REMEMBER you have to use process.env['STRING'] NOT process.env.STRING or it won't convert properly. Thanks! This is the one that trips me up!!!

@Smakosh 2019-02-25 16:11:56

For latest RN versions, you can use this native module: https://github.com/luggit/react-native-config

@Jitendra Suthar 2018-06-21 09:36:54

Step 1: Create separate component like this Component name : pagebase.js
Step 2: Inside this use code this

    export const BASE_URL = "http://192.168.10.10:4848/";
    export const API_KEY = 'key_token';

Step 3: Use it in any component, for using it first import this component then use it. Import it and use it:

        import * as base from "./pagebase";

        base.BASE_URL
        base.API_KEY

@Srdjan Cosic 2018-02-14 14:26:56

It is possible to access the variables with process.env.blabla instead of process.env['blabla']. I recently made it work and commented on how I did it on an issue on GitHub because I had some problems with cache based on the accepted answer. Here is the issue.

@chapinkapa 2016-06-14 22:52:23

Instead of hard-coding your app constants and doing a switch on the environment (I'll explain how to do that in a moment), I suggest using the twelve factor suggestion of having your build process define your BASE_URL and your API_KEY.

To answer how to expose your environment to react-native, I suggest using Babel's babel-plugin-transform-inline-environment-variables.

To get this working you need to download the plugin and then you will need to setup a .babelrc and it should look something like this:

{
  "presets": ["react-native"],
  "plugins": [
    "transform-inline-environment-variables"
  ]
}

And so if you transpile your react-native code by running API_KEY=my-app-id react-native bundle (or start, run-ios, or run-android) then all you have to do is have your code look like this:

const apiKey = process.env['API_KEY'];

And then Babel will replace that with:

const apiKey = 'my-app-id';

Hope this helps!

@Scimonster 2016-10-15 21:40:57

I just used the transform-inline-environment-variables plugin on its own; they seem to have fixed that React Native bug.

@chapinkapa 2016-10-16 00:39:14

I went ahead and updated my answer. Thanks @Scimonster!

@duhseekoh 2016-11-16 17:02:28

This doesn't seem to be working in 0.36. The vars just never get read.

@chapinkapa 2016-12-19 21:02:14

I am not current on 0.36. I'll try to update the response once we upgrade. If anyone else has tried upgrading, I'll take a suggestion or up vote another answer.

@vonGohren 2017-01-18 13:52:43

Im trying to get it to work with 0.38, but im struggeling to get the vars read. Trying to figure out where and how the babelrc is read to dig a bit into the problem, but I'm struggeling.

@Adam Faryna 2017-02-25 21:48:25

Sounds like great solution, but not works for me at [email protected] The only property on process.env is NODE_ENV.

@chapinkapa 2017-02-27 05:45:51

I will need to be upgrading here soon, I'll try out a new solution here soon. Thanks @Sanczol

@Ville Miekk-oja 2017-09-12 18:43:36

Does not seem to work anymore. For me the variables are undefined. Do I need to clear babel cache somehow or do something else to get this working?

@Steven Yap 2017-10-02 03:48:20

See the answer below by Jack Zheng... you cannot access the variable via process.env.API_KEY... use process.env['API_KEY'] instead

@Dejan Maksimovic 2017-10-11 18:18:02

This seems like a great solution when debugging, will it work when building releases? You basically run gradle when releasing the app, so seems like you are out of luck with this approach. Or am I missing something?

@chapinkapa 2017-10-12 16:06:35

@DejanMaksimovic it has worked for me on release. When you package a release react-native's packager converts your JS, and so whenever you package your code, you need to have your ENV variables in the same process

@Dejan Maksimovic 2017-10-15 10:34:09

Thanks for your reply. My problem was indeed elsewhere. I think it was the fact that I didn't have react-native preset installed, so transform didn't get picked up at all.

@user1106888 2018-03-08 01:50:15

I am getting the process.env['API_KEY'] as undefined. Can anyone help me set this up

@Guto Marrara Marzagao 2018-05-04 14:27:49

I had the same problem: undefined

@bgmaster 2018-05-26 14:52:52

Does not work for my w/ RN 0.55.4

@James Trickey 2018-06-28 17:18:42

Does not work for me either. Damn shame as this is exactly what I was looking for. (55.1)

@Eric Kim 2018-08-29 10:04:23

This does not work in 0.56

@soheilpro 2018-08-29 13:21:03

Works for me in v0.56. You have to clear bundler's cache by running react-native start --reset-cache every time you change the environment variables.

@Marecky 2018-10-08 22:12:29

Is there any RN configuration library that supports defaults? Like Mozilla's Convict? npmjs.com/package/convict

@Slavo Vojacek 2017-07-20 07:48:34

The simplest (not the best or ideal) solution I found was to use react-native-dotenv. You simply add the "react-native-dotenv" preset to your .babelrc file at the project root like so:

{
  "presets": ["react-native", "react-native-dotenv"]
}

Create a .env file and add properties:

echo "SOMETHING=anything" > .env

Then in your project (JS):

import { SOMETHING } from 'react-native-dotenv'
console.log(SOMETHING) // "anything"

@Anshul Koka 2017-08-17 17:51:24

I was hoping for a .env based solution. Thank you!

@Compaq LE2202x 2018-02-21 08:48:04

@Slavo Vojacek How do I use this to configure for example one base_url for both staging and production?

@Slavo Vojacek 2018-03-17 20:47:21

@CompaqLE2202x I am not quite sure I understand? Are you asking about using different .env files (per environment), or about reusing some of your values in different .env files, so you don't duplicate them across, say, Staging and Production?

@Compaq LE2202x 2018-03-19 06:52:51

@SlavoVojacek I'm asking about different .env files per environment let's say staging and production.

@mgamsjager 2018-12-04 08:40:08

@SlavoVojacek couldn't you overwrite values in a CI stage or at deployment?

@Bogdan D 2019-03-25 12:47:27

@CompaqLE2202x, this solution won't allow you to define custom environments, out of the box. But it does have two environments: development and production

@Toni Chaz 2017-06-14 10:44:24

i have created a pre build script for the same problem because i need some differents api endpoints for the differents environments

const fs = require('fs')

let endPoint

if (process.env.MY_ENV === 'dev') {
  endPoint = 'http://my-api-dev/api/v1'
} else if (process.env.MY_ENV === 'test') {
  endPoint = 'http://127.0.0.1:7001'
} else {
  endPoint = 'http://my-api-pro/api/v1'
}

let template = `
export default {
  API_URL: '${endPoint}',
  DEVICE_FINGERPRINT: Math.random().toString(36).slice(2)
}
`

fs.writeFile('./src/constants/config.js', template, function (err) {
  if (err) {
    return console.log(err)
  }

  console.log('Configuration file has generated')
})

And i have created a custom npm run scripts to execute react-native run..

My package-json

"scripts": {
    "start-ios": "node config-generator.js && react-native run-ios",
    "build-ios": "node config-generator.js && react-native run-ios --configuration Release",
    "start-android": "node config-generator.js && react-native run-android",
    "build-android": "node config-generator.js && cd android/ && ./gradlew assembleRelease",
    ...
}

Then in my services components simply import the auto generated file:

import config from '../constants/config'

fetch(`${config.API_URL}/login`, params)

@Logister 2017-05-26 02:34:46

I used the __DEV__ polyfill that is built into react-native in order to solve this problem. It is automatically set to true so long as you are not building react native for production.

E.g.:

//vars.js

let url, publicKey;
if (__DEV__) {
  url = ...
  publicKey = ...
} else {
  url = ...
  publicKey = ...
}

export {url, publicKey}

Then just import {url} from '../vars'and you'll always get the correct one. Unfortunately, this wont work if you want more than two environments, but its easy and doesn't involve adding more dependencies to your project.

@realtebo 2018-04-16 21:08:02

do you know a way to 'foce' DEV to TRUE even when creating a release build in xcode?

@Logister 2018-04-16 22:32:05

Nope. I just comment out the prod vars and then copy paste the dev vars into the prod section when I want to do a release build with dev variables.

@vonovak 2017-05-05 19:35:19

@chapinkapa's answer is good. An approach that I have taken since Mobile Center does not support environment variables, is to expose build configuration through a native module:

On android:

   @Override
    public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        String buildConfig = BuildConfig.BUILD_TYPE.toLowerCase();
        constants.put("ENVIRONMENT", buildConfig);
        return constants;
    } 

or on ios:

  override func constantsToExport() -> [String: Any]! {
    // debug/ staging / release
    // on android, I can tell the build config used, but here I use bundle name
    let STAGING = "staging"
    let DEBUG = "debug"

    var environment = "release"
    if let bundleIdentifier: String = Bundle.main.bundleIdentifier {
      if (bundleIdentifier.lowercased().hasSuffix(STAGING)) {
        environment = STAGING
      } else if (bundleIdentifier.lowercased().hasSuffix(DEBUG)){
        environment = DEBUG
      }
    }

    return ["ENVIRONMENT": environment]
  }

You can read the build config synchronously and decide in Javascript how you're going to behave.

@Patrik Prevuznak 2017-04-11 11:29:25

In my opinion the best option is to use react-native-config. It supports 12 factor.

I found this package extremely useful. You can set multiple environments, e.g. development, staging, production.

In case of Android, variables are available also in Java classes, gradle, AndroidManifest.xml etc. In case of iOS, variables are available also in Obj-C classes, Info.plist.

You just create files like

  • .env.development
  • .env.staging
  • .env.production

You fill these files with key, values like

API_URL=https://myapi.com
GOOGLE_MAPS_API_KEY=abcdefgh

and then just use it:

import Config from 'react-native-config'

Config.API_URL  // 'https://myapi.com'
Config.GOOGLE_MAPS_API_KEY  // 'abcdefgh'

If you want to use different environments, you basically set ENVFILE variable like this:

ENVFILE=.env.staging react-native run-android

or for assembling app for production (android in my case):

cd android && ENVFILE=.env.production ./gradlew assembleRelease

@Marklar 2017-04-12 04:28:41

It may be worth noting that in the README it states Keep in mind this module doesn't obfuscate or encrypt secrets for packaging, so do not store sensitive keys in .env. It's basically impossible to prevent users from reverse engineering mobile app secrets, so design your app (and APIs) with that in mind

@thibaut noah 2017-10-06 14:35:02

Thing is it will not work with some frameworks like twitter which requires to have they key set as com.twitter.sdk.android.CONSUMER_KEY in your .env

@sfratini 2017-10-10 19:27:34

If you mean putting the key inside the Manifest, the extension supports it. It is just not described in this answer. You can use the variables in XML, Java and JS files.

@Marecky 2018-10-09 21:12:17

react-native-config does not work with RN 0.56, it has unresolved issues and it is unmaintained for over 6 months. The issue witch kills its usage in RN is github.com/luggit/react-native-config/issues/267, here is some hacking to make it work github.com/luggit/react-native-config/issues/285

@Pikachu-go 2017-04-08 12:16:33

you can also have different env scripts: production.env.sh development.env.sh production.env.sh

And then source them in when starting to work [which is just tied to an alias] so all the sh file has is export for each env variable:

export SOME_VAR=1234
export SOME_OTHER=abc

And then adding babel-plugin-transform-inline-environment-variables will allow access them in the code:

export const SOME_VAR: ?string = process.env.SOME_VAR;
export const SOME_OTHER: ?string = process.env.SOME_OTHER;

@Maximo Dominguez 2017-04-08 19:41:17

Are you adding anything @chapinkapa hasn't said?

@Josh Habdas 2016-09-22 17:18:15

The specific method used to set environment variables will vary by CI service, build approach, platform and tools you're using.

If you're using Buddybuild for CI to build an app and manage environment variables, and you need access to config from JS, create a env.js.example with keys (with empty string values) for check-in to source control, and use Buddybuild to produce an env.js file at build time in the post-clone step, hiding the file contents from the build logs, like so:

#!/usr/bin/env bash

ENVJS_FILE="$BUDDYBUILD_WORKSPACE/env.js"

# Echo what's happening to the build logs
echo Creating environment config file

# Create `env.js` file in project root
touch $ENVJS_FILE

# Write environment config to file, hiding from build logs
tee $ENVJS_FILE > /dev/null <<EOF
module.exports = {
  AUTH0_CLIENT_ID: '$AUTH0_CLIENT_ID',
  AUTH0_DOMAIN: '$AUTH0_DOMAIN'
}
EOF

Tip: Don't forget to add env.js to .gitignore so config and secrets aren't checked into source control accidentally during development.

You can then manage how the file gets written using the Buddybuild variables like BUDDYBUILD_VARIANTS, for instance, to gain greater control over how your config is produced at build time.

@volk 2016-09-27 18:54:09

overall i like the idea, but how does the env.js.example part work? let's say i want to launch the app in my local environment. if my env.js file is in gitignore and env.js.example is used as an outline, the env.js.example isn't a legitimate JS extension, so i'm just a little confused on what you meant by this part

@Josh Habdas 2016-09-27 23:35:56

@volk The env.js.example file sits in the codebase as a reference document, a canonical source of truth as to what config keys the app wants to consume. It both describes the keys required to run the app, as well as the filename expected once copied and renamed. The pattern is common in Ruby apps using the dotenv gem, which is where I lifted the pattern from.

@leonfs 2016-06-29 20:25:07

I think something like the following library could help you out to solve the missing bit of the puzzle, the getPlatform() function.

https://github.com/joeferraro/react-native-env

const EnvironmentManager = require('react-native-env');

// read an environment variable from React Native
EnvironmentManager.get('SOME_VARIABLE')
  .then(val => {
    console.log('value of SOME_VARIABLE is: ', val);

  })
  .catch(err => {
    console.error('womp womp: ', err.message);
  });

The only problem I see with this, that it's async code. There is a pull request to support getSync. Check it out too.

https://github.com/joeferraro/react-native-env/pull/9

@chapinkapa 2016-07-28 20:34:31

I love the "womp womp" lol!

@Josh Habdas 2016-09-22 17:49:44

Upvoted for providing an alternative approach not mentioned. No one size fits all.

@jcollum 2016-10-16 00:40:25

The asynch pull req has been merged in

@jcollum 2016-10-16 00:57:02

react-native-env doesn't appear to support Android. What's the point?

@tohster 2015-10-14 20:15:58

React native does not have the concept of global variables. It enforces modular scope strictly, in order to promote component modularity and reusability.

Sometimes, though, you need components to be aware of their environment. In this case it's very simple to define an Environment module which components can then call to get environment variables, for example:

environment.js

var _Environments = {
    production:  {BASE_URL: '', API_KEY: ''},
    staging:     {BASE_URL: '', API_KEY: ''},
    development: {BASE_URL: '', API_KEY: ''},
}

function getEnvironment() {
    // Insert logic here to get the current platform (e.g. staging, production, etc)
    var platform = getPlatform()

    // ...now return the correct environment
    return _Environments[platform]
}

var Environment = getEnvironment()
module.exports = Environment

my-component.js

var Environment = require('./environment.js')

...somewhere in your code...
var url = Environment.BASE_URL

This creates a singleton environment which can be accessed from anywhere inside the scope of your app. You have to explicitly require(...) the module from any components that use Environment variables, but that is a good thing.

@Damon Yuan 2015-10-15 01:23:57

my problem is how to getPlatform(). I have make a file like this but cannot finish the logic here in React Native

@tohster 2015-10-15 01:45:36

@DamonYuan that depends entirely on how you're setting up your packages. I have no idea what staging or production even mean, because it's dependent on your environment. For example, if you want different flavors for IOS vs Android then you can initialize Environment by importing it your index.ios.js and index.android.js files and setting the platform there, e.g. Environment.initialize('android').

@Damon Yuan 2015-10-15 01:54:44

thx, let me try first

@chapinkapa 2016-06-14 22:54:00

@DamonYuan does what I put help at all, or do you need some more clarification?

@enapupe 2016-07-26 22:21:47

This is very nice when you have control over the code. I'm running a third part module which relies on process.env, so...

@James111 2016-08-04 04:23:34

Just set a variable "current_platform" in the environment.js file...

@Josh Habdas 2016-09-22 17:08:28

If you create an env.js file be sure to ignore it from check-ins to the repository and copy the keys used, with empty string values, into another env.js.example file you do check-in so others can build your app more easily. If you accidentally check in project secrets consider rewriting history to remove them not just from the source but the history thereof.

@Isaac 2019-01-07 01:24:52

React native does not have the concept of global variables, it does. You can assign any value to global variable by doing global.varA = 'valueA' and you can access the value anywhere you want to

Related Questions

Sponsored Content

11 Answered Questions

[SOLVED] How to add icons to React Native app

  • 2015-12-17 08:18:44
  • Adam Katz
  • 98950 View
  • 205 Score
  • 11 Answer
  • Tags:   icons react-native

27 Answered Questions

[SOLVED] How to do logging in React Native?

  • 2015-05-08 03:40:20
  • skyline75489
  • 150763 View
  • 249 Score
  • 27 Answer
  • Tags:   logging react-native

17 Answered Questions

[SOLVED] React Native fixed footer

  • 2015-04-04 14:43:11
  • 4ega
  • 99850 View
  • 92 Score
  • 17 Answer
  • Tags:   react-native

21 Answered Questions

[SOLVED] Android failed to load JS bundle

11 Answered Questions

[SOLVED] iOS Launch screen in React Native

4 Answered Questions

[SOLVED] React-Native - Custom navigation with Navigator component

1 Answered Questions

[SOLVED] React Native DEV and PROD variables

  • 2015-10-21 16:20:37
  • Ryan McDermott
  • 19758 View
  • 44 Score
  • 1 Answer
  • Tags:   react-native

5 Answered Questions

[SOLVED] What IDE is recommended for React Native?

1 Answered Questions

How to create different environment for react-native application

  • 2017-01-31 11:59:07
  • Zhao Yi
  • 472 View
  • 1 Score
  • 1 Answer
  • Tags:   react-native

Sponsored Content