Extra vars do not show up in EAS build

We’ve been switching our workflow from expo build:<platform> to eas builds (because we had to, to use Stripe on iOS).

It’s been a super bumpy road.

The latest issue that I’m running into is that we used to use react-native-dotenv to manage our configurations. That works fine in development, but when we run a build, the @env module is empty.

Thinking it might be best to switch to the Constants.manifest.extra path, since that seems to be recommended, I decided to give it a shot. So we now have an app.config.js file which starts as follows:

We then have the following:

import 'dotenv/config';

const extraEnvs = {
  EXTRA_TEST: true,
  AUTH0_DOMAIN: process.env.AUTH0_DOMAIN,
  AUTH0_NATIVE_CLIENT_ID: process.env.AUTH0_NATIVE_CLIENT_ID,
  AUTH0_WEB_CLIENT_ID: process.env.AUTH0_WEB_CLIENT_ID,
  GRAPHQL_ENDPOINT: process.env.GRAPHQL_ENDPOINT,
  STORAGE_BASE: process.env.STORAGE_BASE,
  SEGMENT_IOS_WRITE_KEY: process.env.SEGMENT_IOS_WRITE_KEY,
  SEGMENT_ANDROID_WRITE_KEY: process.env.SEGMENT_ANDROID_WRITE_KEY,
  GOOGLE_API_KEY: process.env.GOOGLE_API_KEY,
  STRIPE_PUBLISHABLE_KEY: process.env.STRIPE_PUBLISHABLE_KEY,
};

console.log('@@ extraEnvs: ', extraEnvs);

export default () => {
  return {
    expo: {
      [...]
      extra: extraEnvs,
    },
  };
};

When our CD scripts run, I can see the extraEnvs properly printed out, with the appropriate values per environment. But when I actually run the app? There’s nothing in there, even though it works fine in development (using --dev-client).

As you can see, I added a testing value (EXTRA_TEST: true,) to see what happened when I console.log the whole manifest in the app. That one is there. But all the other variables, which console.log during the build process, aren’t there when the app runs.

Anyone have any idea what’s going on? This switch to EAS is making me want to pull my hair out. Every time I fix something, a couple other things break.

EDIT 1:
I just noticed something. I run expo publish during deployment to do OTA updates, before a build gets submitted to the app stores. It looks like the environment variables print out during the publish command, but when the eas commands run, the environment variables are empty. Does app.config.js run differently during the eas commands? I’m not sure I understand how/why that would be the case? It’s the same js file?

EDIT 2:
Of course, as soon as I finish writing this stuff, I think I find the culprit:

I do find it a bit frustrating that these systems seem to have diverged so much.

Hey @ec_raphael, I’m glad you found the cause of the issue but don’t like to hear that you’ve had a frustrating experience with the transition to EAS. That’s far from the experience we aim to provide.

Out of curiosity, did you find/make use of the migration docs Migrating from "expo build" - Expo Documentation

Cheers,
Adam

Hey @adamjnav, yup, I did. I just missed some stuff :slight_smile:

I think I have a pretty strong mental model built up over the past few years of working with Expo, and while I was going through the guide, I may not have read as carefully as necessary, relying more on my existing mental model than building a new one.

One thing that really tripped me up (but I got help in the discord) was that we were using react-native-skeleton-content - npm with no problems in Expo Go, but once we switched, things kept failing, and it was really hard to debug because we were getting a message about missing native modules, but without a specific module being mentioned. It ended up being something to do with react-native-reanimated and unimodules.

I’m also trying to “break free” from my mental model around expo publish, release channels, and start thinking in the eas model.

Something I’ve been playing with to make the transition easier is to create a layer that switches between the old and the new manifest system, depending on what is available. The reason why this matters to us is that some programmers on the team are still using Expo Go somehow.

Here is how:

I created a file config.ts that has the following:

import Constants from "expo-constants"

// eslint-disable-next-line
let config

if (Constants.manifest) {
  config = Constants.manifest.extra // The old manifest
} else {
  config = Constants.manifest2.extra.expoClient.extra // The new manifest
}

export default config

Now elsewhere in the code, where previously I used

import Constants from "expo-constants"
const { someVariable } = Constants.manifest.extra

Now I use

import config from "../config" // path to that new config.ts file
const { debugSentry, env, sentryDsn } = config
...

However this solution is still incomplete due to complications with how eas secrets / eas update work – I created a post here detailing this aspect: Are EAS Secrets available to EAS Updates