> ## Documentation Index
> Fetch the complete documentation index at: https://docs.revyl.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration

> The build section of .revyl/config.yaml and every remote build CLI flag

`.revyl/config.yaml` is the configuration file for local and remote builds. It
is generated when `revyl init` runs for the first time in your project.
Optional overrides can also be passed into `revyl build`.

## A complete example

<Tabs>
  <Tab title="Expo">
    ```yaml theme={null}
    build:
      platforms:
        ios:
          app_id: "<your-ios-app-uuid>"
          commands:
            - bun install
            - bunx expo prebuild --platform ios
            - cd ios && pod install
            - cd ios && xcodebuild -workspace YourApp.xcworkspace -scheme YourApp -configuration Release -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build ARCHS=arm64
          output: ios/build/Build/Products/Release-iphonesimulator/*.app
          image: ios-macos-26-xcode-26.5
          env:
            EXPO_PUBLIC_API_URL: https://staging.example.com
          secrets:
            - EXPO_TOKEN

        android:
          app_id: "<your-android-app-uuid>"
          commands:
            - bun install
            - bunx expo prebuild --platform android
            - cd android && ./gradlew assembleRelease
          output: android/app/build/outputs/apk/release/*.apk
    ```
  </Tab>

  <Tab title="React Native">
    ```yaml theme={null}
    build:
      platforms:
        ios:
          app_id: "<your-ios-app-uuid>"
          commands:
            - npm install
            - cd ios && pod install
            - cd ios && xcodebuild -workspace YourApp.xcworkspace -scheme YourApp -configuration Release -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build ARCHS=arm64
          output: ios/build/Build/Products/Release-iphonesimulator/*.app
          image: ios-macos-26-xcode-26.5
          env:
            ENVFILE: .env.staging

        android:
          app_id: "<your-android-app-uuid>"
          commands:
            - npm install
            - cd android && ./gradlew assembleRelease
          output: android/app/build/outputs/apk/release/*.apk
    ```
  </Tab>

  <Tab title="iOS">
    ```yaml theme={null}
    build:
      platforms:
        ios:
          app_id: "<your-ios-app-uuid>"
          commands:
            - xcodebuild -project YourApp.xcodeproj -scheme YourApp -configuration Release -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' -derivedDataPath build ARCHS=arm64
          output: build/Build/Products/Release-iphonesimulator/*.app
          image: ios-macos-26-xcode-26.5
    ```
  </Tab>

  <Tab title="Android">
    ```yaml theme={null}
    build:
      platforms:
        android:
          app_id: "<your-android-app-uuid>"
          commands:
            - ./gradlew assembleRelease
          output: app/build/outputs/apk/release/*.apk
    ```
  </Tab>
</Tabs>

## PR review build fields

GitHub PR-review builds use the same environment, secret, and cache field
shapes as direct remote builds:

```yaml theme={null}
pr_review:
  builds:
    ios:
      framework: expo_ios
      env:
        EXPO_PUBLIC_API_URL: https://staging.example.com
      secrets:
        - EXPO_TOKEN
      caches:
        - key: ios-derived-data
          paths:
            - ios/build
```

`env` contains non-secret values, while `secrets` contains names previously
stored with `revyl build secret set`. A name cannot appear in both. PR-review
caches are independently declared: omitting `pr_review.builds.*.caches` or
setting it to `[]` disables caching for that PR-review build, regardless of the
matching `build.platforms.*` cache configuration.

The legacy PR-review form `env: [SECRET_NAME]` is accepted and interpreted as
`secrets: [SECRET_NAME]`, but is deprecated.

## Platform entries

Each key under `build.platforms` is a named build stream. The key must be, or
contain, `ios` or `android`. `ios`, `android`, `ios-dev`, and `android-release`
all work. Pass the key to `--platform`; passing just `ios` or `android` picks
the best-matching stream.

| Field      | Required                    | Description                                                                                                        |
| ---------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `app_id`   | Yes                         | UUID of the Revyl app that stores this stream's builds.                                                            |
| `commands` | One of `commands`/`command` | Ordered build commands, run in sequence. Takes precedence over `command`.                                          |
| `command`  | One of `commands`/`command` | Single build command.                                                                                              |
| `setup`    | No                          | Optional command run before `commands`.                                                                            |
| `output`   | Recommended                 | Path or glob to the built artifact, relative to the project root. See [artifact resolution](#artifact-resolution). |
| `scheme`   | No                          | Xcode scheme. When set, the CLI applies it to `xcodebuild` commands. iOS only.                                     |
| `image`    | No                          | [Toolchain image](/remote-builds/toolchains) key to build on. Defaults to the platform's current default image.    |
| `env`      | No                          | Non-secret environment variables for remote builds. See [environment variables](#environment-variables).           |
| `secrets`  | No                          | Encrypted org build-secret names. See [build secrets](#build-secrets).                                             |
| `caches`   | No                          | Cache disks for this stream. See [Caching](/remote-builds/caching).                                                |

Steps run in the project root. Each `commands` entry is a shell command, so
`cd android && ./gradlew …` and `A=B tool …` both work.

## Artifact resolution

After the last command exits 0, Revyl resolves the artifact:

* **iOS:** `output` path or glob pointing at a simulator `.app` bundle. If unset, Revyl searches `build/**/*.app`. The bundle must be a simulator build (`-sdk iphonesimulator`).
* **Android:** `output` path or glob pointing at an `.apk`. If unset, Revyl searches `**/build/outputs/apk/**/*.apk`. `.aab` artifacts are rejected.

Set `output` explicitly whenever more than one artifact could match, like a flavor
matrix producing several APKs, or a cached DerivedData directory holding stale
products.

## Environment variables

Non-secret variables are exported into the shell for every remote build
command. Use this for public build configuration such as `EXPO_PUBLIC_*`
variables that Expo inlines into the bundle or `ENVFILE` for
react-native-config:

```yaml theme={null}
build:
  platforms:
    ios:
      env:
        EXPO_PUBLIC_API_URL: https://staging.example.com
```

Override or add variables per invocation:

```bash theme={null}
revyl build --remote --platform ios --env EXPO_PUBLIC_API_URL=https://staging.example.com
```

`--env` values take precedence over the config file's `env` map.

Do not put credentials or tokens in `env` or `--env`; those values are part of
the remote build request. Use encrypted build secrets instead.

## Build secrets

Create or update an encrypted organization secret through the masked prompt:

```bash theme={null}
revyl build secret set EXPO_TOKEN
```

For CI, send the value over stdin so it does not appear in process arguments or
shell history:

```bash theme={null}
printf '%s' "$EXPO_TOKEN" | revyl build secret set EXPO_TOKEN --stdin
```

Commit only the secret name:

```yaml theme={null}
build:
  platforms:
    ios:
      secrets:
        - EXPO_TOKEN
        - SENTRY_AUTH_TOKEN
```

Use `--secret NAME` to add a reference for one invocation. Repeated names are
de-duplicated:

```bash theme={null}
revyl build --remote --platform ios --secret EXPO_TOKEN
```

Remote builds validate the names before creating a job, decrypt values only
when the sandbox starts, and inject them into every build command. A name cannot
appear in both `env` and `secrets`.

True remote secrets are not downloaded for local builds. A local build uses the
same names from its process environment:

```bash theme={null}
set -a
source .env.local
set +a
revyl build --platform ios
```

Revyl does not parse `.env.local` automatically. Keep it out of version control;
the CLI fails before running the build if a referenced local value is missing.

List or delete stored names without revealing values:

```bash theme={null}
revyl build secret list
revyl build secret delete EXPO_TOKEN
```

## Repo-backed builds

For repositories too large to upload per build, configure a Git source so the
runner fetches code directly:

```yaml theme={null}
build:
  source:
    type: git
    repo_url: git@github.com:company/mobile-monorepo.git
    ref: main            # branch, tag, or commit SHA
    subdir: apps/mobile  # optional monorepo project directory
    lfs: true            # fetch Git LFS objects
```

With a Git source configured, the CLI skips the archive upload. Local
uncommitted edits to tracked files are still included: the CLI uploads them as
a patch that the runner applies after checkout.

Repository access credentials are provisioned per organization. Contact
[support@revyl.ai](mailto:support@revyl.ai) to set up a deploy key or access
token for private repositories.

## CLI reference

```bash theme={null}
revyl build --remote [flags]
```

| Flag                 | Description                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------ |
| `--platform <key>`   | Platform or config key: `ios`, `android`, `ios-dev`, … Defaults to `ios`.                  |
| `--app <id>`         | App UUID override. Defaults to the stream's `app_id`.                                      |
| `--image <key>`      | [Toolchain image](/remote-builds/toolchains) override. Wins over the config `image` field. |
| `--env KEY=VALUE`    | Environment override, repeatable. Wins over the config `env` map.                          |
| `--secret NAME`      | Encrypted build-secret reference, repeatable.                                              |
| `--version <string>` | Version label for the registered build. Auto-generated when omitted.                       |
| `--detach`           | Queue the build and return the job ID without waiting.                                     |
| `--no-cache`         | Run this build without restoring or saving [caches](/remote-builds/caching).               |
| `--no-set-current`   | Don't make the new version the app's current build.                                        |
| `--json`             | Machine-readable result on stdout.                                                         |
| `--debug`            | Stream full build logs while following.                                                    |

Managing running builds:

```bash theme={null}
revyl build status <build-job-id>
revyl build status <build-job-id> --follow
revyl build cancel <build-job-id>
revyl build list
```

## Timeout

Remote builds are stopped by the server when they exceed their timeout —
**60 minutes by default**, up to a maximum of 4 hours. Optionally set it per
platform with the `timeout` key, in seconds:

```yaml theme={null}
build:
  platforms:
    ios:
      timeout: 3600
```

Or per invocation with `revyl build --remote --timeout 3600`.

Ctrl-C stops following the build; the build keeps running in the cloud. Cancel
it with `revyl build cancel <build-job-id>`.

## Related

* [Caching](/remote-builds/caching): cache disk configuration and semantics
* [Toolchain Images](/remote-builds/toolchains): available images and installed tools
* [Artifact Requirements](/builds/artifact-requirements): what the `.app`/`.apk` must look like
