skip to content

In Codemagic, what are environment variable groups, and how should a codemagic.yaml workflow receive secrets such as a Google Play service-account key?

level: middleimportance: should knowfreq 40%

answer

  1. named sets imported together
  2. team-level versus application-level
  3. Secret checkbox encrypts
  4. binary files need base64
  5. same names, different groups

basics

~20 s

Codemagic environment variable groups are named sets of variables defined in team or application settings, marked Secret to encrypt them, and imported by name under environment.groups. Binary files are base64-encoded before storing and decoded during the build.

solid answer

~50 s

Secrets never go in the committed file. You add a variable in the Codemagic UI, give it a **group** name and tick **Secret**, which encrypts it and hides the value in the UI. The workflow imports the whole group with `environment.groups: [google_credentials]` and scripts read `$GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`. Groups live either in **team settings** (global, usable by every app unless limited through Application access) or in an **application's** settings. Variables defined in the UI must belong to a group. Because two groups can hold the same names, a `staging` and a `production` group let identical scripts run with different values depending on which group a workflow imports. Text secrets such as the service-account JSON or a `.p8` key are pasted as-is; binary files such as a keystore or `.p12` must be base64-encoded first and decoded in a script. `environment.vars` is only for public values.

code

yaml · 17 lines
yaml
workflows:
  android-release:
    name: Scooter Android release
    environment:
      groups:
        - google_credentials
        - production
      vars:
        PACKAGE_NAME: "com.example.scooter"
    scripts:
      - name: Restore Firebase config
        script: |
          echo $ANDROID_FIREBASE_SECRET | base64 --decode > $CM_BUILD_DIR/android/app/google-services.json
    publishing:
      google_play:
        credentials: $GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS
        track: internal

go deeper

for a junior

Remember that secrets go into Secret variables in the Codemagic UI and a workflow imports them through environment.groups.

for a middle

Explain team versus application groups, base64 for binary files, and how same-named variables in two groups switch environments.

for a senior

Lay out groups so production credentials reach only release workflows and apps that need them, and prefer code signing identities for signing files.

for a principal

Decide how credentials are owned, scoped and rotated across many apps and teams sharing one Codemagic account.

## Why groups exist A Codemagic workflow needs credentials: a Google Play service account, App Store Connect API values, Firebase files, a token for a private Git dependency. Committing them to `codemagic.yaml` would expose them to everyone with repository access. Codemagic stores them in its UI instead, organised into **environment variable groups**, and the file references groups only by name. A **group** tags a set of related variables so they can be imported in one step. Codemagic's docs state that environment variables defined in the app settings must belong to a group. ## Where groups are defined | Level | Defined in | Visible to | |---|---|---| | Team (global) | Team settings, Global variables and secrets | Every app of the team, unless limited under Application access | | Application | The app's Environment variables tab | Every `codemagic.yaml` workflow of that app | | Workflow | `environment.vars` in the file | That workflow only; public values only | A credential shared by all of a team's apps, such as an App Store Connect key, fits a global group; a Play service account for one app fits that app's group. ## Importing a group ```yaml environment: groups: - google_credentials - scooter_production vars: PACKAGE_NAME: "com.example.scooter" ``` Every variable in the listed groups becomes an environment variable for the build, so a script or a publishing field reads `$GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS`. Built-in read-only variables sit alongside them: `CI` is `true`, `BUILD_NUMBER` counts builds of this workflow, `PROJECT_BUILD_NUMBER` counts builds of the project, and `CM_BUILD_DIR` is the clone directory. ## Secret values and binary files - Ticking **Secret** encrypts the value and obfuscates it in the UI. - **Text** secrets, like a service-account JSON or the contents of an App Store Connect `.p8` key, are pasted as they are, including their begin and end lines. - **Binary** files, like an Android keystore, a `.p12` certificate or a `.mobileprovision` profile, must be **base64-encoded** locally before pasting and decoded in a script with `echo $VAR | base64 --decode > /path/file`. For signing files there is now a better home than a base64 variable: the team's **Code signing identities**, referenced through `android_signing` and `ios_signing`. Base64 variables remain the manual fallback. ## The documented variable names Codemagic's samples and CLI tools expect certain names, and sticking to them saves wiring: | Variable | Holds | Typical group | |---|---|---| | `GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS` | Service-account JSON for Play publishing | `google_credentials` | | `APP_STORE_CONNECT_ISSUER_ID` | Issuer ID of the API key | `appstore_credentials` | | `APP_STORE_CONNECT_KEY_IDENTIFIER` | Key ID of the API key | `appstore_credentials` | | `APP_STORE_CONNECT_PRIVATE_KEY` | Contents of the `.p8` file | `appstore_credentials` | | `CERTIFICATE_PRIVATE_KEY` | Private key for CLI-based automatic signing | `appstore_credentials` | | `CM_KEYSTORE`, `CM_KEYSTORE_PASSWORD`, `CM_KEY_ALIAS`, `CM_KEY_PASSWORD` | Manual Android signing values | `keystore_credentials` | Storing related variables in the same group means one line under `groups` brings the whole set. When the Apple Developer Portal **integration** is used instead, the App Store Connect variables are not needed at all: the workflow names the key under `integrations`. ## One script, several environments Groups can reuse variable names. A `staging` group and a `production` group can both define `API_BASE_URL` and `FLEET_API_TOKEN`; which one a build sees depends only on the group its workflow imports. That keeps scripts identical across a staging workflow and a production workflow of the scooter app. ## Traps 1. Putting a password under `environment.vars` commits it to Git. 2. Forgetting to import the group: the variable exists in the UI but is empty in the build. 3. In a workflow's `when.condition`, variables are read as `env.NAME`; shell syntax `$NAME` is not supported there. 4. Pasting a binary keystore without base64 corrupts it. Groups are Codemagic's answer to secret handling; general secret-management principles belong to CI concepts, but these keys and their rules are what an interviewer checks.

  • How do you limit a Codemagic team-level variable group to certain apps?
    Global groups defined in team settings are usable by every app of the team by default. Editing the group's **Application access** restricts it to the applications you pick, which keeps one app's production credentials out of another app's builds.
  • Why might a Codemagic build see an empty value for a variable you added in the UI?
    The workflow must import the variable's group under `environment.groups`; UI variables are not injected otherwise. Also check the group name's spelling and, for a global group, that Application access includes this app.

Variable groups work like labelled key rings at a front desk. A staging ring and a production ring carry keys with the same labels that open different doors; a workflow signs out a ring by name, and the ring it takes decides which doors its scripts can open.

saying these in an interview costs you the question

  • Secrets can live under environment.vars because the repository is private
  • A keystore can be pasted into a secret variable without encoding
  • UI variables reach every workflow without importing their group
  • Two variable groups cannot define a variable with the same name
  • A when condition reads variables with shell syntax like $NAME