EAS update fails in production (managed workflow)

My eas-cli version is 0.49.0.

Last night, I tried the EAS update for the first time in production, but unfortunately, it didn’t work. The app froze for me on iPhone 7 and others in team could open the app, but the data was coming from development. My guess is the wrong environemt variables were used.

So, I did expo build and then expo update --branch production --message "Some message".

My environment variables are in eas.json, like this:

  "build": {
    "production": {
      "channel": "production",
      "env": {
        "API_KEY": "xxxx",
    "preview": {
      "extends": "development",
      "channel": "preview",
      "developmentClient": false,
      "distribution": "store"
    "development": {
      "channel": "development",
      "developmentClient": false,
      "env": {
        "API_KEY": "xxxx",
      "distribution": "internal",
      "android": {
        "buildType": "apk"
  "submit": {
    "production": {}
  "cli": {
    "version": ">= 0.40.0",
    "requireCommit": true

I also have a secret key that is stored in expo.

Is there anything I’m doing wrong?

hey there! check out this page for more info about env vars and eas update: Using environment variables with EAS Update - Expo Documentation

Thanks for your response! But, that page is not very useful, to be honest. Here’s why:

  1. It doesn’t tell me where exactly the environment variables in EAS updates come from. In fact, it gives the impression that whoever wrote that page didn’t have enought knowlegde about EAS updates.
  2. In my post, I explained exactly where the environment variables are used in my builds. That page doesn’t explain why development environment variables are used in my production Expo updates.
  3. That page doesn’t explain what happens to secret keys in EAS updates.

Ad. 1 Doc is pretty clear those variables are set via extra field in app.config.js and in the latter section there is an example how to set that up using envs. Values injected into your update(just like in build) come from whatever you define in app.config.js, so if you use envs, it will be env variables in your shell.
As. 2 Build profiles in eas.json are for building, update command does not provide any way to specify the profile so it should be obvious that there is no connection between them. Also even for builds, values in eas.json are only specifying what envs are created on the builder instance, to pass them to the build artifact you need to define them via an extra field.
Ad. 3 Yes, because nothing happens with them, documentation should specify what is happening not what is not happening. Also if you include a secret in an update it’s available in plain text in a js bundle, so it’s either should not be secret or it should not be used in an update,


@wkozyra I’m sorry, but this still doesn’t answer my questions.

  1. Are you telling me that the environment variables in my eas.json are not used when doing eas update? Then, isn’t this section confusing? Using environment variables with EAS Update - Expo Documentation

  2. You add channels to the build profiles for the eas update, so I disagree with you. It’s not obvious. In fact, what would seem obvious is that when you add channel: “production” to the production build profile, that means everything that applies to that profile should apply to your channel too. My understanding is that when you specify the channel by using the branch in your eas update command, that means the build assiciated to that channel is used. Am I wrong?

  3. Does that mean if I have secret keys in my app, I can’t use EAS updates?


The documentation you have been initially referred to is accurate, though it might take some consideration to adjust your mental model of the process to how it is implemented.

Like described and mentioned, environment variables defined in eas.json, and those defined as secrets on the server, are used for EAS builds, and builds only. That’s why they are listed under the build key in eas.json, and linked to a build profile. The bundling for eas update happens completely local on your machine, so there is no interaction with the build server either for any secrets defined there.

Similarly, when you run eas update, you supply a branch to publish the update to. A branch is completely separate from a channel, which is one of the core concepts of EAS Updates and described in detail here. At any point, you can decide which channel looks at which branch to receive updates, so at publish time, there is again no relationship with any channel configuration, or any specific build profile.

As I mentioned above, bundling an update with eas update happens completely local, which means that any environment variables you want to be available, you will need to specify yourself. There is no process that dynamically creates environment variables for you. The documentation provides you with a number of options for providing these, for example through the app.config.js extra key, but you are free to use any method that suits your needs.

I hope this clarifies the thought process behind updates a bit better. Feel free to reply with any additional questions.

@kbrandwijk Thank you for your response and sorry for the late reply. I got busy with other stuff. I have some questions:

  1. You say “the branch is completey separate from a channel”. But, I read this article you shared, and it seems like by default the channel is linked to the branch with the same name. And, that makes me think that with the configuration I have in my eas.json (see my original post) and the command I ran, the update must have been applied to my production build, unless some very strange is happening here or I haven’t understood anything from the article. So, my assumptions is that I got that part right.
  2. You say “an update with eas update happens completely local, which means that any environment variables you want to be available, you will need to specify yourself”, but the biggest question here is how do I do that? How do I make sure that the correct environment variables are used when running eas update? I have a lot of environment variables (like any other real app), so a solution like the following won’t work for me (it won’t for any real app, un less the app is a the simplest to-do list).
API_URL="https://prod.example.com" eas update --branch production

And, using env.ts file, how am I supposed to know what environment the eas update is targetting so I can use the corrent environment variables.

Lastly, it seems like there’s no way I can use a secret key without sharing it with all developers in the team, right?

  1. The first time you publish an update to a branch, it will by default create a channel with the same name, and link the branch to it. This is just for convenience though, it doesn’t take anything away from what I said about branches and channels being two different things. You decide what channel you link to what branch. If you publish to a branch that doesn’t have the same name as an existing channel, your app will not receive an update until you manually link the new branch to the channel you’re using for the build. So for example, if you have your build configured with channel ‘production’ and you publish an update with --branch production-update (or any other name), nothing will happen to your production app until you link the two together with eas channel:edit production --branch production-update. That is the core concept I’ve been trying to explain. You publish updates to branches, and your app looks for updates on a channel. Unless you link a channel to a branch, it will not get updates.

  2. There’s many ways to load environment variables, there’s nothing Expo specific about that. For example, you could run export $(cat .env.production | xargs) && eas update --branch production" (or even store that as a script in your package.json, and it would load the right env file into your environment before running eas update.

And no, there is no way to access server secrets locally.

@kbrandwijk Thanks a lot! I’ll try again and let you know if there are any questions.

1 Like