# Bitrise Docs > Find product documentation, code samples, API & CLI references, and more. This file contains all documentation content in a single document following the llmstxt.org standard. ## Bitrise API --- ## Configuring the build cache for Bazel in local builds You can use the Bitrise Build Cache for local Bazel builds too. Your local builds then read from the same cache as your CI builds, so an action your CI already ran doesn't have to run again on your machine. The Bitrise Build Cache CLI sets this up for you by writing the cache flags to your `~/.bazelrc`. ### Before you start Ensure you have: - A working Bazel project on your machine, on Bazel 6 or later. The setup uses Bazel's credential helper support, which earlier versions don't have. - A Bitrise workspace with the Build Cache enabled. Check it on the [Build Cache page](https://app.bitrise.io/build-cache/). - Network access to the Bitrise hosts the Build Cache uses, if your machine is behind a VPN, a firewall, or an outbound proxy. See [Network endpoints for firewalls and VPNs](/bitrise-build-cache/getting-started-with-the-build-cache/network-endpoints-for-firewalls-and-vpns). :::important[Activation is global, not per-project] `activate bazel` writes a single block to `~/.bazelrc` in your home directory. It never touches your project's `.bazelrc`. Every Bazel project on your machine picks up the cache flags, not just the one you activated from. The repository URL reported to the dashboard is read from the git remote of the directory you ran the activation in, so on a machine with several Bazel projects they all report the first one. That affects dashboard attribution only, not cache correctness. Re-run the activation from another project's directory to change it. ::: ### Installing the CLI Install the CLI with Homebrew (**recommended**): ```bash brew install bitrise-io/bitrise-build-cache/bitrise-build-cache ``` Or, without Homebrew: ```bash curl --retry 5 -sSfL \ 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' \ | sh -s -- -b ~/.local/bin ``` Make sure the install location is on your `PATH`, then check the install: ```bash bitrise-build-cache --version ``` Keep the CLI on your `PATH` afterwards. Bazel runs the CLI on every build to fetch a fresh auth token, not only during setup. ### Activating the cache Run the interactive wizard: ```bash bitrise-build-cache activate --interactive ``` The wizard asks for the following: 1. **Sign in to Bitrise**: opens your browser for authentication on the first run. The CLI stores the credentials in the OS keychain and refreshes them automatically, so later runs skip this step. On a machine without a usable keychain, the CLI falls back to storing them in a config file. 1. **Select a workspace**: pick the workspace whose Build Cache you want to use. The CLI selects it automatically if you only have access to one. 1. **Which build tools should I set up**: ensure **Bazel** is selected. Use space to toggle an option and enter to confirm. 1. **Display name for this machine's local invocations**: the name your local builds show up under in the Build Cache dashboard, for example `local-`. 1. **Enable cache push**: select **No, pull only**. See [Local builds only read from the cache](#local-builds-only-read-from-the-cache). The non-interactive equivalent, once you have signed in: ```bash bitrise-build-cache activate bazel --cache ``` #### What the activation writes A single marked block appended to `~/.bazelrc`. Existing content is preserved, and re-running the activation only updates the block: ```bash # [start] generated-by-bitrise-build-cache build --credential_helper=*.services.bitrise.io=bitrise-build-cache build --remote_cache=grpcs://bitrise-accelerate.services.bitrise.io build --remote_timeout=600s build --remote_header=x-flare-buildtool=bazel build --remote_header=x-flare-builduser= build --noremote_upload_local_results build --bes_backend=grpcs://flare-bes.services.bitrise.io:443 build --bes_results_url=https://app.bitrise.io/build-cache/invocations/bazel/ build --bes_timeout=2m build --bes_upload_mode=wait_for_upload_complete build --build_event_publish_all_actions build --show_timestamps build --remote_header='x-org-id=' build --bes_header='x-org-id=' build --remote_header='x-repository-url=https://github.com//.git' build --bes_header='x-repository-url=https://github.com//.git' build --bes_header='x-os=' build --bes_header='x-locale=C' build --bes_header='x-default-charset=UTF-8' build --bes_header='x-cpu-cores=4' build --bes_header='x-mem-size=16759259136' # [end] generated-by-bitrise-build-cache ``` Two lines worth highlighting: - `--credential_helper` points at the CLI rather than storing a token, so Bazel fetches a fresh one on every build and an expiring login keeps working. This is why the CLI has to stay on your `PATH`. - `--noremote_upload_local_results` is pull-only mode. Activating with `--cache-push` writes `--remote_upload_local_results` instead. The `x-os`, `x-cpu-cores`, `x-mem-size`, `x-locale`, and `x-default-charset` headers describe your machine and are used for analytics only, and don't affect cache keys. They matter if you commit the configuration, because they're specific to the machine that generated the block. See [What is safe to commit](#what-is-safe-to-commit). ### Verifying the setup Run the CLI's health check: ```bash bitrise-build-cache doctor ``` It reports the status of every part of the local setup and ends with an overall verdict. The probes for the other build tools report as skipped: ```bash Bitrise Build Cache - doctor CLI version: 3.x.y Healthy: ✓ auth OAuth login (keychain) (workspace ), token valid until ✓ keychain-smoke Set/Get/Delete round-trip OK ✓ auth-backend latency , source=keychain, workspace= ✓ xcelerate-proxy skipped (xcode not activated) ✓ xcelerate-wrapper-path skipped (xcode not activated) ✓ xcelerate-enrichment skipped (xcode not activated) ✓ ccache-helper skipped (c++ not activated) ✓ ccache-binary skipped (c++ not activated) ✓ log-dirs no activated tool writes logs Overall: ok ``` To let the CLI repair the issues it can fix on its own, run `bitrise-build-cache doctor --fix --interactive`. ### Running a build 1. Run `bazel clean` first. Bazel's local action cache sits in front of the remote cache, so if a target is already built locally, Bazel serves it from disk and never contacts Bitrise - and you see no evidence that the remote cache works. ```bash cd path/to/your/bazel/project bazel clean ``` 1. Build your target: ```bash bazel build //your/target:name ``` A build that hits a warm cache ends like this: ```bash (16:47:35) INFO: Invocation ID: (16:47:35) INFO: Streaming build results to: https://app.bitrise.io/build-cache/invocations/bazel/ (16:47:36) INFO: Analyzed target //src/close-matching-prs:close-matching-prs (91 packages loaded, 9216 targets configured). (16:47:36) INFO: Found 1 target... (16:47:36) INFO: Elapsed time: 0.934s, Critical Path: 0.18s (16:47:36) INFO: 11 processes: 4 remote cache hit, 7 internal. (16:47:36) INFO: Build completed successfully, 11 total actions ``` ### Checking that it worked The summary line is the proof. It reads differently in each of the three cases: | Summary line | What it means | |---|---| | `11 processes: 4 remote cache hit, 7 internal.` | Working. The actions were fetched from the Bitrise Build Cache. | | `1 process: 4 action cache hit, 1 internal.` | Served from your local cache. The remote cache was never contacted, so run `bazel clean` first. | | `11 processes: 7 internal, 4 processwrapper-sandbox.` | Built locally from scratch. Either the cache has no entries for this target, or authentication failed. Look for `WARNING: Remote Cache: UNAUTHENTICATED` earlier in the output. | `internal` actions, such as symlinks and file writes, are never cacheable. The ratio that matters is remote cache hits against the actions that aren't internal. | Signal | Where to find it | What success looks like | |---|---|---| | `INFO: N processes: X remote cache hit` | Bazel build summary | A non-zero `remote cache hit` count after a `bazel clean` | | `INFO: Streaming build results to:` | First and last lines of the build | A link to the invocation is printed | | Dashboard | The printed link, or the [Build Cache page](https://app.bitrise.io/build-cache/) | A row appears under your display name, with the same hit counts | ### Local builds only read from the cache The setup in this guide activates the Build Cache in pull-only mode: your local builds read from the shared cache but never write to it. This is the recommended mode for local development. Build tools recommend writing cache entries only from an environment where the source files don't change during the build. On a local machine you might keep editing files while a build is running, which can produce cache entries that don't match their inputs, and those entries would then be served to your teammates and to CI. Pull-only removes that risk: a broken local build can't affect anyone else. The usual pattern is to have CI populate the cache, because CI builds from a clean, fixed checkout, and to let local machines pull from it. ### Pushing to the cache from local builds Pull-only assumes that something else fills the cache, which is normally CI. If nothing does, your local builds have nothing to read: the summary line keeps reporting `0 remote cache hit`. If your team doesn't run the Build Cache on CI, turn pushing on for your local builds and leave it on. Your machine then populates the cache as you work, for you and for your teammates. Re-run `bitrise-build-cache activate --interactive` and answer **Yes, push too** at the cache push prompt when you run the wizard, or run the non-interactive activate command: ```bash bitrise-build-cache activate bazel --cache --cache-push ``` You can check which mode you're in without running a build: ```bash grep upload_local_results ~/.bazelrc # --noremote_upload_local_results → pull-only # --remote_upload_local_results → push enabled ``` :::note An entry written from a build whose source files changed while it was running can be wrong, and your teammates read the same entry. Avoid editing files during a build you push from. Setting up the Build Cache on CI is the more robust option, because CI builds from a clean, fixed checkout. Once it runs there, switch your machine back to pull-only. ::: ### Committing the configuration to your repository Bazel already reads a `.bazelrc` from your workspace root, so the cache flags can be committed to the repository instead of being generated on every machine. Onboarding a dev machine then comes down to installing the CLI and signing in: ```bash brew install bitrise-io/bitrise-build-cache/bitrise-build-cache bitrise-build-cache auth login ``` #### How the files combine Bazel reads its configuration files in this order, and the last value wins for a single-valued flag: 1. The system file, `/etc/bazel.bazelrc` 1. The workspace file, `/.bazelrc` (the committed one) 1. The home file, `~/.bazelrc` (what the activation writes, if it was ever run) 1. Command-line flags So the home file takes precedence over the committed one, and command-line flags beat both. Add `--announce_rc` to a build to see what Bazel actually loaded. #### Commit pull-only and let CI opt into push A developer who only installs the CLI and runs `auth login` never gets a `~/.bazelrc`, so there is nothing to override the committed block. Whatever you commit is what they build with, so commit the safe mode: ```bash build --noremote_upload_local_results ``` On CI, run the activation with pushing enabled before the build. Because the home file beats the committed workspace file, it overrides the committed pull-only flag on that machine only: ```bash bitrise-build-cache activate bazel --cache --cache-push ``` That gives you the split with no per-developer setup: the committed file is the pull-only default everyone inherits, and the one environment that should write to the cache is the one that runs the activation. #### What is safe to commit | Lines | Commit | Why | |---|---|---| | `--remote_cache`, `--remote_timeout`, `--bes_backend`, `--bes_results_url`, `--bes_timeout`, `--bes_upload_mode`, `--build_event_publish_all_actions`, `--show_timestamps` | Yes | Identical on every machine | | `--remote_header='x-org-id=…'` and the matching `--bes_header` | Yes | Workspace-wide, not machine-specific | | `--remote_header='x-repository-url=…'` and the matching `--bes_header` | Yes | It identifies this repository | | `--noremote_upload_local_results` | Yes, in the pull-only form | Every developer who only runs `auth login` inherits it. CI flips it by running the activation with `--cache-push` | | `--credential_helper=*.services.bitrise.io=bitrise-build-cache` | Yes, after checking the value | It's the bare binary name, which Bazel looks up on `PATH`. If the activation ran on a machine where the CLI wasn't on `PATH`, the CLI writes an absolute path instead. Don't commit that form | | `--bes_header='x-os=…'`, `x-cpu-cores`, `x-mem-size`, `x-locale`, `x-default-charset` | No | Per-machine, and `x-os` contains your hostname. They're analytics only and don't affect cache keys, but committing them attributes everyone's builds to your machine | | `--remote_header=authorization="Bearer …"` | Never | A live credential. It only appears in a block generated on CI | #### What happens without the CLI installed If you commit the `--credential_helper` line, a teammate who hasn't installed the CLI can't build at all. Bazel looks the helper up on `PATH`, doesn't find it, and fails while initializing the remote cache: ```bash ERROR: Could not find file with name 'bitrise-build-cache' on PATH '...' ERROR: Could not find file with name 'bitrise-build-cache' on PATH '...' ERROR: Could not find file with name 'bitrise-build-cache' on PATH '...' ERROR: Error initializing RemoteModule ``` Bazel exits with code 2 and no targets are built. There's no fallback to a local build, because the failure happens before the build starts. Installing the CLI and running `bitrise-build-cache auth login` on that machine resolves it. ### Remote Build Execution If Remote Build Execution is enabled for your workspace, you can use it locally by adding the `--rbe` flag to the activation. You need the workers set up for your workspace and the pool configuration in your repository's `.bazelrc` first. See [Remote Build Execution for Bazel](/bitrise-build-cache/build-cache-for-bazel/remote-build-execution-for-bazel). ### Troubleshooting Start with the CLI's health check. It inspects every part of the local setup and repairs the issues it can fix on its own: ```bash bitrise-build-cache doctor --fix --interactive ``` If you're still experiencing issues, check the following table: | Issue | Fix | |---|---| | The wizard reports that it needs a terminal | Run `TERM=dumb bitrise-build-cache activate --interactive` for line-based mode. | | The build reports `action cache hit` instead of `remote cache hit` | Run `bazel clean` so Bazel has to fetch from the remote cache. | | The build fails with `Could not find file with name 'bitrise-build-cache' on PATH` | The CLI isn't installed, or isn't on your `PATH`. Install it, then run `bitrise-build-cache auth login`. | | The build fails while fetching credentials, naming the credential helper | The CLI is installed but has no credentials. Run `bitrise-build-cache auth login`. | | `doctor` reports a problem it can't fix | Re-run it with `--debug` for the full context. | | The build can't reach the cache, or the cache calls time out | Your VPN, firewall, or proxy may block the Bitrise hosts. Check them against [Network endpoints for firewalls and VPNs](/bitrise-build-cache/getting-started-with-the-build-cache/network-endpoints-for-firewalls-and-vpns). | --- ## Configuring the build cache for Bazel in other CI environments The Bitrise Build Cache does not require using the Bitrise CI. You can use other CI/CD services and still take advantage of remote caching to improve your Bazel build times. To do so, you need to configure your CI environment to download the Bitrise Build Cache CLI during the build and then run the CLI to enable the Bitrise Build Cache. 1. Select your Bitrise workspace and go to **Build Cache**. 1. Click **New connection**. 1. Select **Other CI provider** and then select your build tool from the dropdown menu. ![2025-10-21-choose-build-tool.png](/img/_paligo/uuid-95236863-449a-87ff-2713-11f9a7f3cfdd.png) 1. Click **Create token**. ![2025-10-21-create-token.png](/img/_paligo/uuid-20c79dca-f52e-e046-e9f2-3fce1c6019ba.png) 1. Enter a name and set it to never expire. 1. Copy the variables and add them to your CI configuration as Environment Variables. 1. Add the following script to your CI configuration before the step you want to speed up: :::important[Environment] Make sure to run the script in the same environment as the Bazel command you want to speed up. For example, if you use multiple Docker containers throughout the build, make sure that the Bitrise Build Cache CLI runs in the same Docker container as the Bazel command. ::: ```bash #!/usr/bin/env bash set -euxo pipefail # download Bitrise Build Cache CLI curl --retry 5 -sSfL 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' | sh -s -- -b /tmp/bin -d # run the CLI to enable Bitrise build cache for Bazel /tmp/bin/bitrise-build-cache activate bazel --cache --cache-push ``` 1. If you have Remote Build Execution enabled for your workspace, you can also use it locally by adding the `--rbe` flag. :::note[Enabling RBE locally] You will need to have the workers set up for your workspace, and the pool configuration in your repository’s `.bazelrc` file before enabling RBE locally! ::: --- ## Configuring the build cache for Bazel in the Bitrise CI environment You can use the Bitrise [Build Cache for Bazel](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-bazel) on the Bitrise CI by adding our dedicated Step to your Workflow. The Step activates the Bitrise Build Cache. After it executes, Bazel builds will automatically read from the build cache and push new entries if it's enabled. **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add the **Bitrise [Build Cache for Bazel](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-bazel)** Step to your Workflow. The Step requires no configuration. **Configuration YAML** 1. Open the `bitrise.yml` file and add the `activate-build-cache-for-bazel` Step to your Workflow. The Step requires no configuration. ```yaml your-workflow: steps: - git-clone: {} - activate-build-cache-for-bazel: ``` During your first build, outputs will be saved to cache. We recommend running a couple of builds to ensure the cache is warmed up. --- ## Remote Build Execution for Bazel Remote execution of a Bazel build allows you to distribute build and test actions across multiple machines. This speeds up build and test execution, allows reuse of build outputs across development teams, and provides a consistent environment. You can use the Bitrise Build Cache with Remote Build Execution both on Bitrise and in a non-Bitrise CI environment. ### Configuring Remote Build Execution on Bitrise **Workflow Editor** 1. Set up the Bitrise [Build Cache for Bazel](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-bazel): [Configuring the build cache for Bazel in the Bitrise CI environment](/bitrise-build-cache/build-cache-for-bazel/configuring-the-build-cache-for-bazel-in-the-bitrise-ci-environment). 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. In the **Bitrise [Build Cache for Bazel](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-bazel)** Step, set the **Enable Bazel RBE** input field to **true**. **Configuration YAML** 1. Open your configuration YAML file. 1. Add the `activate-build-cache-for-bazel` Step to your Workflow. ```yaml your-workflow: steps: - git-clone: {} - activate-build-cache-for-bazel: inputs: - enable_rbe: true ``` ### Configuring Remote Build Execution in a non-Bitrise environment **Other CI** 1. Start setting up the Bitrise [Build Cache for Bazel](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-bazel): [Configuring the build cache for Bazel in other CI environments](/bitrise-build-cache/build-cache-for-bazel/configuring-the-build-cache-for-bazel-in-other-ci-environments). 1. When enabling the Bitrise Build Cache, add the `--rbe` flag. ```bash /tmp/bin/bitrise-build-cache activate bazel --cache --cache-push=false --rbe ``` :::note[Cache] We recommend setting the `--cache-push` flag to false because during remote build execution, workers upload results to the cache. ::: **Local environment** 1. Start setting up the Bitrise [Build Cache for Bazel](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-bazel): [Configuring the build cache for Bazel in local builds](/bitrise-build-cache/build-cache-for-bazel/configuring-the-build-cache-for-bazel-in-local-builds). 1. Add the RBE endpoint config to your `.bazelrc`: ```yaml build:remote --remote_executor=grpcs://bitrise-accelerate.services.bitrise.io:443 ``` ### Recommended flags for Remote Build Execution Bazel offers a number of command flags that are needed to get the most out of Remote Build Execution. We recommend adding them to your `.bazelrc` file so you can reuse them: ```yaml build:remote --jobs=100 build:remote --noremote_upload_local_results build:remote --spawn_strategy=remote,local build:remote --remote_default_exec_properties=Pool= ``` Replace `` with the name of your worker pool. If you have worker pools in multiple data centers, use the same pool name in each data center so the same configuration works everywhere. With everything in place, you can invoke Remote Build Execution by adding the remote config to any Bazel command: ```bash bazel build //... --config=remote ``` What each flag does: | Flag and recommended values | Description | | --- | --- | | `--jobs=100` | Defines the maximum number of build/test actions Bazel may have "in flight" at once. If you omit the flag Bazel silently falls back to the number of logical CPU cores on the host VM. That default is appropriate for local execution but severely underutilizes the RBE cluster. `--jobs=100` is a good starting point for most Android/iOS monorepos but it can be increased gradually based on the worker count. | | `--remote_default_exec_properties=Pool=` | Selects the worker pool that runs your remote actions. The value is the name of your worker pool as shown on Bitrise. The property set must match the worker pool exactly: make sure that no other `exec_properties` are set anywhere for the targets, otherwise Bazel will not match the worker pool and the build will fail. | | `--spawn_strategy=remote,local` | Determines the order in which Bazel tries to execute an action. Bazel will use the first strategy in the list that can run a given action. The default value is `remote,worker,sandboxed,local`. Keep remote first so actions run in your remote execution environment, with a graceful fallback to local execution. | | `--noremote_upload_local_results` | Skips re‑uploading outputs that were produced locally. Remote workers already push artifacts to the cache, saving bandwidth. This config flag is also configured via Bitrise Build Cache CLI. If you use it, please make sure that `--cache-push` flag is false or off in the CLI when you use this flag. | ### Selecting a worker pool per target `--remote_default_exec_properties` applies to the whole invocation, and Bazel ignores it for any target whose execution platform sets its own `exec_properties`. To route different targets to different worker pools — for example, running tests on a pool with a different macOS image — define a platform for each pool and set the `Pool` property there: ```python platform( name = "macos_tests", constraint_values = [ "@platforms//os:macos", "@platforms//cpu:arm64", ], exec_properties = {"Pool": ""}, ) ``` Register the platform with `--extra_execution_platforms` and use standard Bazel platform and toolchain resolution to assign targets to it. --- ## Configuring the build cache for Gradle in local builds You can use the Bitrise Build Cache for local Gradle builds too. Your local builds then read from the same cache as your CI builds, so a task your CI already compiled doesn't have to be compiled again on your machine. The Bitrise Build Cache CLI sets this up for you. It writes a Gradle init script to `~/.gradle/init.d/`, so your project files stay untouched. ### Before you start Ensure you have: - A working Gradle project on your machine (macOS or Linux). - A Bitrise workspace with the Build Cache enabled. Check it on the [Build Cache page](https://app.bitrise.io/build-cache/). - Network access to the Bitrise hosts the Build Cache uses, if your machine is behind a VPN, a firewall, or an outbound proxy. See [Network endpoints for firewalls and VPNs](/bitrise-build-cache/getting-started-with-the-build-cache/network-endpoints-for-firewalls-and-vpns). :::note[Android projects with native code] If your project builds C/C++ code (NDK, JNI, or native modules), set up `ccache` alongside Gradle. The Gradle plugin caches Java and Kotlin task outputs, but native compiles bypass it and go through `ccache` instead. Install it with `brew install ccache`, then select both **Gradle** and **ccache (C/C++)** in the wizard. ::: ### Installing the CLI Install the CLI with Homebrew (**recommended**): ```bash brew install bitrise-io/bitrise-build-cache/bitrise-build-cache ``` Or, without Homebrew: ```bash curl --retry 5 -sSfL \ 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' \ | sh -s -- -b ~/.local/bin ``` Make sure the install location is on your `PATH`, then check the install: ```bash bitrise-build-cache --version ``` ### Activating the cache Run the interactive wizard: ```bash bitrise-build-cache activate --interactive ``` The wizard asks for the following: 1. **Sign in to Bitrise**: opens your browser for authentication on the first run. The CLI stores the credentials in the OS keychain and refreshes them automatically, so later runs skip this step. On a machine without a usable keychain, the CLI falls back to storing them in a config file. 1. **Select a workspace**: pick the workspace whose Build Cache you want to use. The CLI selects it automatically if you only have access to one. 1. **Which build tools should I set up**: ensure **Gradle** is selected, plus **ccache (C/C++)** if your project builds native code. Use space to toggle an option and enter to confirm. 1. **Display name for this machine's local invocations**: the name your local builds show up under in the Build Cache dashboard, for example `local-`. 1. **Enable cache push**: select **No, pull only**. See [Local builds only read from the cache](#local-builds-only-read-from-the-cache). 1. **Keep the cache proxies running in the background**: select **Yes, install + start** if you set up `ccache`. This registers the helper processes with the OS so they survive shell restarts. :::note[Environment Variables take precedence] If `BITRISE_BUILD_CACHE_AUTH_TOKEN` and `BITRISE_BUILD_CACHE_WORKSPACE_ID` are already set in your shell, the CLI uses those instead of the stored credentials. Unset them if you want the sign-in to apply. ::: ### Verifying the setup Run the CLI's health check: ```bash bitrise-build-cache doctor ``` It reports the status of every part of the local setup — credentials, backend connectivity, helper processes, and log directories — and ends with an overall verdict: ```bash Bitrise Build Cache - doctor CLI version: 3.x.y Healthy: ✓ auth OAuth login (keychain) (workspace ), token valid until ✓ keychain-smoke Set/Get/Delete round-trip OK ✓ auth-backend latency , source=keychain, workspace= ✓ ccache-binary found at /opt/homebrew/bin/ccache ✓ ccache-helper running (~/.local/state/ccache/ccache.sock) ✓ log-dirs all log dirs present + writable Overall: ok ``` To let the CLI repair the issues it can fix on its own, run `bitrise-build-cache doctor --fix --interactive`. ### Running a build 1. Clean the project's local build outputs first, so the build has to fetch from the remote cache. Pass `--no-daemon` as well: a Gradle daemon started before the activation doesn't pick up the new configuration. ```bash cd path/to/your/gradle/project ./gradlew clean --no-daemon ``` 1. Run the build: ```bash ./gradlew :app:assembleDebug ``` A build that hits a warm cache ends like this: ```bash > Task :app:compileDebugKotlin FROM-CACHE > Task :feature:one:compileDebugKotlin FROM-CACHE BUILD SUCCESSFUL in 18s 149 actionable tasks: 71 executed, 78 from cache [Bitrise Analytics] 155 tasks uploaded. Check invocation at https://app.bitrise.io/build-cache/invocations/gradle/ ``` ### Checking that it worked | Signal | Where to find it | What success looks like | |---|---|---| | `Task :module:name FROM-CACHE` | Gradle build output, per task | The task line ends with `FROM-CACHE` | | `N actionable tasks: X executed, Y from cache` | Gradle build summary | A non-zero `from cache` count | | Invocation link | Printed at the end of the build | Opens the per-task metrics for the build | | Dashboard | [Build Cache page](https://app.bitrise.io/build-cache/) | A row appears under your display name | | Init script | `~/.gradle/init.d/bitrise-build-cache.init.gradle.kts` | The file exists and contains `buildCache {` | ### Local builds only read from the cache The setup in this guide activates the Build Cache in pull-only mode: your local builds read from the shared cache but never write to it. This is the recommended mode for local development. Build tools recommend writing cache entries only from an environment where the source files don't change during the build. On a local machine you might keep editing files while a build is running, which can produce cache entries that don't match their inputs — and those entries would then be served to your teammates and to CI. Pull-only removes that risk: a broken local build can't affect anyone else. The usual pattern is to have CI populate the cache, because CI builds from a clean, fixed checkout, and to let local machines pull from it. ### Pushing to the cache from local builds Pull-only assumes that something else fills the cache, which is normally CI. If nothing does, your local builds have nothing to read: the summary line says `0 from cache`, and it keeps saying that. If your team doesn't run the Build Cache on CI, turn pushing on for your local builds and leave it on. Your machine then populates the cache as you work, for you and for your teammates. Re-run `bitrise-build-cache activate --interactive` and answer **Yes, push too** at the cache push prompt when you run the wizard, or run the non-interactive activate command: ```bash bitrise-build-cache activate gradle --cache --cache-push ``` If a build doesn't behave as expected, re-run the activation with debug logging: ```bash bitrise-build-cache activate gradle --cache --cache-push --debug ``` :::note An entry written from a build whose source files changed while it was running can be wrong, and your teammates read the same entry. Avoid editing files during a build you push from. Setting up the Build Cache on CI is the more robust option, because CI builds from a clean, fixed checkout. Once it runs there, switch your machine back to pull-only. ::: ### Troubleshooting Start with the CLI's health check. It inspects every part of the local setup and repairs the issues it can fix on its own: ```bash bitrise-build-cache doctor --fix --interactive ``` If you're still experiencing issues, check the following table: | Issue | Fix | |---|---| | The wizard reports that it needs a terminal | Run `TERM=dumb bitrise-build-cache activate --interactive` for line-based mode. | | `doctor` reports a problem it can't fix | Re-run it with `--debug` for the full context. | | Your build ignores the new configuration | Stop any running Gradle daemons with `./gradlew --stop`, or pass `--no-daemon`. | | You want to start over | It's safe to re-run the wizard. It re-reads the current state and applies the same activation again. | | The build can't reach the cache, or the cache calls time out | Your VPN, firewall, or proxy may block the Bitrise hosts. Check them against [Network endpoints for firewalls and VPNs](/bitrise-build-cache/getting-started-with-the-build-cache/network-endpoints-for-firewalls-and-vpns). | --- ## Configuring the build cache for Gradle in other CI environments The Bitrise Build Cache does not require using the Bitrise CI. You can use other CI/CD services and still take advantage of the cache to improve your Gradle build times. To do so, you need to configure your CI environment to download the Bitrise Build Cache CLI during the build and then run the CLI to enable the Bitrise Build Cache. 1. Select your Bitrise workspace and go to **Build Cache**. 1. Click **New connection**. 1. Select **Other CI provider** and then select your build tool from the dropdown menu. ![2025-10-21-choose-build-tool.png](/img/_paligo/uuid-95236863-449a-87ff-2713-11f9a7f3cfdd.png) 1. Click **Create token**. ![2025-10-21-create-token.png](/img/_paligo/uuid-20c79dca-f52e-e046-e9f2-3fce1c6019ba.png) 1. Enter a name and set it to never expire. 1. Copy the variables and add them to your CI configuration as Environment Variables. 1. Add the following script to your CI configuration before the step you want to speed up: :::important[Environment] Make sure to run the script in the same environment as the Gradle command(s) you want to speed up. For example, if you use multiple Docker containers throughout the build, make sure that the Bitrise Build Cache CLI runs in the same Docker container as the Gradle command. ::: ```bash #!/usr/bin/env bash set -euxo pipefail # download Bitrise Build Cache CLI curl --retry 5 -sSfL 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' | sh -s -- -b /tmp/bin -d # run the CLI to enable Bitrise build cache for Gradle /tmp/bin/bitrise-build-cache activate gradle --cache --cache-push ``` --- ## Configuring the build cache for Gradle in the Bitrise CI environment In the Bitrise CI environment, you only need our official Step to use the Bitrise Build Cache for your Gradle builds. If you want to use the Bitrise Build Cache [in your local builds](/bitrise-build-cache/build-cache-for-gradle/configuring-the-build-cache-for-gradle-in-local-builds), you need to first activate it in our CI environment. **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add the [**Build Cache for Gradle**](https://github.com/bitrise-steplib/bitrise-step-activate-gradle-remote-cache) Step to your Workflow. The Step should be before any Step that executes Gradle tasks, such as [**Gradle Runner**](https://github.com/bitrise-io/steps-gradle-runner) or [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build). ![gradle-cache-image.png](/img/_paligo/uuid-1afefa9a-7cc1-db41-6186-0ee56293458c.png) **Configuration YAML** 1. Open the `bitrise.yml` file and add the `activate-build-cache-for-gradle` Step to your Workflow. The Step should be before any Step that executes Gradle tasks, such as `gradle-runner` or `android-build`. ```yaml your-workflow: steps: - git-clone@8: {} - activate-build-cache-for-gradle: ``` --- ## Gradle configuration cache Gradle configuration cache reduces build times by caching the result of a Gradle project's configuration phase and reusing it in subsequent builds. For details, read [Gradle's official documentation](https://docs.gradle.org/current/userguide/configuration_cache.html). The [Bitrise Build Cache](https://bitrise.io/platform/devops/build-caching) supports this feature for Gradle 8.6 and later versions. ### Setting up the configuration cache To set up the configuration cache: 1. Make sure you have a subscription or a trial for the [Bitrise Build Cache](https://bitrise.io/platform/devops/build-caching). 1. Run a build locally with the `--configuration-cache` flag. This ensures that your Gradle project supports configuration caching. To enable configuration caching in the Gradle settings, [refer to Gradle's official guide](https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:usage:enable). 1. Generate a Gradle encryption key: ``` openssl rand -base64 16 ``` 1. Save the key as a [Secret](/bitrise-ci/configure-builds/secrets) named GRADLE_ENCRYPTION_KEY in your Bitrise project. This ensures that the encrypted value of the configuration cache remains the same across different builds. Using a fixed encryption key is supported from Gradle version 8.6 or later. Bitrise doesn't support Gradle configuration cache for earlier Gradle versions. 1. Add the **Build Cache for Gradle** Step to your Workflow. The Step must be of version 2.7.7 or later. Any subsequent updates to the Step will cause a one-off invalidation of the configuration cache. If this happens, do a rebuild to fix the issue. :::note[Authentication tokens] From Step version 3.6.1, the Gradle plugins authenticate with the token of the build that is running, so you don't need to set up an authentication token for the configuration cache. On earlier Step versions, the token is part of the cached configuration and has to stay the same across builds. Those versions need a [personal access token](/bitrise-platform/accounts/personal-access-tokens#creating-a-personal-access-token) saved as a [Secret](/bitrise-ci/configure-builds/secrets) with the BITRISE_BUILD_CACHE_AUTH_TOKEN key, and your [workspace slug](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs) as an Environment Variable named BITRISE_BUILD_CACHE_WORKSPACE_ID. ::: 1. Add the **Restore Gradle configuration cache** and the **Restore Gradle Cache** Steps before your Gradle invocation in the Workflow. The Steps retrieve cached configuration data and enable the configuration cache to access artifacts it references. :::note[Configuration cache directory] The **Restore Gradle configuration cache** Step saves data in the `./.gradle/configuration-cache` directory. You can override this by changing the **Configuration cache directory** input. ::: For example, if you use **Android Build** to build your Gradle project, these two Steps must come before it in the Workflow. 1. Add the **Save Gradle configuration cache** and the **Save Gradle Cache** Steps after your Gradle invocation in the Workflow. The Steps save the configuration data to the cache and save artifacts referenced by the configuration cache. 1. Enable the **Save transforms** input of the **Save Gradle Cache** Step. You need Step version 1.4.1 or later. ### Saving the Gradle configuration cache log Gradle's build logs might contain information about why it didn't reuse the configuration cache. You can save the log to the **Artifacts** page of your build: 1. Enable the `--info` [log level](https://docs.gradle.org/current/userguide/logging.html) in Gradle. 1. Add the **Deploy to Bitrise.io** Step to your Workflow. 1. Set the **Deploy directory or file path** input to what Gradle outputs as the file path. You can check the deployed file on the **Artifacts** page: open Bitrise CI, select your project and then the build, and select the **Artifacts** tab. ### Troubleshooting the configuration cache If your build doesn't reuse the configuration cache, you can check a number of potential problems. #### General troubleshooting - Make sure to add the Save/Restore Gradle cache Steps to utilize dependency caching. Gradle configuration cache references artifacts that must be present. - It may take multiple runs before the configuration cache is fully applied and reused. - Check the Gradle logs to find out why Gradle didn't reuse the configuration cache. You can [save the gradle configuration cache log](#saving-the-gradle-configuration-cache-log) to your build artifacts. - Updates to the **Build Cache for Gradle** Step will cause a one-off invalidation of the configuration cache. Just run another build to fix the problem. - On Step versions before 3.6.1, check that the authentication token is the same in every build. A token that changes between builds invalidates the cached configuration. #### Failed to instrument class error Your build could fail with the following error: ``` org.gradle.internal.operations.BuildOperationInvocationException: Failed to instrument class io/bitrise/gradle/cache/BitriseBuildCache in ClassLoaderScopeIdentifier.Id{coreAndPlugins:init-file:/root/.gradle/init.d/bitrise-build-cache.init.gradle.kts(export)} ``` To fix this issue: 1. In the **Save Gradle cache** Step, set the **Save transforms** input to **true**. :::note[Version requirement] The input is only available from version 1.4.1 or later. ::: 1. Force a save by running a build without the **Restore Gradle cache** Step. --- ## Gradle execution reason diagnostic builds Cache hit ratio is a measurement of how many content requests a cache is able to fill successfully, compared to how many requests it receives. Getting a high amount of cache misses slows down your build as it doesn't take full advantage of caching. When running Gradle tasks, a change in task inputs usually lead to a cache miss. Gradle's execution reasons can help understand why the change in inputs happened, and to debug the problem. You can keep on reading to understand the details of how Gradle tasks and their caching works. To learn how to set up diagnostic builds on Bitrise, skip ahead to [Diagnostic builds](#diagnostic-builds). ### Gradle tasks and caching In the Gradle build system, the basic unit of action is a task. A task could be compiling classes, running unit tests, or creating a JAR. Each task has its own inputs, such as files or environmental variables, and outputs. Tasks usually generate their output in a specific build directory which is configurable for each module. The contents of this directory can be often reused between builds on the same machine. As such, Gradle saves time by executing only the tasks that can't be reused. For other tasks, the output from the build directory is reused and the task gets the `UP-TO-DATE` label. This process is what Gradle calls an [incremental build](https://docs.gradle.org/current/userguide/incremental_build.html). :::note[Incremental build vs incremental task execution] Incremental builds are not the same as incremental task execution! You can read about incremental tasks [in Gradle's official docs](https://docs.gradle.org/current/userguide/custom_tasks.html#incremental_tasks). ::: #### Gradle tasks in a CI environment When running Gradle in a CI environment, all tasks are either executed or retrieved from cache because the build directory is empty. After execution, Gradle saves metadata about the task inputs in the [project cache directory](https://docs.gradle.org/current/userguide/directory_layout.html). Gradle uses this metadata to be able to perfom incremental builds. For example, in the case of a compile task, Gradle saves the checksum of the source files and only re-compiles files that have changed, based on the checksums. For more information on how Gradle checks task inputs, [read Gradle’s docs on task inputs and outputs.](https://docs.gradle.org/current/userguide/incremental_build.html#sec:task_inputs_outputs) If metadata is not available, Gradle will execute all tasks. #### Caching tasks If the metadata indicates that a task has to be executed, and the Bitrise build cache is enabled, the task inputs and certain Gradle properties such as the version are hashed into the cache key. If either the remote or local cache has a match for the cache key, the task does not have to be fully executed: its execution result is loaded from the cache and gets the `FROM-CACHE` outcome label. If there is no match for the cache key in the remote or local cache (a cache miss), the task is fully executed and its outputs are stored in the cache. When a task doesn't have the `UP-TO-DATE` label, the reasons for this are recorded and displayed in the task's row in the invocation details on Bitrise. Some of the possible reasons are as follows: - If the metadata is missing, **No history available** is displayed. - If the outputs are missing, **Output... has been removed** is displayed. - Tasks without the `UP-DO-DATE` label can still be cached if their inputs were cached at least once previously. ### Diagnostic builds To understand what changes contribute to a task’s execution, you’ll need the Gradle metadata and the build outputs from a previous build. Restoring them on a CI environment simulates a local incremental build, showing the changes between builds that contribute to cache misses. These builds are called diagnostic builds on Bitrise. :::important[Debugging purposes only] Diagnostic builds heavily use [key-based caching](/bitrise-ci/dependencies-and-caching/key-based-caching/accessing-key-based-cache-archives) and have increased build time. Their purpose is debugging and they shouldn't be a part of your daily workflows! The archive limit for key-based cache is 15 Gb. If your app’s outputs exceed that, you can run two separate builds with the same principle, using your own artifact storage solution. ::: To set up and run a Gradle diagnostic build: 1. Create a CI configuration that: - Saves the build outputs and Gradle metadata with the Bitrise Build Cache CLI. - Restores the build outputs and metadata from cache. 1. Run an initial build to save the necessary directories in the key-based cache. 1. Run the diagnostic build to reveal Gradle execution reasons. #### Creating the CI configuration for a diagnostic build To create a CI configuration for a Gradle diagnostic build, your Bitrise Workflow will need two new Steps to save and restore build outputs, using the Bitrise Build Cache CLI. :::note[Do not use key-based caching Steps] Diagnostic builds use key-based caching but for this purpose, do not use our dedicated key-based caching Steps. Set up **Script** Steps as they are described in this guide. ::: **Workflow Editor** 1. Create a new Workflow for the diagnostic build. If you store your `bitrise.yml` file [in your repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository), we recommend creating a new branch, too, and run the diagnostic build from that branch. 1. Add the **Build Cache for Gradle** Step to the Workflow. 1. After the Step that runs your Gradle tasks (for example, **Android Build**), add a **Script** Step. :::important[Environment] Make sure to run the script in the same environment as the Gradle command(s) you want to speed up. For example, if you use multiple Docker containers throughout the build, make sure that the Bitrise Build Cache CLI runs in the same Docker container as the Gradle command. ::: 1. To the **Script content** input, add the following: ```bash /tmp/bin/bitrise-build-cache save-gradle-output-data ``` This saves the Gradle metadata directory and the build outputs to the key-based cache under a cache key unique for your Workspace, app, and Workflow. 1. Before the Step that runs your Gradle tasks, add another **Script** Step. 1. To the **Script content** input, add the following: ```bash /tmp/bin/bitrise-build-cache restore-gradle-output-data ``` This Step accesses the cache and restores your Gradle build data. **Configuration YAML** 1. Create a new Workflow for the diagnostic build. If you store your `bitrise.yml` file [in your repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository), we recommend creating a new branch, too, and run the diagnostic build from that branch. 1. Add the `activate-build-cache-for-gradle` Step to your Workflow. 1. After the Step that runs your Gradle tasks (for example, `android-build`), add a `script` Step. :::important[Environment] Make sure to run the script in the same environment as the Gradle command(s) you want to speed up. For example, if you use multiple Docker containers throughout the build, make sure that the Bitrise Build Cache CLI runs in the same Docker container as the Gradle command. ::: 1. To the `content` input, add: ```yaml - script: inputs: - content: |- /tmp/bin/bitrise-build-cache save-gradle-output-data ``` This saves the Gradle metadata directory and the build outputs to the key-based cache under a cache key unique for your Workspace, app, and Workflow. 1. Before the Step that runs your Gradle tasks, add another `script` Step. 1. To the `content` input, add `/tmp/bin/bitrise-build-cache restore-gradle-output-data`: ```yaml - script: inputs: - content: |- /tmp/bin/bitrise-build-cache restore-gradle-output-data ``` This Step accesses the cache and restores your Gradle build data. #### Saving the directories in the key-based cache When setting up a Gradle diagnostic build for the first time, you need to run an initial build with the [created configuration](#creating-the-ci-configuration-for-a-diagnostic-build) to save the necessary directories in the key-based cache. This initial build will not show any execution reason in the invocation details. 1. Once the CI configuration is complete, run a build. 1. Check the logs to make sure the uploads have been successfully completed. ![upload-complete.png](/img/_paligo/uuid-223b519e-cddd-6157-de92-bfdf36d7ba2d.png) #### Running and checking a diagnostic build After the [CI configuration is complete](#creating-the-ci-configuration-for-a-diagnostic-build) and [an initial build has successfully uploaded](#running-and-checking-a-diagnostic-build) the necessary directories to the key-based cache, you can run a diagnostic build to reveal execution reasons for Gradle tasks. Make sure you use the same Workflow and branch as the initial build With a diagnostic build, Gradle will behave as if it was an incremental local build. 1. Run the build. 1. Open [the Build Cache page](https://app.bitrise.io/build-cache/). 1. Among the **Latest invocations**, find the tasks you need. A blue icon will show you the tasks that contain task execution reasons: ![invocations-significant.png](/img/_paligo/uuid-f63b2a01-2f9d-fb91-dc1d-a94aa4d3e386.png) You will see changes related to your CI configuration that frequently cause cache task input changes and cache misses. ![task-reason.png](/img/_paligo/uuid-60ec20cb-92a4-2e4d-c084-55988b170c60.png) To successfully interpret and debug these reasons, you can check out the [relevant Gradle documentation](https://docs.gradle.org/current/userguide/build_cache_debugging.html) or delve into our [debugging tips](https://discuss.bitrise.io/t/debugging-and-optimizing-bitrise-build-cache-for-gradle/23275). --- ## Build Cache for React Native overview Bitrise Build Cache for React Native speeds up your CI builds by caching native compilation artifacts across builds. It covers all three native build systems used in a React Native project: - **Gradle**: Android build outputs (compiled classes, resources, dex files) are cached via Bitrise's remote build cache. - **Xcode**: iOS compilation results are cached via Bitrise's remote build cache (the same backend used for Gradle and Bazel). - **C++ native modules**: Compiled native bridge code and third-party native modules are cached via `ccache`, with cache entries shared across builds through Bitrise's remote build cache. By caching native compilation outputs, subsequent CI builds can skip recompiling unchanged native code. This is especially effective for React Native projects where the native layer changes infrequently compared to the JS layer. --- ## Configuring the Build Cache for React Native in local builds You can use the Bitrise Build Cache for local React Native builds too. Your local builds then read from the same cache as your CI builds, so native code your CI already compiled doesn't have to be compiled again on your machine. A React Native project builds through three native toolchains, and the Bitrise Build Cache CLI covers all of them: Gradle for Android, Xcode for iOS, and `ccache` for C++ native modules. For an overview of what each one caches, see [Build Cache for React Native overview](/bitrise-build-cache/build-cache-for-react-native/build-cache-for-react-native-overview). ### Before you start Ensure you have: - A working React Native project on your machine, with Xcode 26 or later for the iOS side. Earlier versions don't expose the compilation cache flags the CLI needs, and the wrapper does nothing there. - A Bitrise workspace with the Build Cache enabled. Check it on the [Build Cache page](https://app.bitrise.io/build-cache/). - Network access to the Bitrise hosts the Build Cache uses, if your machine is behind a VPN, a firewall, or an outbound proxy. See [Network endpoints for firewalls and VPNs](/bitrise-build-cache/getting-started-with-the-build-cache/network-endpoints-for-firewalls-and-vpns). ### Installing the CLI and ccache **Homebrew** ```bash brew install bitrise-io/bitrise-build-cache/bitrise-build-cache brew install ccache ``` **curl** Install the CLI with the installer script and [download `ccache`](https://ccache.dev/download.html) manually: ```bash curl --retry 5 -sSfL \ 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' \ | sh -s -- -b ~/.local/bin ``` Make sure both install locations are on your `PATH`, then check the installs: ```bash bitrise-build-cache --version which ccache ``` ### Activating the cache Run the interactive wizard: ```bash bitrise-build-cache activate --interactive ``` The wizard asks for the following: 1. **Sign in to Bitrise**: opens your browser for authentication on the first run. The CLI stores the credentials in the OS keychain and refreshes them automatically, so later runs skip this step. 1. **Select a workspace**: pick the workspace whose Build Cache you want to use. The CLI selects it automatically if you only have access to one. 1. **Which build tools should I set up**: ensure **Gradle**, **Xcode**, and **ccache (C/C++)** are selected. Use space to toggle an option and enter to confirm. 1. **Display name for this machine's local invocations**: the name your local builds show up under in the Build Cache dashboard, for example `local-`. 1. **Enable cache push**: select **No, pull only**. See [Local builds only read from the cache](#local-builds-only-read-from-the-cache). 1. **Keep the cache proxies running in the background**: select **Yes, install + start**. This registers the helper processes with the OS so they survive shell restarts. :::important[Open a new terminal afterwards] Activating Xcode prepends `~/.bitrise-xcelerate/bin` to your `PATH` by writing a line to your shell rc file. Your current shell hasn't picked that up yet, so builds started in it still run without the `xcodebuild` wrapper — and `doctor` won't warn you about it. ::: Open a new terminal, or run `source ~/.zshrc`, then confirm that the wrapper is in place: ```bash which xcodebuild # → /Users//.bitrise-xcelerate/bin/xcodebuild ``` ### Verifying the setup Run the CLI's health check: ```bash bitrise-build-cache doctor ``` It reports the status of every part of the local setup — credentials, backend connectivity, helper processes, and log directories — and ends with an overall verdict: ```bash Bitrise Build Cache - doctor CLI version: 3.x.y Healthy: ✓ auth OAuth login (keychain) (workspace ), token valid until ✓ keychain-smoke Set/Get/Delete round-trip OK ✓ auth-backend latency , source=keychain, workspace= ✓ ccache-binary found at /opt/homebrew/bin/ccache ✓ xcelerate-proxy running (/var/folders/…/T/xcelerate-proxy.sock) ✓ xcelerate-enrichment no enrichment attempts yet ✓ ccache-helper running (~/.local/state/ccache/ccache.sock) ✓ log-dirs all log dirs present + writable Overall: ok ``` `xcelerate-enrichment` changes from `no enrichment attempts yet` to `healthy` after your first build. To let the CLI repair the issues it can fix on its own, run `bitrise-build-cache doctor --fix --interactive`. ### Running an Android build 1. Clean the project's local build outputs first, so the build has to fetch from the remote cache. Pass `--no-daemon` as well: a Gradle daemon started before the activation doesn't pick up the new configuration. ```bash cd path/to/your/rn/project/android ./gradlew clean --no-daemon ``` 1. Run the build: ```bash cd .. bitrise-build-cache react-native run -- npx react-native build-android ``` A build that hits a warm cache ends like this: ```bash > Task :app:compileDebugKotlin FROM-CACHE BUILD SUCCESSFUL in 22s 149 actionable tasks: 71 executed, 78 from cache [Bitrise Analytics] 155 tasks uploaded. Check invocation at https://app.bitrise.io/build-cache/invocations/gradle/ ``` ### Running an iOS build Run the build through the CLI's wrapper command: ```bash bitrise-build-cache react-native run -- npx react-native build-ios ``` Or call `xcodebuild` directly if you want full control over the destination and configuration: ```bash xcodebuild \ -workspace ios/.xcworkspace \ -scheme \ -configuration Debug \ -sdk iphonesimulator \ -destination 'generic/platform=iOS Simulator' \ CODE_SIGNING_ALLOWED=NO clean build ``` Expect a `CompilationCacheMetrics` line with non-zero hits and a `[Bitrise Analytics] Invocation saved` link at the end of the output. Native modules compile through `ccache`, and their stats are included in the same invocation. For more about which commands to wrap and why, see [Wrapping native build commands](/bitrise-build-cache/build-cache-for-react-native/wrapping-native-build-commands). ### Checking that it worked | Signal | Where to find it | What success looks like | |---|---|---| | `FROM-CACHE` and the `Y from cache` summary | Android build output | A non-zero `from cache` count | | `CompilationCacheMetrics N / M (P%)` | iOS build output | Non-zero hits | | `[Bitrise Analytics] Invocation saved` | Last lines of the build output | An invocation link is printed | | Dashboard | [Build Cache page](https://app.bitrise.io/build-cache/) | One row per iOS build and one per Android build, under your display name | | `bitrise-build-cache doctor` | Your shell | `xcelerate-proxy`, `xcelerate-enrichment`, and `ccache-helper` are all healthy | :::note[Explicit module build warnings] A few `swift compiler caching requires explicit module build` warnings can appear even though the wrapper sets `SWIFT_ENABLE_EXPLICIT_MODULES=YES`. Xcode emits them before the wrapper's build settings apply, and they are safe to ignore. The cache hit numbers confirm that caching is working. ::: Some projects can't build under explicit modules at all, and fail with `unable to resolve module dependency`. Activate with `--no-swift-cache` there: it caches clang and Objective-C compilation only, leaving Swift uncached. The wizard doesn't ask about this, so use the non-interactive activate command: ```bash bitrise-build-cache activate react-native --no-swift-cache ``` ### Local builds only read from the cache The setup in this guide activates the Build Cache in pull-only mode: your local builds read from the shared cache but never write to it. This is the recommended mode for local development. Build tools recommend writing cache entries only from an environment where the source files don't change during the build. On a local machine you might keep editing files while a build is running, which can produce cache entries that don't match their inputs — and those entries would then be served to your teammates and to CI. Pull-only removes that risk: a broken local build can't affect anyone else. The usual pattern is to have CI populate the cache, because CI builds from a clean, fixed checkout, and to let local machines pull from it. ### Pushing to the cache from local builds Pull-only assumes that something else fills the cache, which is normally CI. If nothing does, your local builds have nothing to read: the Android build keeps reporting `0 from cache` and the iOS build `0 / N (0%)`. If your team doesn't run the Build Cache on CI, turn pushing on for your local builds and leave it on. Your machine then populates the cache as you work, for you and for your teammates. Re-run the wizard and answer **Yes, push too** at the cache push prompt: ```bash bitrise-build-cache activate --interactive ``` This covers all three backends at once, so your Android, iOS, and native module builds all start writing to the cache. If a build doesn't behave as expected, re-run the wizard with debug logging: ```bash bitrise-build-cache activate --interactive --debug ``` :::note If `xcelerate-proxy` or `ccache-helper` was already running from an earlier activation, the new push setting won't take effect until you restart it — both lock in push-enablement at start-up and don't reload it when you re-run the wizard. Restart them: ```bash bitrise-build-cache xcelerate stop-proxy bitrise-build-cache ccache storage-helper stop bitrise-build-cache activate --interactive ``` ::: :::note An entry written from a build whose source files changed while it was running can be wrong, and your teammates read the same entry. Avoid editing files during a build you push from. Setting up the Build Cache on CI is the more robust option, because CI builds from a clean, fixed checkout. Once it runs there, switch your machine back to pull-only. ::: ### Troubleshooting Start with the CLI's health check. It inspects every part of the local setup and repairs the issues it can fix on its own: ```bash bitrise-build-cache doctor --fix --interactive ``` If you're still experiencing issues, check the following table: | Issue | Fix | |---|---| | The wizard reports that it needs a terminal | Run `TERM=dumb bitrise-build-cache activate --interactive` for line-based mode. | | `which xcodebuild` still points to `/usr/bin/xcodebuild` | Open a new terminal, or run `source ~/.zshrc`. | | The iOS build shows no cache activity at all | Check that you ran it from a terminal and not from Xcode.app, which bypasses the wrapper. | | Your Android build ignores the new configuration | Stop any running Gradle daemons with `./gradlew --stop`, or pass `--no-daemon`. | | `doctor` reports a problem it can't fix | Re-run it with `--debug` for the full context. | | The build can't reach the cache, or the cache calls time out | Your VPN, firewall, or proxy may block the Bitrise hosts. Check them against [Network endpoints for firewalls and VPNs](/bitrise-build-cache/getting-started-with-the-build-cache/network-endpoints-for-firewalls-and-vpns). | --- ## Configuring the Build Cache for React Native in non-Bitrise CI environments The Bitrise Build Cache CLI can be downloaded and run on any third-party CI provider (GitHub Actions, GitLab CI, CircleCI, Jenkins, etc.). 1. Create a [Personal Access Token](urn:resource:component:54560). 1. [Get your Workspace slug](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs). 1. Set two variables in your CI provider's secret/environment settings: - BITRISE_BUILD_CACHE_AUTH_TOKEN: your Personal Access Token. - BITRISE_BUILD_CACHE_WORKSPACE_ID: your Workspace slug. 1. Add the following script to your CI pipeline before any Step that runs a build. It must run in the same environment (same shell, same container) as the build commands it's meant to accelerate. ```bash #!/usr/bin/env bash set -euxo pipefail # Download the Bitrise Build Cache CLI. curl --retry 5 -sSfL \ 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' \ | sh -s -- -b /tmp/bin -d # Activate Build Cache for React Native (Gradle + Xcode + ccache for C++). /tmp/bin/bitrise-build-cache activate react-native ``` By default this enables all three backends. To disable a backend, pass the matching flag: ``` /tmp/bin/bitrise-build-cache activate react-native --gradle=true --xcode=true --cpp=false ``` CI is normally the environment that fills the cache. Pass `--cache-push` to activate write access alongside reads: ``` /tmp/bin/bitrise-build-cache activate react-native --cache-push ``` :::note If you have previously used the Bitrise Build Cache CLI for Gradle or Xcode only, make sure you are on **CLI v1.0.0 or later** to get React Native support. ::: 1. After activation, the `bitrise-build-cache` binary is on PATH. Prefix any command that runs a build with `bitrise-build-cache react-native run`. :::note For more information about wrapping, see [Wrapping native build commands](/bitrise-build-cache/build-cache-for-react-native/wrapping-native-build-commands). ::: **Example configuration: GitHub Actions** ```yaml jobs: build-rn: runs-on: macos-latest env: BITRISE_BUILD_CACHE_AUTH_TOKEN: ${{ secrets.BITRISE_BUILD_CACHE_AUTH_TOKEN }} BITRISE_BUILD_CACHE_WORKSPACE_ID: ${{ secrets.BITRISE_BUILD_CACHE_WORKSPACE_ID }} steps: - uses: actions/checkout@v4 - name: Activate Bitrise Build Cache for React Native run: | curl --retry 5 -sSfL \ 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' \ | sh -s -- -b /tmp/bin -d /tmp/bin/bitrise-build-cache activate react-native --cache-push - name: Install JS dependencies run: yarn install - name: Build iOS run: /tmp/bin/bitrise-build-cache react-native run npx react-native run-ios --configuration=Release - name: Build Android run: /tmp/bin/bitrise-build-cache react-native run npx react-native run-android --mode=release ``` ### Validating the setup 1. Run a build with the new configuration. The activation step should complete successfully. 1. Open the **Build details** page on Bitrise and check the **Build Cache** tab. You should see the wrapped commands listed with their cache stats. 1. The first build will report 0% cache hit rate: the cache is empty at this point. This is expected. 1. Run 1–3 additional builds to warm the cache. Subsequent builds should report a hit rate above 0%. 1. You can monitor cache performance per build and across builds on the [Build Cache list page](https://app.bitrise.io/build-cache/). --- ## Configuring the Build Cache for React Native in the Bitrise CI environment You can add the activation either through the Workflow Editor or directly in `bitrise.yml`. **Workflow Editor** 1. Make sure you have: - An active Bitrise Build Cache trial or subscription. You can check your subscription status on the [Bitrise Build Cache page](https://app.bitrise.io/build-cache/). - A React Native project that already builds successfully without Build Cache (so you have a clear baseline). - For iOS projects: **Xcode 26 or later**. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Select the Workflow you need. 1. Add the **Build Cache for React Native** step *before* any Step that triggers a native build. For example, before **Script** Steps that run `yarn`, `npm`, `npx`, `expo`, `fastlane`, or direct Gradle/Xcode commands. You can place it right after `git-clone`. 1. Leave the inputs at their defaults unless you have a specific reason to change them. The step has two main inputs: - **Enable Xcode cache**: Activates Bitrise Build Cache for iOS builds. A background proxy is started automatically. - **Enable Gradle cache**: Activates Bitrise Build Cache for Android builds. C++ native modules are also cached via `ccache`, with a background storage helper started automatically. 1. In **Script** Steps that invoke a native build, prefix the command with `bitrise-build-cache react-native run`. :::note If you use the official Bitrise Steps **Gradle Runner**, **Android Build**, or **Xcode Archive** to drive your React Native build, make sure you are on the latest version: the wrapping is handled automatically and you do not need to change inputs. For more information about wrapping, see [Wrapping native build commands](/bitrise-build-cache/build-cache-for-react-native/wrapping-native-build-commands). ::: 1. Save the Workflow and run a build. **Configuration YAML** 1. Make sure you have: - An active Bitrise Build Cache trial or subscription. You can check your subscription status on the [Bitrise Build Cache page](https://app.bitrise.io/build-cache/). - A React Native project that already builds successfully without Build Cache (so you have a clear baseline). - For iOS projects: **Xcode 26 or later**. 1. Add the `activate-build-cache-for-react-native` Step before any step that runs a build: ```yaml workflows: build-react-native: steps: - activate-ssh-key@4: {} - git-clone@8: {} - activate-build-cache-for-react-native@0: {} # JS dependencies — no wrapping needed. - script@1: title: Install dependencies inputs: - content: yarn install ``` 1. Wrap commands that trigger native builds with the CLI: :::note If you use the official Bitrise Steps **Gradle Runner**, **Android Build**, or **Xcode Archive** to drive your React Native build, make sure you are on the latest version: the wrapping is handled automatically and you do not need to change inputs. For more information about wrapping, see [Wrapping native build commands](/bitrise-build-cache/build-cache-for-react-native/wrapping-native-build-commands). ::: ```yaml workflows: build-react-native: steps: - activate-ssh-key@4: {} - git-clone@8: {} - activate-build-cache-for-react-native@0: {} # JS dependencies — no wrapping needed. - script@1: title: Install dependencies inputs: - content: yarn install - script@1: title: Build Android inputs: - content: bitrise-build-cache react-native run npx react-native run-android --mode=release - script@1: title: Build iOS inputs: - content: bitrise-build-cache react-native run npx react-native run-ios --configuration=Release - deploy-to-bitrise-io@2: {} ``` ### Validating the setup 1. Run a build with the new configuration. The activation step should complete successfully. 1. Open the **Build details** page on Bitrise and check the **Build Cache** tab. You should see the wrapped commands listed with their cache stats. 1. The first build will report 0% cache hit rate: the cache is empty at this point. This is expected. 1. Run 1–3 additional builds to warm the cache. Subsequent builds should report a hit rate above 0%. 1. You can monitor cache performance per build and across builds on the [Build Cache list page](https://app.bitrise.io/build-cache/). --- ## React Native Cache FAQ ### What exactly gets cached? - **Android:** Gradle task outputs (compilation, resource processing, dex generation) via the remote build cache. - **iOS:** Xcode compilation outputs (object files, module artifacts) via the LLVM CAS-backed cache. - **C++ native modules:** Compiled native bridge code and third-party native modules via `ccache`, backed by Bitrise's remote storage. ### What does NOT get cached? - **Metro JS bundling** — the JavaScript bundling step is not affected by this setup. - **`node_modules`** — package installation (`yarn` / `npm` / `pnpm`) is not cached by this tool. Use Bitrise's standard caching steps if you want to cache `node_modules`. ### Do I need to wrap every command? Only wrap commands that trigger *native builds*. You do not need to wrap: - `yarn install` / `npm install` / `pnpm install` - `yarn test` / `npm test` (JS-only tests) - Any command that does not invoke Gradle or Xcode Wrap commands like `npx react-native run-android`, `npx react-native run-ios`, `./gradlew assembleRelease`, `fastlane build`, or any script that ultimately calls `xcodebuild` or Gradle. ### Will this speed up my tests? Build Cache reduces *compilation* time. If your test workflow includes a build step (for example `xcode-build-for-test`), that step will be faster. The actual test execution time is not affected. ### Can I use this alongside the standalone Gradle or Xcode Build Cache steps? No — the **Build Cache for React Native** step configures caching for Gradle, Xcode, and C++ in one go. If you are already using a standalone **Build Cache for Gradle** or **Build Cache for Xcode** step, replace it with this step to avoid conflicting configurations. ### Can I selectively disable one of the backends? Yes. The activation step exposes inputs for Gradle and Xcode (both default to `true`). On the CLI, pass `--gradle=false`, `--xcode=false`, or `--cpp=false` to `bitrise-build-cache activate react-native`. Disabling Gradle also disables the C++/`ccache` flow on the Android side; the C++ backend follows the `--cpp` flag. ### Can I still fine-tune ccache configuration? Yes — the React Native activation only sets the following environment variables to point `ccache` at Bitrise's remote storage: - CCACHE_BASEDIR - CCACHE_NOHASHDIR - CCACHE_REMOTE_ONLY - CCACHE_REMOTE_STORAGE - CMAKE_CXX_COMPILER_LAUNCHER - CMAKE_C_COMPILER_LAUNCHER Anything else — including your `ccache.conf` — is yours to customize. Note that the env vars above override the same parameters coming from config files. ### How do I troubleshoot issues? - Enable verbose logging by setting the **Verbose logging** input on the Activate step (or pass `--debug` to the CLI). This logs additional details about cache configuration and the background storage helper. - Confirm that the activation step ran in the *same environment* as the build commands (same container/shell on non-Bitrise CI). - Confirm that native build commands are wrapped with `bitrise-build-cache react-native run`. - Check the **Build Cache** tab on the build details page to see whether the wrapped invocations were registered. - For iOS, confirm the stack uses **Xcode 26 or later**. ### I'm using an official Bitrise step to build my app. Do I still need the wrapper? No. If you are using the latest versions of **Gradle Runner**, **Android Build**, or **Xcode Archive**, the wrapping is handled by the step itself — just make sure those steps are up to date. If you use a different official Bitrise step that runs a build, [let us know](https://github.com/bitrise-io/bitrise-build-cache-cli/issues) so we can add support. --- ## Wrapping native build commands After activation, prefix every command that triggers a *native* build with `bitrise-build-cache react-native run`. The wrapper: - Ensures the `ccache` storage helper is running for the duration of the build. - Tracks cache hit rates and reports build analytics back to Bitrise. - Forwards arguments, `stdin`, `stdout`, `stderr`, and the exit code of your command unchanged. **Before:** ```bash npx react-native run-android ``` **After:** ``` bitrise-build-cache react-native run npx react-native run-android ``` This works with any package manager or build tool: ``` # yarn bitrise-build-cache react-native run yarn build:android # npm bitrise-build-cache react-native run npm run build:ios # expo bitrise-build-cache react-native run expo build:ios # pnpm bitrise-build-cache react-native run pnpm run build:android # fastlane bitrise-build-cache react-native run fastlane beta # Direct Gradle invocation bitrise-build-cache react-native run ./gradlew assembleRelease ``` You only need to wrap commands that ultimately invoke Gradle or Xcode. Plain JS commands (`yarn install`, `yarn test`, etc.) do not need to be wrapped. --- ## Configuring the Build Cache for Xcode in local builds You can use the Bitrise Build Cache for local Xcode builds too. Your local builds then read from the same compilation cache as your CI builds, so code your CI already compiled doesn't have to be compiled again on your machine. The Bitrise Build Cache CLI sets this up by installing an `xcodebuild` wrapper on your `PATH`. Your project files stay untouched. ### Before you start Ensure you have: - A working Xcode project on your machine, built with Xcode 26 or later. Earlier versions don't expose the compilation cache flags the CLI needs, and the wrapper does nothing there. - A Bitrise workspace with the Build Cache enabled. Check it on the [Build Cache page](https://app.bitrise.io/build-cache/). - Network access to the Bitrise hosts the Build Cache uses, if your machine is behind a VPN, a firewall, or an outbound proxy. See [Network endpoints for firewalls and VPNs](/bitrise-build-cache/getting-started-with-the-build-cache/network-endpoints-for-firewalls-and-vpns). :::important[Terminal builds only] The cache works for `xcodebuild` runs that resolve through your `PATH`: Terminal, iTerm, the integrated terminal of your editor, `fastlane`, and any script that shells out to `xcodebuild`. Xcode.app invokes `xcodebuild` through a hard-coded absolute path, so pressing ⌘B or ⌘R in the IDE bypasses the wrapper. Those builds get no cache reads, no cache writes, and no analytics. If you build from the IDE and see no cache activity, that's why — run the build from a terminal instead. ::: ### Installing the CLI **Homebrew** ```bash brew install bitrise-io/bitrise-build-cache/bitrise-build-cache ``` **curl** ```bash curl --retry 5 -sSfL \ 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' \ | sh -s -- -b ~/.local/bin ``` Make sure the install location is on your `PATH`, then check the install: ```bash bitrise-build-cache --version ``` ### Activating the cache Run the interactive wizard: ```bash bitrise-build-cache activate --interactive ``` The wizard asks for the following: 1. **Sign in to Bitrise**: opens your browser for authentication on the first run. The CLI stores the credentials in the macOS keychain and refreshes them automatically, so later runs skip this step. 1. **Select a workspace**: pick the workspace whose Build Cache you want to use. The CLI selects it automatically if you only have access to one. 1. **Which build tools should I set up**: ensure **Xcode** is selected. Use space to toggle an option and enter to confirm. 1. **Display name for this machine's local invocations**: the name your local builds show up under in the Build Cache dashboard, for example `local-`. 1. **Enable cache push**: select **No, pull only**. See [Local builds only read from the cache](#local-builds-only-read-from-the-cache). 1. **Keep the cache proxies running in the background**: select **Yes, install + start**. This registers the cache proxy with the OS so it survives shell restarts. :::important[Open a new terminal afterwards] The activation prepends `~/.bitrise-xcelerate/bin` to your `PATH` by writing a line to your shell rc file. Your current shell hasn't picked that up yet, so builds started in it still run without the wrapper — and `doctor` won't warn you about it. ::: Open a new terminal, or run `source ~/.zshrc`, then confirm that the wrapper is in place: ```bash which xcodebuild # → /Users//.bitrise-xcelerate/bin/xcodebuild ``` ### Verifying the setup Run the CLI's health check: ```bash bitrise-build-cache doctor ``` It reports the status of every part of the local setup — credentials, backend connectivity, the cache proxy, and log directories — and ends with an overall verdict: ```bash Bitrise Build Cache - doctor CLI version: 3.x.y Healthy: ✓ auth OAuth login (keychain) (workspace ), token valid until ✓ keychain-smoke Set/Get/Delete round-trip OK ✓ auth-backend latency , source=keychain, workspace= ✓ xcelerate-proxy running (/var/folders/…/T/xcelerate-proxy.sock) ✓ xcelerate-enrichment no enrichment attempts yet ✓ log-dirs all log dirs present + writable Overall: ok ``` `xcelerate-enrichment` changes from `no enrichment attempts yet` to `healthy` after your first build. To let the CLI repair the issues it can fix on its own, run `bitrise-build-cache doctor --fix --interactive`. ### Running a build Run your usual `xcodebuild` command from a terminal: ```bash cd path/to/your/xcode/project xcodebuild \ -workspace .xcworkspace \ -scheme \ -configuration Debug \ -sdk iphonesimulator \ -destination 'generic/platform=iOS Simulator' \ CODE_SIGNING_ALLOWED=NO clean build ``` The wrapper redirects the build's derived data to `~/.bitrise/cache/xcode-dd/` and its module cache to `~/.bitrise/cache/xcode-ptd/`, so the cache keys are the same across machines. Your existing `~/Library/Developer/Xcode/DerivedData/` folder stays as it is, and Xcode.app keeps using it. A build that hits a warm cache ends like this: ```bash CompilationCacheMetrics note: 82 hits / 82 cacheable tasks (100%) ** BUILD SUCCEEDED ** [Bitrise Analytics] Invocation succeeded ✅ after 15.808s [Bitrise Analytics] Proxy blob stats: hits: 168 (60 MB) / total: 168 (100.00%). Uploaded blobs: 0 (0 B) [Bitrise Analytics] Proxy KV stats: hits: 82 / total: 82 (100.00%). Uploaded KV blobs: 0 B [Bitrise Analytics] Xcode task stats: hits: 82 / total: 82 (100.00%) [Bitrise Analytics] Invocation saved. Visit 👉 https://app.bitrise.io/build-cache/invocations/xcode/ ``` ### Checking that it worked | Signal | Where to find it | What success looks like | |---|---|---| | `CompilationCacheMetrics note: N / M cacheable tasks (P%)` | Xcode build output | The line is present, with non-zero hits | | `[Bitrise Analytics] Xcode task stats:` | Last lines of the build output | The same numbers as `CompilationCacheMetrics` | | `[Bitrise Analytics] Proxy blob stats:` | Last lines of the build output | `hits: N / total: M`, showing blobs served from the remote cache | | Invocation link | Printed at the end of the build | Opens the invocation with the same hit ratios | | Dashboard | [Build Cache page](https://app.bitrise.io/build-cache/) | A row appears under your display name | | Per-invocation log | `~/.local/state/xcelerate/logs/xcelerate-.log` | The full wrapper log for the build | :::note[Explicit module build warnings] A few `swift compiler caching requires explicit module build` warnings can appear even though the wrapper sets `SWIFT_ENABLE_EXPLICIT_MODULES=YES`. Xcode emits them before the wrapper's build settings apply, and they are safe to ignore. The cache hit numbers confirm that caching is working. ::: Some projects can't build under explicit modules at all, and fail with `unable to resolve module dependency`. Activate with `--no-swift-cache` there: it caches clang and Objective-C compilation only, leaving Swift uncached. The wizard doesn't ask about this, so use the non-interactive activate command: ```bash bitrise-build-cache activate xcode --cache --no-swift-cache ``` ### Local builds only read from the cache The setup in this guide activates the Build Cache in pull-only mode: your local builds read from the shared cache but never write to it. This is the recommended mode for local development. Build tools recommend writing cache entries only from an environment where the source files don't change during the build. On a local machine you might keep editing files while a build is running, which can produce cache entries that don't match their inputs — and those entries would then be served to your teammates and to CI. Pull-only removes that risk: a broken local build can't affect anyone else. The usual pattern is to have CI populate the cache, because CI builds from a clean, fixed checkout, and to let local machines pull from it. ### Pushing to the cache from local builds Pull-only assumes that something else fills the cache, which is normally CI. If nothing does, your local builds have nothing to read: the ratio stays at `0 / N (0%)` for your scheme, configuration, and SDK combination. If your team doesn't run the Build Cache on CI, turn pushing on for your local builds and leave it on. Your machine then populates the cache as you work, for you and for your teammates. You have two options to turn on pushing: - Re-run `bitrise-build-cache activate --interactive` and answer **Yes, push too** at the cache push prompt. - Run the non-interactive activate command: ```bash bitrise-build-cache activate xcode --cache --cache-push ``` If a build doesn't behave as expected, re-run the activation with debug logging: ```bash bitrise-build-cache activate xcode --cache --cache-push --debug ``` :::note If the cache proxy was already running from an earlier activation, the new push setting won't take effect until you restart it — the proxy locks in push-enablement at start-up and doesn't reload it when you re-activate. Restart it: ```bash bitrise-build-cache xcelerate stop-proxy bitrise-build-cache activate xcode --cache --cache-push ``` ::: :::note An entry written from a build whose source files changed while it was running can be wrong, and your teammates read the same entry. Avoid editing files during a build you push from. Setting up the Build Cache on CI is the more robust option, because CI builds from a clean, fixed checkout. Once it runs there, switch your machine back to pull-only. ::: ### Troubleshooting Start with the CLI's health check. It inspects every part of the local setup and repairs the issues it can fix on its own: ```bash bitrise-build-cache doctor --fix --interactive ``` If you're still experiencing issues, check the following table: | Issue | Fix | |---|---| | The wizard reports that it needs a terminal | Run `TERM=dumb bitrise-build-cache activate --interactive` for line-based mode. | | `which xcodebuild` still points to `/usr/bin/xcodebuild` | Open a new terminal, or run `source ~/.zshrc`. | | The build shows no cache activity at all | Check that you ran it from a terminal and not from Xcode.app. | | `doctor` reports a problem it can't fix | Re-run it with `--debug` for the full context. | | You want to start over | It's safe to re-run the wizard. It re-reads the current state and applies the same activation again. | | The build can't reach the cache, or the cache calls time out | Your VPN, firewall, or proxy may block the Bitrise hosts. Check them against [Network endpoints for firewalls and VPNs](/bitrise-build-cache/getting-started-with-the-build-cache/network-endpoints-for-firewalls-and-vpns). | --- ## Configuring the Build Cache for Xcode in non-Bitrise CI environments The Bitrise Build Cache does not require using the Bitrise CI. You can use other CI/CD services and still take advantage of the cache to improve your Xcode build times. To do so, you need to configure your CI environment to download the Bitrise Build Cache CLI during the build and then run the CLI to enable the Bitrise Build Cache. 1. Generate a Personal Access Token on Bitrise: [Creating a personal access token](/bitrise-platform/accounts/personal-access-tokens#creating-a-personal-access-token). Copy the value of the token, as you will need it during the process. 1. [Find your Workspace ID](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs): open the **Workspace settings** page and select **General settings** on the left navigation menu. You can find and copy the slug from there. 1. Set the following Environment Variables in your CI configuration: - BITRISE_BUILD_CACHE_AUTH_TOKEN: The value should be your Personal Access Token. - BITRISE_BUILD_CACHE_WORKSPACE_ID: The value should be the Bitrise Workspace slug. 1. Add the following script to your CI configuration before the step you want to speed up: :::important[Environment] Make sure to run the script in the same environment as the Xcode command(s) you want to speed up. If you already have a workflow set up for other build tools (for example, Gradle), you need to make sure to install the latest CLI version that supports Xcode, i.e. at least v1.0.0. The Xcode Compilation Cache requires Xcode 26 or later version. ::: ```bash #!/usr/bin/env bash set -euxo pipefail # download Bitrise Build Cache CLI curl --retry 5 -sSfL 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' | sh -s -- -b /tmp/bin -d # run the CLI to enable Bitrise build cache for Xcode /tmp/bin/bitrise-build-cache activate xcode --cache --cache-push ``` --- ## Configuring the Build Cache for Xcode in the Bitrise CI environment You need the **Bitrise [Build Cache for Xcode](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-xcode)** Step to activate the Build Cache for your Xcode project. After the Step executes, Xcode tasks will automatically read from the build cache and push new entries, too. **Workflow Editor** 1. Make sure your build runs on a stack with Xcode 26 or higher version installed: [Setting the stack for your builds](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds). 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add the [**Build Cache for Xcode**](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-xcode) Step to your Workflow. The Step should be before any Step that executes Xcode tasks. For example, **fastlane** or [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive). 1. Optionally, you can disable pushing new cache entries: set the **Push new cache entries** input to **false**. In read-only mode, your build only reads from the cache but doesn't update it. 1. Click **Save changes**. **Configuration YAML** 1. Make sure your build runs on a stack with Xcode 26 or higher version installed: [Setting the stack for your builds](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds). 1. Add the `activate-build-cache-for-xcode` Step to your Workflow. The Step should be before any Step that executes Xcode tasks. For example, `fastlane` or `xcode-archive`. ```yaml your-workflow: meta: bitrise.io: stack: osx-xcode-26.0.x-edge steps: - git-clone: {} - activate-build-cache-for-xcode: {} ``` --- ## Xcode Compilation Cache FAQ ### What are the requirements to use Xcode Compilation Cache? You need Xcode 26 and **Explicitly Built Modules enabled** (default in Xcode 26 for Swift targets) ### Will this work with Swift Package Manager dependencies? As of September 2025, SPM dependencies are not cacheable in Xcode 26 Beta. Apple is working on it and it should be available in the future. ### What build tasks are not cacheable? `CompileStoryboard`, `CompileXIB`, `CompileAssetCatalogVariant`, `PhaseScriptExecution`, `DataModelCompile`, `CopyPNGFile`, `GenerateDSYMFile`, and `Ld` tasks are currently not cacheable. ### Will it speed up my Xcode Tests? Xcode Compilation Cache helps reducing compilation times. This means build and archive actions benefit the most. In case of Xcode Test, the compilation of the tests will be faster, but running the tests won’t be quicker. For testing the performance benefits of Xcode compilation cache, we recommend to test with a Workflow which runs [Xcode Archive](https://bitrise.io/integrations/steps/xcode-archive) or [Xcode Build For Testing](https://bitrise.io/integrations/steps/xcode-build-for-test) (or any other build command). ### How can I disable Xcode compilation cache temporarily? The simplest method is to specify a custom Xcode flag: `--no-bitrise-build-cache`. This is recognized by the Bitrise wrapper and disables caching without disabling analytics. This means the invocation will show up on the UI but it will not use caching and therefore won't count towards the caching quota. There is another option: you can override the PATH to remove the wrapping we set up by issuing: ```bash export PATH="${PATH#"$HOME/.bitrise-xcelerate/bin:"}" ``` Note that this will be reverted in the next terminal session as the Bitrise Build Cache CLI persists, the PATH overrides in `~/.zshrc` and `~/.bashrc`. To make this persist among Bitrise Steps, set the PATH again with envman: ```bash envman add --key PATH --value "$PATH" ``` ### How to pass compilation cache build flags manually? To enable compilation caching manually per-project, you can disable passing the necessary flags in the [Build Cache for Xcode](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-xcode) Step (on Bitrise CI) with the **Skip passing cache flags to xcodebuild** Step input. If you are using the Bitrise Build Cache CLI locally, you can pass the `--cache-skip-flag` to your `activate xcode` command. In this case, you either need to manually set some flags per-build, or in your project's build settings. Some might already have a named version in Xcode IDE, for example, "Enable Compilation Caching", or "Explicitly Built Modules". These are the flags we pass by default: ```yaml - "COMPILATION_CACHE_ENABLE_PLUGIN": "YES" - "COMPILATION_CACHE_ENABLE_INTEGRATED_QUERIES": "YES" - "COMPILATION_CACHE_ENABLE_DETACHED_KEY_QUERIES": "YES" - "SWIFT_ENABLE_COMPILE_CACHE": "YES" - "SWIFT_ENABLE_EXPLICIT_MODULES": "YES" - "SWIFT_USE_INTEGRATED_DRIVER": "YES" - "CLANG_ENABLE_COMPILE_CACHE": "YES" - "CLANG_ENABLE_MODULES": "YES" ``` Learn more on how we pass these flags on Bitrise in this [blog post](https://bitrise.io/blog/post/lifting-the-hood-on-build-cache-for-xcode). ### What about tools that depend on Xcode Index Data Store? Xcode does not generate an `Index.noindex/DataStore` in DerivedData when remote compilation cache is enabled. This can cause an error if your tasks depend on the Index Data Store. Here's an example error, generated by [Periphery](https://github.com/peripheryapp/periphery) when the Index data store isn’t found: `error: Internal Error: index store path does not exist: /Users/vagrant/Library/Developer/Xcode/DerivedData/.../Index.noindex/DataStore` Currently, there’s no solution for this. A workaround can be to use Bitrise [Build Cache for Xcode](https://github.com/bitrise-steplib/bitrise-step-activate-build-cache-for-xcode) with all the steps and workflows which don’t depend on the Index data store, and run the steps which do depend on the Index data store in a separate workflow where you don’t configure Bitrise Build Cache for Xcode. --- ## At-rest encryption for the Build Cache [Bitrise Build Cache](https://bitrise.io/platform/devops/build-caching) protects customer data with at-rest encryption using envelope encryption and AES-256-GCM. ### At-rest encryption overview - A unique Data Encryption Key (DEK) is generated for each customer. - The DEK is encrypted using a Key Encryption Key (KEK), which is generated and managed by a Key Management System (KMS). For example, Google KMS. - We rotate the KEK every 90 days for enhanced security. - The encrypted DEKs are stored securely in our database, but the DEK never persists in its decrypted form—it is only used in memory when encrypting or decrypting data. - The DEK is used to encrypt customer data, ensuring that sensitive information is securely stored at rest. KEK and DEKs are never stored together, ensuring strong isolation. The raw KEK is never exposed: it is only used within KMS to encrypt and decrypt DEKs securely. This approach ensures strong encryption, safe key handling, and a high level of data protection for our customers. ### Security benefits - Strong encryption: AES-256-GCM is a widely trusted encryption standard that provides robust protection for sensitive data. - Customer isolation: Each customer has a unique DEK, meaning that if one customer's key were to be compromised, no other customers' data would be affected. Accessing encrypted data alone does not provide access to decrypted data. - Regulatory compliance: Our at-rest encryption aligns with best practices recommended by security and privacy regulations, including: - **GDPR (General Data Protection Regulation)**: Encourages encryption as a data protection measure. - **CCPA (California Consumer Privacy Act)**: Encrypted data may be exempt from certain breach liability requirements. - **SOC 2**: Supports encryption as a key security control for compliance. - **ISO/IEC 27001**: Recommends encryption for securing stored data. - **NIST (National Institute of Standards and Technology)**: Provides encryption standards (for example, AES-256) to ensure strong data protection and compliance with industry security frameworks. ### Customer-managed Encryption Keys For customers seeking greater control over their encryption, we offer the option to use Customer-Managed Encryption Keys (CMEKs). With CMEKs, customers can store their Key Encryption Key (KEK) in their own Google Cloud KMS or Amazon KMS, allowing them to: - Maintain full control: Manage their own KEKs, including creation, rotation, and revocation. - Enhance security compliance: Ensure that only they have access to their encryption keys, aligning with strict internal security policies. If you're interested in using CMEKs, [contact us](https://bitrise.io/contact) to discuss your requirements. --- ## Clearing the Build Cache You can clear the entire contents of your Bitrise Build Cache any time. This clears everything, including the Gradle configuration cache. There is no way to delete specific parts of the cache. After clearing the cache, your first build will take longer because outputs will need to be saved again. :::important[Owners only] Only workspace owners can clear the cache. ::: To clear the cache: 1. Open the Bitrise Build Cache. 1. Click **Clear cache**. 1. In the dialog, click **Clear cache**. ![SCR-20260401-obcc.png](/img/_paligo/uuid-9547e14a-19b8-4d74-9d5a-6558fdc1f8ea.png) --- ## Getting started with the Build Cache The [Bitrise Build Cache](https://bitrise.io/platform/devops/build-caching) is a fully managed caching solution that reduces CI build durations for applications built with Gradle, Bazel, Xcode, and React Native. It specifically caches build and test outputs to minimize how much work is done in subsequent builds, making it more efficient in environments with frequent updates. Compatible with any CI tool, it accelerates the build cycle without requiring you to manage a caching infrastructure. :::tip[Try it for free] We offer a 30-day free trial at no cost; you don't even need to provide payment information. The trial starts automatically when you set up the Bitrise Build Cache. [Click here to get started with the Bitrise Build Cache](https://app.bitrise.io/build-cache). If you don't have a Bitrise account, you will be prompted to create one first before proceeding to set up the Build Cache. ::: Bitrise supports remote build caching for the Gradle, Bazel, Xcode, and React Native build systems. Follow the guide that matches your build system and the environment you want to set the Build Cache up in. ### Setting up on Bitrise CI - [Build Cache for Gradle](/bitrise-build-cache/build-cache-for-gradle/configuring-the-build-cache-for-gradle-in-the-bitrise-ci-environment). - [Build Cache for Bazel](/bitrise-build-cache/build-cache-for-bazel/configuring-the-build-cache-for-bazel-in-the-bitrise-ci-environment). - [Build Cache for Xcode](/bitrise-build-cache/build-cache-for-xcode/configuring-the-build-cache-for-xcode-in-the-bitrise-ci-environment). - [Build Cache for React Native](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-the-bitrise-ci-environment). ### Setting up on other CIs - [Build Cache for Gradle](/bitrise-build-cache/build-cache-for-gradle/configuring-the-build-cache-for-gradle-in-other-ci-environments). - [Build Cache for Bazel](/bitrise-build-cache/build-cache-for-bazel/configuring-the-build-cache-for-bazel-in-other-ci-environments). - [Build Cache for Xcode](/bitrise-build-cache/build-cache-for-xcode/configuring-the-build-cache-for-xcode-in-non-bitrise-ci-environments). - [Build Cache for React Native](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-non-bitrise-ci-environments). ### Setting up in a local dev environment - [Build Cache for Gradle](/bitrise-build-cache/build-cache-for-gradle/configuring-the-build-cache-for-gradle-in-local-builds). - [Build Cache for Bazel](/bitrise-build-cache/build-cache-for-bazel/configuring-the-build-cache-for-bazel-in-local-builds). - [Build Cache for Xcode](/bitrise-build-cache/build-cache-for-xcode/configuring-the-build-cache-for-xcode-in-local-builds). - [Build Cache for React Native](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-local-builds). ### Adding a new connection to the Build Cache To start using the Bitrise Build Cache, you have to add a new connection. The process consists of: - Selecting a CI provider: you can use either Bitrise or another CI provider. - Selecting a build tool: currently, Bazel, Gradle, Xcode, and React Native are supported. - If you use Bitrise as your CI provider, selecting a Bitrise project. - If you use a different CI provider, adding [a personal access token](/bitrise-platform/accounts/personal-access-tokens#creating-a-personal-access-token) to allow the Bitrise Build Cache access to your CI. - Adding the cache activation scripts to your CI process. On Bitrise, we have dedicated [Steps](/bitrise-ci/workflows-and-pipelines/steps/steps-overview) for this. To add a new connection: 1. Log in to Bitrise and select the **Build Cache** from the left navigation menu. 1. On the top right corner, click **New connection**. ![cache-new-connection.png](/img/_paligo/uuid-bdbb02c7-b8e7-bf04-fb52-7cacd2231760.png) 1. Follow the instructions. --- ## Invocations Invocation is a key concept in remote caching. An invocation is a single command execution. This means running a specific command to achieve a particular goal. Invocations are only counted when the Bitrise Build Cache and/or analytics are enabled. Only cached invocations (invocations downloading data from the cache) are counted for billing purposes. Invocations not downloading data are not billed (free). ### Checking invocations You can check the details of every single invocation in your cache history. 1. Open the Build Cache. 1. Select the tab of your build tool, either Gradle, Xcode, or Bazel. 1. Select your filter. You can filter for: - Dates - Bitrise projects - CI providers - Invocation status - Bitrise Workflow 1. In the invocation list, click the downward arrow to the left of any given invocation to see the basic information about it: ![2025-09-16-xcode-tab-invocations.png](/img/_paligo/uuid-e1c9e6b8-a0cf-6513-8b88-7ad65a2df1fe.png) - Invocation ID. - The CI provider used. - The build URL. If you use the Bitrise CI, you will see the Workflow and the Step in which the command was executed. 1. Click the arrow on the right to get to the details page of the invocation. ### Invocation details The invocation details page shows: - The command name and the event data of its invocation (such as CI provider, build tool, duration, cache hit rate). - The critical path: the longest chain of dependent build tasks within an invocation. Executed cacheable tasks can be fixed to improve build cache performance. - Uploads and downloads during the invocation. Large items or a high number of items increase invocation size. This can impact cache efficiency. The details page allows you to compare the metrics of this invocation to the averages from the last 30 days for the same command: ![mygreat-project.png](/img/_paligo/uuid-3452d29c-7dd3-8a00-dbc3-c69620063c48.png) If you use the Bitrise CI, the command card can take you to the project's build list: ![mygreat-project-name.png](/img/_paligo/uuid-79a85107-1f7e-60a6-6934-cbec5be94c28.png) For even more invocation metrics, check out [Insights](/insights/available-metrics-in-insights/command-metrics). ### Comparing invocation differences You can compare two command invocations side-by-side to quickly identify what changed between them. This helps debugging and failure root cause analysis. For example, in Bitrise Insights you see an increase in command failure. You check which command started to fail. On the build cache page, you can check out the differences between two invocations of the command. To check the differences: 1. Open the Build Cache. 1. Select the tab of your build tool, either Gradle, Xcode, or Bazel. 1. Set any filters you might need. 1. Click **Compare**. ![inv-compare.png](/img/_paligo/uuid-4e5bd057-700c-f047-f6ae-498ebd98f1a2.png) 1. Check the box to the right of the invocations you want to compare. 1. Click **Compare** to see the difference. ![invocation-diffing.png](/img/_paligo/uuid-d5bbba7f-b660-6c42-3745-ce80f0c72abf.png) In this example, you can immediately see that the duration of the more recent invocation has doubled compared to the previous one. You can dive in to the detailed comparison to see why. ![demo-wait-seconds-reason.png](/img/_paligo/uuid-ca915855-de3e-21af-a1d7-539b1020af65.png) The `demo.wait.seconds` Gradle property changed from 28 to 56. :::tip[Invocation details] You can also access the compare function [from the **Invocation details** page](#invocation-details): you can find the button in the top right corner of the page. ::: --- ## Maven Central repository manager Hosted CI/CD platforms, including Bitrise, generate significant aggregate traffic to Maven Central across all customer builds. To protect our users from rate limiting (HTTP 429 errors) and to improve build performance, Bitrise deploys a repository manager (a proxy cache) in each of our datacenters. This repository manager stores Gradle artifacts so builds resolve dependencies from within our datacenter rather than over the public internet. This results in a fraction of the typical number of upstream requests to Maven Central and faster dependency resolution for your builds. :::note[Repository manager vs Build Cache vs Key-based caching] The repository manager stores third-party dependencies from Maven Central so they don't need to be re-downloaded from the internet on every build. Build Cache stores your project's own build outputs (compiled classes, task results) so Gradle doesn't need to re-execute work that hasn't changed. The [key-value cache](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching) stores whole files and directories you designate (like `~/.gradle/caches`) so they persist between builds on ephemeral CI runners. All three are complementary and can be used together. ::: ### How the repository manager works All Bitrise-hosted builds are opted in to the repository manager by default. Usually, no action is required on your part. The repository manager works via a Gradle `init` script embedded into the build runner. The `init` script adds the Bitrise repository manager to the top of your list of repositories in your Gradle configuration, so dependencies are resolved from the co-located repository manager first. If the repository manager doesn't have an artifact, it fetches it from Maven Central once and stores it for all subsequent builds across the platform. Because the repository manager is co-located with the CI runner in the same datacenter, downloads are faster than pulling from a remote CDN. :::note Early iterations of the system required adding a Step to your Workflow. Most users that added a Workflow Step (such as [Activate Gradle Mirrors](https://github.com/bitrise-steplib/bitrise-step-activate-gradle-mirrors)) solely for repository manager functionality can safely remove it. ::: ### Special cases still requiring a Step The repository manager is enabled by default for all Bitrise-hosted builds, but there are some special cases where you still need to add the [Activate Gradle Mirrors](https://github.com/bitrise-steplib/bitrise-step-activate-gradle-mirrors) Step to your Workflow: #### Dependency verification If your project uses dependency verification, you must follow additional steps. Bitrise uses an `init` script to add the repository manager to the repositories list of Gradle projects. When enabled, dependency verification will reject this modification, because it requires every plugin and dependency to be listed in the project's verification metadata XML file (`$PROJECT_ROOT/gradle/verification-metadata.xml`). To pass dependency verification: 1. Add the [Activate Gradle Mirrors](https://github.com/bitrise-steplib/bitrise-step-activate-gradle-mirrors) Step to your Workflow. 2. Make sure that the Step version is locked to the latest patch version (in the example it's `0.1.2`). Currently, this is done in the `bitrise.yml` configuration file: :::note You will need to update your `verification-metadata.xml` each time you update the Step's version. ::: ```yaml activate-gradle-mirrors@0.1.2: inputs: - verbose: 'true' ``` 3. Find the CLI version used by the Step in the dependency matrix. Open the corresponding CLI release page (`https://github.com/bitrise-io/bitrise-build-cache-cli/releases/tag/`) and download the `verification-metadata-mirror.xml`. `verification-metadata-mirror.xml` contains SHA-256 checksums to match what the Bitrise repository manager serves, while the plain `verification-metadata.xml` records origin Maven Central checksums and will fail verification when the mirror is active. 4. Add the components content to your `$PROJECT_ROOT/gradle/verification-metadata.xml` file from the downloaded metadata. 5. Review and commit the changes. :::note We've collected the plugins' dependencies using a simple Gradle project and a specific platform runtime version. You might experience that in your setup Gradle pulls slightly different dependencies. In this case, you need to generate the dependency metadata yourself. ::: #### Updating the verification metadata These steps are required each time you update the activating Step, or if you find that the collected metadata still differs from the one Gradle expects in your environment. The Bitrise Build Cache CLI has a command that adds the plugin dependencies in a way that is meant for collecting the dependencies. With this, updating the build cache & analytics dependencies is done by the following steps: 1. Update the [Activate Gradle Mirrors](https://github.com/bitrise-steplib/bitrise-step-activate-gradle-mirrors) Step to the latest version — updating & locking the version to the latest exact (patch) Step version in the `bitrise.yml`. 2. If your Workflows include any build cache Steps (for example [Build Cache for Gradle](https://github.com/bitrise-steplib/bitrise-step-activate-gradle-remote-cache) Step or [Build Cache for React Native](https://github.com/bitrise-steplib/bitrise-step-activate-react-native-features) Step), pin to the Step version whose associated CLI version matches the [Activate Gradle Mirrors](https://github.com/bitrise-steplib/bitrise-step-activate-gradle-mirrors) Step's associated CLI version. This information is available for each Step in the associated dependency matrix. 3. On your development machine or on Bitrise in a separate workflow, install the associated version of the CLI for the activate gradle mirror as listed by its dependency matrix. ```bash # Replace CLIVERSION with the CLI version you want to install, for example: v2.4.6 curl --retry 5 -sSfL 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' | sh -s -- -b /tmp/bin -d "CLIVERSION" ``` 4. If you already have the Bitrise Build Cache enabled, make sure to back up `$HOME/.gradle/init.d/bitrise-build-cache.init.gradle.kts` as the next step will overwrite it. 5. If your production workflow has the Bitrise Maven Central mirror active (the default), activate the mirror locally so the regenerated metadata records mirror-served checksums instead of the origin ones: ```bash BITRISE_MAVENCENTRAL_PROXY_ENABLED=true /tmp/bin/bitrise-build-cache activate gradle-mirrors -d ``` 6. Run the Bitrise Build Cache CLI's `gradle-verification add-reference-deps` command on your development machine or your CI configuration. This will generate an init script with the latest plugins in dry-run mode. 7. In your project folder, run your usual Workflow to write the verification metadata: ```bash ./gradlew tasks --write-verification-metadata sha256 ``` 8. Review the metadata differences and commit and migrate your changes to your production Workflow to finish the update and use the updated Step in your Workflows. 9. If you have backed up `$HOME/.gradle/init.d/bitrise-build-cache.init.gradle.kts` on your local machine, you can now revert the changes. This way you can keep your dependencies locked while using the latest version of the Bitrise Build Cache. ### Opting out of the repository manager If you need direct access to Maven Central you can disable the repository manager, set `BITRISE_MAVENCENTRAL_PROXY_ENABLED` to `false` in your build configuration: - **Workflow level:** Add the environment variable in your Workflow Editor under **Env Vars** for the relevant Workflow. - **Project level:** Add it as an project level environment variable in the Workflow Editor to disable the proxy for all Workflows in that project. - **Secret:** Add it as a secret environment variable if you prefer to keep it out of your `bitrise.yml`. This environment variable takes precedence over all other settings, including the [Activate Gradle Mirrors](https://github.com/bitrise-steplib/bitrise-step-activate-gradle-mirrors) Step. No additional script Steps or code changes are needed. :::note If you opt out, your builds will resolve dependencies directly from Maven Central and may be subject to rate limiting (HTTP 429 errors) during peak traffic periods. ::: ### Using the proxy cache with Build Hub For developers using Bitrise Build Hub, add the following script to your job definition prior to dependency resolution: ``` curl --retry 5 -sSfL 'https://raw.githubusercontent.com/bitrise-io/bitrise-build-cache-cli/main/install/installer.sh' | sh -s -- -b /tmp/bin -d \ && BITRISE_MAVENCENTRAL_PROXY_ENABLED=true /tmp/bin/bitrise-build-cache activate gradle-mirrors -d \ || true ``` --- ## Network endpoints for firewalls and VPNs If your machine or your CI runner sits behind a corporate VPN, a firewall, or an outbound proxy, you must make sure the Bitrise Build Cache can access a handful of Bitrise hosts. The allowlist in this document covers: - The Bitrise Build Cache CLI. - The Gradle plugins it installs. - The Bazel configuration it writes. - Everything the Xcode and `ccache` proxies connect to. It applies to local development machines and to CI runners outside Bitrise alike. On Bitrise-hosted machines there's nothing to do: the traffic stays inside our datacenter. ### Allowlist Allowlist these hosts and ports: ```bash *.services.bitrise.io :443, :444 app.bitrise.io :443 oauth.bitrise.io :443 api.bitrise.io :443 ``` That's the complete set. If you need specific host names instead of using wildcards, the sections below break it down per build tool. :::note[Non-Bitrise hosts] Installing and updating the CLI itself goes to GitHub and Google Artifact Registry, and the Gradle init script resolves plugins from the Gradle Plugin Portal, Maven Central, and JitPack. Those aren't Bitrise hosts, so they aren't listed here, but your build needs them too. ::: ### Endpoints used on every build Allowlist the sections that match the build tools you actually run. React Native builds need the Gradle, Xcode, and `ccache` sections together. #### Gradle | Host | Port | Protocol | Purpose | |---|---|---|---| | `bitrise-accelerate.services.bitrise.io` | 443 | gRPC/TLS | Remote build cache, and the Test Distribution endpoint | | `gradle-analytics.services.bitrise.io` | 443 **and 444** | gRPC/TLS | Plugin analytics, including per-task and task input file data | | `gradle-sink.services.bitrise.io` | 443 | HTTPS | Analytics HTTP sink | #### Bazel | Host | Port | Protocol | Purpose | |---|---|---|---| | `bitrise-accelerate.services.bitrise.io` | 443 | gRPC/TLS | Remote cache and Remote Build Execution | | `flare-bes.services.bitrise.io` | 443 | gRPC/TLS | Build Event Service | #### Xcode | Host | Port | Protocol | Purpose | |---|---|---|---| | `bitrise-accelerate.services.bitrise.io` | 443 | gRPC/TLS | Compilation cache, through the `xcelerate` proxy | | `xcode-analytics.services.bitrise.io` | 443 | HTTPS | Invocation analytics, and DerivedData save and restore | | `multiplatform-analytics.services.bitrise.io` | 443 | HTTPS | Invocation analytics of the `xcodebuild` wrapper | #### ccache | Host | Port | Protocol | Purpose | |---|---|---|---| | `bitrise-accelerate.services.bitrise.io` | 443 | gRPC/TLS | Object cache, through the storage helper | | `multiplatform-analytics.services.bitrise.io` | 443 | HTTPS | Invocation analytics | #### React Native For a React Native build, you need: - Everything in the Gradle, Xcode, and `ccache` sections. - `multiplatform-analytics.services.bitrise.io` on port 443 for the React Native invocation record. ### Endpoints used during activation and login The CLI reaches these while you activate the cache or log in: | Host | Port | Purpose | |---|---|---| | `app.bitrise.io` | 443 | Benchmark phase status, invocation links, OAuth client metadata, and the `/oidc/token` endpoint | | `oauth.bitrise.io` | 443 | OAuth issuer for `bitrise-build-cache auth login` | | `api.bitrise.io` | 443 | The workspace picker of the login flow | If you authenticate with the `BITRISE_BUILD_CACHE_AUTH_TOKEN` Env Var instead of an interactive login, you can drop `oauth.bitrise.io` and `api.bitrise.io` from the allowlist. --- ## Bitrise Build Cache --- ## Insights [Bitrise Insights](/insights) offers detailed metrics on the performance of your Build Cache, including invocation count, command duration, or cache hit rate. You can explore Insights starting from any invocation: 1. Open the Build Cache. 1. Open the [Invocation details](/bitrise-build-cache/getting-started-with-the-build-cache/invocations) page. 1. Click **Explore Insights**. Alternatively, clicking any of the metrics on the card takes you to Insights. ![cache-insights-explore.png](/img/_paligo/uuid-299959e9-b519-88a2-05a2-ee89fa6963cd.png) Caching metrics are available as build cache metrics and command metrics. ### Build cache metrics Build cache metrics provide data-based visibility into the [Bitrise Build Cache](https://bitrise.io/platform/devops/build-caching) system. You can achieve more consistent and reliable CI/CD workflows by reducing the unpredictability that comes with inefficient caching. If your Bitrise Build Cache is correctly set up, you need no additional configuration to access data in Insights. The following Build Cache metrics are available: - **Invocation count**: This metric shows how frequently the cache is used in your builds and helps you understand the frequency and type of commands being executed. A high invocation count indicates strong cache adoption while a low count might mean caching isn't utilized to its full effect. - **Uploads/downloads**: This measures the amount of data transfer to and from the build cache per each command. High data transfer volumes can point to excessive uploads or downloads which might slow down your builds. If downloads aren't significantly lower than uploads, it might indicate inefficient caching. Insights shows the p50 (median) value and the p90 value per invocation for both uploads and downloads: that is, how much data a given invocation uploads and downloads. ![p90-uploads.png](/img/_paligo/uuid-cb1811cf-42dd-3707-9288-42d1291a9780.png) - **Cache hit rate**: This measures the percentage of data requests that can be served by the build cache. Insights shows the p10 hit rate (meaning only 10% of cases will have an equivalent or lower hit rate) and the median (p50) hit rate. The p10 value is particularly important because a low hit rate suggests suboptimal cache configuration or incorrectly defined cache keys. For Build Cache metrics - like any other metrics in Insights - you can: - [Create a dashboard](/insights/getting-started-with-insights#creating-a-new-dashboard). - [Set alerts](/insights/configuring-alerts-in-insights) for specific thresholds. #### Common use cases for build cache metrics If your metrics show sudden and significant variation, you can check each related invocation to find out when the issue started. Filter to the relevant item/time period and then select the **Related invocations** tab. This can be useful for both uploads/downloads or cache hit rate. For example, if there is a sudden spike in uploads compared to downloads, it might mean that data is being repeatedly generated and stored but rarely reused, reducing efficiency: ![trends.png](/img/_paligo/uuid-5d4f1f7c-0ca9-93fb-251c-4b63c26f1f4b.png) ![issues-list.png](/img/_paligo/uuid-7d6dc7a5-d2ad-0a24-e940-6ce654e08db4.png) For another example, here's a sudden change in cache hit rate for a given Workflow, suggesting a weak spot in the caching setup: ![cache-hit-rate-workflow.png](/img/_paligo/uuid-cf5db37b-0d3a-2292-c706-28a35c9c342e.png) You can look at the invocation count to identify when a project started (when the invocation count suddenly spikes) or stopped (when the invocation count suddenly drops) using the Build Cache: ![started-build-cache.png](/img/_paligo/uuid-d2661447-265a-5f94-41dc-40c36c7acad6.png) ![stopped-using-cache.png](/img/_paligo/uuid-8f7bf7cb-1d82-dacf-ecc0-b3e98438c118.png) This can help, for example, detecting and fixing configuration issues that break the cache setup. --- ## Build Hub for GitHub Actions overview Bitrise Build Hub is a high-performance build infrastructure for GitHub Actions, purpose-built for mobile app development. It provides fully managed, zero-maintenance runners that execute your GitHub Actions workflows on the industry's fastest Apple silicon and Linux machines. Find out how to set up Build Hub for GitHub Actions: [Configuring Build Hub for GitHub Actions](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions). ### Key capabilities - `M4 Pro` Apple silicon and `AMD EPYC Zen4/Zen5` Linux machines optimized for iOS and Android builds. - Latest Xcode versions within 24 hours of Apple release, including betas. - Mobile-optimized stacks with preinstalled tooling (`Xcode`, `Android SDK`, `Flutter`, `React Native`, and more). - Co-located caching for near-zero latency and no network egress costs. - US and EU data centers for data residency requirements. - Pre-warmed VM pools for instant build start with no queue times. Build Hub works with both GitHub Cloud and GitHub Enterprise Server repositories. Your existing GitHub Actions workflow files stay unchanged—you only update the runs-on label to route builds to Bitrise infrastructure. ### Requirements To run your GitHub Actions workflows on Bitrise Build Hub infrastructure, you need: - A Bitrise workspace. - A GitHub account. - A way to authenticate the Build Hub machines to GitHub Actions. You can either use a personal access token or the Bitrise - Build Hub app. We recommend using the app. - A machine pool on Bitrise: you can select the machine type, the amount of machines, and the system image that contains the software configuration required to launch your instance. ### Authentication Bitrise Build Hub requires either the Bitrise - Build Hub GitHub app or a [GitHub personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) to authenticate the runners and enable proper management of the GitHub Action workflows and runner configurations. We recommend using the GitHub app integration. #### GitHub app authentication The Bitrise - Build Hub app can be installed to a GitHub account or a GitHub organization. The app can be scoped to access either: - All repositories: All current and future repositories owned by the resource owner. Includes public repositories. - Select repositories: At least one repository must be selected. Build Hub won't be able to access other repositories owned by the same resource owner. The app has the following access rights: - Read access to actions, metadata, and organization events. - Read and write access to organization self hosted runners. You can install the app to the GitHub account or organization of your choice when [creating a machine pool](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-a-machine-pool). #### GitHub personal access token You can use two types of tokens: - [Classic tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) - [Fine-grained access tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token) The different token types require different access types, depending on your [target scope](/bitrise-build-hub/build-hub-for-github-actions/build-hub-for-github-actions-overview#target-scope). Check out the table below to see the exact permissions for the respective target scopes: | Target scope | Required permission for a classic token | Required permissions for a fine-grained access token | | --- | --- | --- | | GitHub Enterprise (GHE) Cloud: https://github.com/enterprises/<enterprise> GHE Server: https://<hostname>/enterprises/<enterprise> | `manage_runners:enterprise` | Not supported | | GitHub Cloud organization: https://github.com/<org> GHE organization: https://<hostname>/<org> | `org:admin` | `read/write` permission to **Self-hosted runners** | | GitHub Cloud repository: https://github.com/<owner>/<repo> GHE repository: https://<hostname>/<owner>/<repo> | `workflow` | Not supported | [Create a personal access token](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-github-personal-access-tokens-for-build-hub) before [creating a machine pool](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-a-machine-pool). ### Provisioning machines for GitHub Actions When [creating a machine pool](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-a-machine-pool), you must request a certain number of machines that will run your builds. The number of machines we keep running at a time depends on the [authentication method](/bitrise-build-hub/build-hub-for-github-actions/build-hub-for-github-actions-overview#authentication): - If you use our GitHub app: We create and start machines on-demand. When a GitHub Actions workflow starts, we provision a machine. If you start multiple GitHub Actions workflows at the same time, we start a machine for each, up to the maximum number of machines defined by the machine pool configuration. When the GitHub Actions build ends, the machines are shut down. - If you use a GitHub personal access token: We always keep running as many machines as you requested in the machine pool. If you need fewer machines at a given time, you need to manually reduce the number of machines in the machine pool configuration. ### Target scope When using a GitHub personal access token to authenticate the Build Hub, you need to set a target scope when [creating a machine pool](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-a-machine-pool). The target scope is the context in which the runner is allowed to operate, such as a specific repository or a GitHub organization. The accepted target scopes are: - GitHub Cloud organization: https://github.com/<org> - GitHub Cloud repository: https://github.com/<owner>/<repo> - GitHub Enterprise (GHE) Cloud: https://github.com/enterprises/<enterprise> - GHE Server: https://<hostname>/enterprises/<enterprise> - GHE organization: https://<hostname>/<org> - GHE repository: https://<hostname>/<owner>/<repo> ### Warmup script Use a warmup script to customize your build environment and improve speed and performance. You can add any script to your configuration when creating a machine pool. The script will run when the machine is set up. To prevent build start failures, make sure the script returns a non-zero exit code in case of an error. --- ## Configuring Build Hub for GitHub Actions To successfully use Build Hub for GitHub Actions, you need to: 1. Create a machine pool on Bitrise. The machine pool requires authentication information. You can either: - Install the Bitrise - Build Hub GitHub app while creating the machine pool. We recommend this authentication method. - [Create a GitHub personal access token](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-github-personal-access-tokens-for-build-hub). 1. Configure your GitHub Actions workflow to use Bitrise infrastructure for your builds. ### Creating GitHub personal access tokens for Build Hub :::note This step is optional. Create a personal access token only if you're not using the Bitrise Build Hub GitHub App. ::: You can use a GitHub personal access token to authenticate Build Hub to GitHub Actions. You can use either a classic access token or a fine-grained access token, depending on your needs. Read more on how authentication works: [Authentication for Build Hub](/bitrise-build-hub/build-hub-for-github-actions/build-hub-for-github-actions-overview#authentication). To create the token on GitHub: **Fine-grained** 1. [Go through the process described here](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-fine-grained-personal-access-token) until you get to selecting a resource owner. 1. Select a resource owner: it should be the organization. :::note[Authorization] The organization might require authorization for the token: for example, you might be prompted to log in via SSO. ::: 1. Under **Repository access**, select **All repositories**. 1. Under **Permissions**, select **Organizations**. 1. Click **Add permissions**. 1. Select **Self-hosted runners**. 1. Set the access to **Read and write**. ![github-fine-grained-token-permissions.png](/img/_paligo/uuid-9def1cb2-5111-b6a3-58af-ade8becde4e4.png) 1. Click **Generate token**. 1. Copy your personal access token: you won't be able to see it again but you need it when [creating a machine pool](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-a-machine-pool). **Classic** 1. [Go through the process described here](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic) until you get to selecting the scopes. 1. Select the right scope: it depends on the target scope you need for your machine pool. - GitHub Cloud organization (https://github.com/<org>) and GHE organization (https://<hostname>/<org>): **org:admin** - GitHub Enterprise (GHE) Cloud (https://github.com/enterprises/<enterprise>) and GHE Server (https://<hostname>/enterprises/<enterprise>): **manage_runners:enterprise**. - GitHub Cloud repository (https://github.com/<owner>/<repo>) and GHE repository (https://<hostname>/<owner>/<repo>): **workflow**. 1. Click **Generate token**. 1. Copy your personal access token: you won't be able to see it again but you need it when [creating a machine pool](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-a-machine-pool). ### Creating a machine pool Create a machine pool that allows running GitHub Action builds on Bitrise hardware. The process is slightly different based on whether you use [a GitHub app](/bitrise-build-hub/build-hub-for-github-actions/build-hub-for-github-actions-overview#authentication) or a [GitHub personal access token](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-github-personal-access-tokens-for-build-hub) for authentication. :::important[Public repositories] If you plan to run builds for a public repository, the runner group your machine pool registers into must have **Allow public repositories** enabled on GitHub (**Organization settings** → **Actions** → **Runner groups**). Without this, GitHub won't dispatch jobs from public repositories to your Build Hub runners: jobs stay queued indefinitely even though the pool, labels, and authentication are all healthy. **Enable this setting at your own risk.** GitHub disables it by default for a serious security reason: fork PR workflows on public repositories can execute untrusted code from external contributors on your self-hosted Build Hub runners, exposing your build environment, secrets, and infrastructure. Before enabling, require approval for workflows on fork PRs at a minimum. See [Approving workflow runs from public forks](https://docs.github.com/en/actions/how-tos/manage-workflow-runs/approve-runs-from-forks) in the GitHub docs. ::: **GitHub app authentication** 1. On the left navigation bar, select **Build Hub**. 1. Click **Machine pool**. ![Build Hub page with the left navigation bar Build Hub item and the Machine pool button highlighted](/img/bitrise-build-hub/2026-09-08-build-hub-select-machine-pool.png) 1. Open the **CI provider** dropdown menu. Select an already-connected account, or click **Connect account** to add a new one. 1. Select GitHub **(GitHub App)** and click **Continue to install**. ![SCR-20260320-mmwy.png](/img/_paligo/uuid-115c121e-082e-a3b6-6741-f53cdab5d89e.png) 1. Select the resource owner. 1. Select the repository scope. - **All repositories**: Applies to all current and future repositories owned by the resource owner. Also includes public repositories (read-only). - **Only select repositories**: Select at least one repository. Also includes public repositories (read-only). ![SCR-20260320-nqmt.png](/img/_paligo/uuid-6186a9bb-4a81-f79c-3200-1e65de613b47.png) 1. Set a unique **Pool name**. You can't change this after creation. 1. Select the connected account in the **CI provider** dropdown menu. 1. Add a **Runner group**. [Runner groups](https://docs.github.com/en/actions/concepts/runners/runner-groups) create a security boundary in GitHub that controls which repositories or organizations can dispatch jobs to your runners. If the group doesn't exist yet on GitHub, Bitrise creates it automatically. Runner groups aren't used to target this specific pool in your workflow: use labels and the `runs-on` property for that instead. 1. When done, click **Next**. 1. Select the image in the **Image** dropdown menu and the amount of machines you need in the **Nr. of machines** field. You can check the images on the [stack reports page](https://bitrise.io/stacks). 1. Select a machine type. For more information about Bitrise machines, check out [Build machines](/bitrise-platform/infrastructure/build-machines/about-build-machines). 1. When done, click **Next**. 1. Check **Use Bitrise for GitHub Actions caching** if you want Bitrise infrastructure to handle GitHub Actions cache requests instead of GitHub's cache backend. This results in faster cache operations. 1. Optionally, add a warmup script to customize your build environment before your Workflow runs. Leave it empty if you don't need a warmup script. :::important[Non-zero exit code] To prevent build start failures, make sure the script returns a non-zero exit code in case of an error. ::: 1. When done, click **Next**. 1. Optionally, add extra labels to help target this pool in your workflow. Bitrise always applies a default set of labels — the pool name, the image, and the machine type — and these can't be changed or removed. You can add your own labels alongside them; a label is a key-value pair, but only the key is mandatory. Labels are how your [GitHub Actions configuration](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#configuring-your-github-actions-workflow) targets this pool, so make sure the `runs-on` property in your workflow file uses the same labels you set here. 1. Click **Create pool**. **GitHub personal access token** 1. On the left navigation bar, select **Build Hub**. 1. Click **Machine pool**. ![Build Hub page with the left navigation bar Build Hub item and the Machine pool button highlighted](/img/bitrise-build-hub/2026-09-08-build-hub-select-machine-pool.png) 1. Open the **CI provider** dropdown menu. Select an already-connected account, or click **Connect account** to add a new one. 1. Click **Connect account** and select **GitHub (PAT)**. 1. Set a connection name and a target scope URL. Read more about target scopes here: [Target scope](/bitrise-build-hub/build-hub-for-github-actions/build-hub-for-github-actions-overview#target-scope) ![SCR-20260320-nsxn.png](/img/_paligo/uuid-22b5a6f5-fedb-0cc6-b685-1bb5406d1e12.png) 1. In the **Personal access token** field, add your GitHub personal access token then click **Connect**. 1. Set a unique **Pool name**. You can't change this after creation. 1. Select the connected account in the **CI provider** dropdown menu. 1. Add a **Runner group**. [Runner groups](https://docs.github.com/en/actions/concepts/runners/runner-groups) create a security boundary in GitHub that controls which repositories or organizations can dispatch jobs to your runners. If the group doesn't exist yet on GitHub, Bitrise creates it automatically. Runner groups aren't used to target this specific pool in your workflow: use labels and the `runs-on` property for that instead. 1. When done, click **Next**. 1. Select the image in the **Image** dropdown menu and the amount of machines you need in the **Nr. of machines** field. You can check the images on the [stack reports page](https://bitrise.io/stacks). 1. Select a machine type. For more information about Bitrise machines, check out [Build machines](/bitrise-platform/infrastructure/build-machines/about-build-machines). 1. When done, click **Next**. 1. Check **Use Bitrise for GitHub Actions caching** if you want Bitrise infrastructure to handle GitHub Actions cache requests instead of GitHub's cache backend. This results in faster cache operations. 1. Optionally, add a warmup script to customize your build environment before your Workflow runs. Leave it empty if you don't need a warmup script. :::important[Non-zero exit code] To prevent build start failures, make sure the script returns a non-zero exit code in case of an error. ::: 1. When done, click **Next**. 1. Optionally, add extra labels to help target this pool in your workflow. Bitrise always applies a default set of labels — the pool name, the image, and the machine type — and these can't be changed or removed. You can add your own labels alongside them; a label is a key-value pair, but only the key is mandatory. Labels are how your [GitHub Actions configuration](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#configuring-your-github-actions-workflow) targets this pool, so make sure the `runs-on` property in your workflow file uses the same labels you set here. 1. Click **Create pool**. ### Configuring your GitHub Actions workflow After you successfully create a machine pool, you need to configure your GitHub Actions workflow to use the machine pool when running your builds. Use the `runs-on` property in your workflow to specify the Bitrise machines. You can target runners based on the labels assigned to them. 1. Open your GitHub repository and select **Actions**. 1. On the left, click the name of the Workflow. 1. Under the name of the Workflow, click **deploy.yml**. 1. Add the `runs-on` property to the jobs you want to run on Build Hub. You must target the labels you create when [creating or updating a machine pool](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#creating-a-machine-pool). - You can use a single label. This will allow the use of all runners that have the specified label: ```yaml jobs: build: runs-on: image:xcode-26 ``` - You can use an array of labels. A runner is only allowed if it has all the specified labels: ```yaml jobs: build: runs-on: [bitrise-runner-my-pool, image:xcode-26] ``` Bitrise automatically creates a `bitrise-runner-` label for every machine pool, so you can target a specific pool by name. For more information on the `runs-on` property, check out the [GitHub Actions documentation](https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job). #### Enabling Linux machines to access tooling :::warning[Only for the deprecated Docker-based Linux image] This section only applies to machine pools using the deprecated Docker-based `linux-docker-bitvirt` image. The `linux-bitvirt-2026` image doesn't require any of these steps. ::: Machine pools using the `linux-docker-bitvirt` image require a workaround to access the preinstalled tools on the Linux image when running a GitHub Actions workflow on Build Hub. When a GitHub Actions workflow uses the `container:` property to run steps inside a Docker container, the runner changes the environment in ways that break the image's tool setup. This means that the build can't access `asdf` as the tool manager and therefore preinstalled tools are not accessible. To solve the problem: 1. Add an `env` property to your container configuration in the GitHub Actions workflow. Set three Environment Variables to tell `asdf` where its core scripts and plugins, installed versions, and shims are, and to override the image's `BASH_ENV=/.bashrc`. ```yaml container: image: bitriseio/ubuntu-noble-24.04-bitrise-2025-android:latest env: ASDF_DIR: /root/.asdf ASDF_DATA_DIR: /root/.asdf BASH_ENV: /root/.asdf/asdf.sh ``` 1. Under the `defaults` property, set the default shell to `bash`. ```yaml container: image: bitriseio/ubuntu-noble-24.04-bitrise-2025-android:latest env: ASDF_DIR: /root/.asdf ASDF_DATA_DIR: /root/.asdf BASH_ENV: /root/.asdf/asdf.sh defaults: run: shell: bash ``` 1. Under the `steps` property, add a step that copies the image's default tool versions to where `asdf` expects them. ```yaml steps: - name: Setup environment run: | cp /root/.tool-versions "$HOME/.tool-versions" ``` 1. Tell Git to treat all working directories as safe. Without this, some commands might fail because of directory ownership mismatch. ```yaml steps: - name: Setup environment run: | cp /root/.tool-versions "$HOME/.tool-versions" git config --global --add safe.directory '*' ``` --- ## Bitrise Build Hub --- ## Build machine types Bitrise offers multiple build machines with different specifications You can choose between them based on your needs. You can track how much time you spent building your apps on each machine type with Insights: [Bitrise CI metrics](/insights/available-metrics-in-insights/bitrise-ci-metrics). :::tip[Machine availability by subscription plan] Not all machines are available on all subscription plans. Visit [the pricing page](http://www.bitrise.io/pricing) to find out which machines are available on your plan! ::: Machine types are divided into resource classes. The same resource class offers multiple machine types with broadly similar performances. Bitrise automatically assigns machine types from a resource class, which means that on the same day, your builds might run on different machine types. :::tip Use the machine type ID to set the machine type in your [configuration YAML](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds#setting-the-stack-in-the-configuration-yaml). ::: | OS and resource class | Hardware type | Specs | Machine type ID | | --- | --- | --- | --- | | macOS Medium | M2 Pro Medium | • 4 CPU @3.49GHz• 6 GB RAM | `g2.mac.medium` | | macOS Medium | M4 Medium | • 5 CPU @4.4 GHz• 6 GB RAM | `g2.mac.medium` | | macOS Large | M2 Pro Large | • 6 CPU @3.49GHz• 14 GB RAM | `g2.mac.large` | | macOS Large | M4 Large | • 5 CPU @4.4 GHz• 14 GB RAM | `g2.mac.large` | | macOS X Large | M2 Pro X Large | • 12 CPU @3.49GHz• 28 GB RAM | `g2.mac.x-large` | | macOS X Large | M4 X Large | • 10 CPU @4.4 GHz• 28 GB RAM | `g2.mac.x-large` | | macOS 4Large | M4 Pro Large | • 7 CPU @4.52GHz• 27 GB RAM | `g2.mac.4large` | | macOS 4X Large | M4 Pro X Large | • 14 CPU @4.52GHz• 54 GB RAM | `g2.mac.4x-large` | | Linux Medium | | • 4 vCPU @3.1 GHz• 16 GB RAM | `standard` | | Linux Large | | • 8 vCPU @3.1 GHz• 32 GB RAM | `elite` | | Linux X Large | | • 16 vCPU @3.1 GHz• 64 GB RAM | `elite-xl` | | Linux Small | AMD EPYC Zen 4/5 | • 2 vCPU• 8 GB RAM | `g2.linux.2small` | | Linux M | AMD EPYC Zen 4/5 | • 4 vCPU @3.7 GHz• 16 GB RAM | `g2.linux.medium` | | Linux 2M | AMD EPYC Zen 4/5 | • 6 vCPU @3.7 GHz• 24 GB RAM | `g2.linux.2medium` | | Linux L | AMD EPYC Zen 4/5 | • 8 vCPU @3.7 GHz• 32 GB RAM | `g2.linux.large` | | Linux 4L | AMD EPYC Zen 4/5 | • 14 vCPU @3.7 GHz• 56 GB RAM | `g2.linux.4large` | | Linux XL | AMD EPYC Zen 4/5 | • 16 vCPU @3.7 GHz• 64 GB RAM | `g2.linux.x-large` | | Linux 3XL | AMD EPYC Zen 4/5 | • 24 vCPU @3.7 GHz• 96 GB RAM | `g2.linux.3x-large` | | Linux 5XL | AMD EPYC Zen 4/5 | • 32 vCPU @3.7 GHz• 128 GB RAM | `g2.linux.5x-large` | | Linux 7XL | AMD EPYC Zen 4/5 | • 48 vCPU @3.7 GHz• 192 GB RAM | `g2.linux.7x-large` | :::note Some macOS resource classes list two hardware types with the same machine type ID. Both generations use the same ID — Bitrise automatically selects the available hardware for each build. ::: --- ## About build stacks The build stack indicates the virtual machine version that we will use to run your build. The main stack types are: - **macOS stacks**: These stacks run on a macOS operating system and each one includes multiple Xcode versions. Ideal for building iOS apps. They also have Android tools installed if you want to use them to build a cross-platform app. - The **Android & Docker** stack: These stacks run on Linux operating system in a Docker environment. They have all Android tools installed and they are ideal for building native Android apps. :::note[Free disk space] Each stack has at least 100 GB of free disk space. You can check each stack's exact available disk space on the relevant stack report page: [Bitrise stack reports](https://stacks.bitrise.io/stack_reports/). ::: Each build runs in its own virtual machine and the virtual machine is rolled back to a saved state, the “base box” state, after the build is finished. This way **your builds are always protected** by changes made by others and by your previous builds and you can use a **stable environment** to define your build workflow, since no state persists between builds. :::note[Passwordless sudo enabled] The user account that is used for the builds is configured to have **passwordless sudo** enabled. This way you are able to install all the extra things you need for your builds and for other automation. If a tool is not preinstalled on your stack of choice, you can install it yourself - see the guide. ::: After adding your app to Bitrise we will select an appropriate stack for it. You can change the stack at any time on the **Stacks & Machines** tab of the Workflow Editor. ![xcode_image.png](/img/_paligo/uuid-fc53715a-add5-8c4c-d4a6-9a04f5da6d3b.png) After selecting the stack you want to use, you’ll see a short description of the stack with an additional link to learn more about that specific one (for example, to see what tools are preinstalled, and which versions, on the selected stack). | Type | Description | | --- | --- | | Stable | Generally available and expected to be supported for the foreseeable future. Updated when an update for the stack’s primary tool is available. Example: when Xcode 7.3.1 was released, the Xcode 7.3 stack was updated to have 7.3.1 instead of 7.3(.0). | | Type | Description | | --- | --- | | Pre-booted | If a stack is available as pre-booted, and there’s enough pre-booted machines with that stack configuration, your build can start right away, without waiting for the build environment to boot. In case there’s no more available pre-booted machine with that stack configuration, your build will start on an on-demand configuration. | | On-demand | If a stack is available as on-demand configuration and there’s no (available) pre-booted configuration for the stack, our system will have to create a virtual machine for your selected configuration when your build starts. This means that your build will be in preparing environment state while the related virtual machine is created & booted. For a macOS configuration the boot process usually takes about 1 - 1.5 minutes. The prepare time (of course) is not counted into the build time, it won’t affect how long your build can run. | --- ## Changelog ### June 2025 **Changed** Mentions of Linux stack update policy has been moved on its own page, [Linux stack update policy](/bitrise-build-hub/infrastructure/build-stacks/linux-stack-update-policy), with more information on Edge, Stable and Frozen stacks. It also describes the yearly cadence of new Linux stacks, as well as the deprecation and removal of older Linux stacks. Removed how to use previous versions of a stack from this page and added it to [Stack update policy](/bitrise-build-hub/infrastructure/build-stacks/stack-update-policy). ### July 2024 **Removed**: Mentions of dependency manager cache updates. Both Cocoapods and Homebrew have better mechanisms now than cloning the entire registry git repo, and these newer mechanisms (Cocoapods CDN, Homebrew API) are enabled on stacks now. When stacks are updated, you can expect the on-disk repos to be up-to-date, but Stable stacks are no longer strictly updated weekly if there are no other changes to release. **Changed**: The breaking changes to stable macOS stacks (once a year when a new Xcode major version is released) no longer apply to older, existing stable stacks, only the newly released stable stack. For example, when Xcode 16.0 is released, the planned breaking changes only apply to the Xcode 16.0 stable stack. Xcode 14.x and 15.x stable stacks won’t receive breaking changes. ### March 2024 **New**: Define what happens when an Edge stack is phased out in favor of a newer edge stack. **Removed**: When a new Xcode Edge stack is released, it no longer brings tooling changes to the Stable stacks. **Changed**: New, simpler simulator runtime policy. The same number of older iOS major versions are installed, but only the latest minor version is installed for each. --- ## Linux stack update policy Linux stacks on Bitrise are based on Ubuntu LTS releases. Each Bitrise stack is based on one Ubuntu LTS version and never gets upgraded to another. Instead, we release new stacks and sunset older ones over time. :::note[Previous version of a stack] Updating a stack to a new version might cause problems with some builds. To help ease the transition, you can use the previous version of a stack for 2-3 days after an update: [Using the previous version of a stack](/bitrise-build-hub/infrastructure/build-stacks/stack-update-policy#using-the-previous-version-of-a-stack). ::: For macOS specific information, check out [macOS stack update policy](/bitrise-build-hub/infrastructure/build-stacks/macos-stack-update-policy). ### Linux stack offerings Bitrise offers multiple Linux stacks to handle different use-cases. You can check the available stacks at any given time [here](https://bitrise.io/stacks/). Each stack is based on one release of a Linux distribution. At the moment, we offer stacks based on Ubuntu LTS releases. Tools are installed on this base image, creating the Bitrise edition of a system. The stack name and ID contains all of the above parameters and looks like this in practice: - Name: Ubuntu Noble 24.04 - Bitrise 2025 Edition - ID: `ubuntu-noble-24.04-bitrise-2025-android` There are subtle differences between the different Linux stacks and their update frequency. You need to be aware of these details in order to pick the right stack and to avoid sudden broken builds. ### Linux stack updates A new Bitrise edition and a new stack is created each year. This is always based on the latest Ubuntu LTS release. Besides the new Ubuntu release, this new yearly Bitrise edition contains breaking changes that would have been too disruptive to ship in existing stacks. For example: - Upgrading a preinstalled tool to a new version with breaking changes. - When multiple versions of a tool are installed (for example, Ruby, Node.js,), removing an old version that reached its end-of-life and no longer receives security fixes. - Configuration changes that could be breaking to some or all user workflows. | Year of stack release | Stack name | Ubuntu base | | --- | --- | --- | | 2024 | Ubuntu Jammy 22.04 - Bitrise 2024 Edition | Ubuntu 22.04 LTS | | 2025 | Ubuntu Noble 24.04 - Bitrise 2025 Edition | Ubuntu 24.04 LTS | | **Future releases** (release codenames are unknown at this point) | | | | 2026 | Ubuntu 26.04 - Bitrise 2026 Edition | Ubuntu 26.04 | | 2027 | Ubuntu 26.04 - Bitrise 2027 Edition | | | 2028 | Ubuntu 28.04 - Bitrise 2028 Edition | Ubuntu 28.04 | | 2029 | Ubuntu 28.04 - Bitrise 2029 Edition | | ### Stack lifecycle Similar to macOS Bitrise stacks, the Linux ones have the following lifecycle: Edge, Stable, Frozen, Removed. A new stack is introduced as an edge stack first, then, after a year of testing and feedback, it becomes a stable stack. One year later it’s marked as frozen, then completely removed after one more year. Different stages of a single stack: ![stack-state-change.svg](/img/_paligo/uuid-5169df38-e851-52da-fb4f-d37c3f98e8d8.svg) Every year, around April and the release of the new Ubuntu version: - A new stack is introduced as an edge stack. - Last year’s edge stack becomes stable. - Last year’s stable stack becomes frozen. - Last year’s frozen stack gets removed. Changing states presented with previous and future stacks: ![multiple-stack-state-change.svg](/img/_paligo/uuid-bcc68f5e-feec-8292-2e57-1bfb0dd9d9b9.svg) Before a stack is removed, it’s flagged for removal, and you see the final removal date throughout the UI. Additionally, the remaining users of the stack receive an email notification from Bitrise. ### Which stack to choose? At any given time, you can choose from at least one edge, stable and frozen stack. The following table helps make this choice: | | Edge | Stable | Frozen | | --- | --- | --- | --- | | Stable stack ID which can be included in bitrise.yml | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Security updates to OS components, system libraries and preinstalled tools | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Updates to OS components and system libraries | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Addition of new tools and tool versions | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Breaking changes in stack updates to existing tools and tool versions | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | New experimental features and configuration changes | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Removal of tools and tool versions | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ### Changelog June 2025 **New** Introduced the concept of Edge, Stable and Frozen stacks with regards to Linux, similar to the [macOS stack update policy](/bitrise-build-hub/infrastructure/build-stacks/macos-stack-update-policy). Defined the yearly cadence of new Linux stacks, as well as the deprecation and removal of older Linux stacks. --- ## macOS stack update policy ### Xcode stack updates You can select macOS stacks based on the Xcode version you need. Under the hood, one VM image contains multiple Xcode versions installed and your requested Xcode version is activated at runtime before your Workflow starts. As a rule of thumb, Xcode minor versions of the same major version share the same VM image, but there might be exceptions based on compatibility issues and other considerations. :::note[Versioning] When talking about versions, we use [semver](https://semver.org/) terminology, regardless of how the various tools define their versions. ::: Stacks have a lifecycle and have four different states: Edge, Stable, Frozen and Removed. ![stack-lifecycle.png](/img/_paligo/uuid-faa7bf60-0cae-0042-f910-e8e6240fc647.png) - **Edge**: These stacks are for previewing upcoming versions and changes. They are updated in-place regularly, and they include the latest stable release of Xcode, the latest beta release of Xcode (if available) and the latest stable version of pre-installed tools. Regular weekly updates could add or remove tools, as well as upgrade the OS. Backwards compatibility for weekly updates is not guaranteed on an Edge stack. Run builds on Edge stacks to preview upcoming tool version changes (such as Ruby 3.2 becoming the default) and get access to the latest pre-release Xcode (such as Xcode 15 Beta). - **Stable**: These stacks are only updated with Xcode patch versions, and with critical security fixes. For maximum reliability and reproducible builds, we recommend pinning exact tool versions in Workflows instead of relying on the stack defaults (for example, pinning a Ruby version). - **Frozen**: These stacks are no longer updated and flagged for removal in accordance with the [Stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). The stack is still available for yourbuilds but you will see the final removal date on the UI. Preinstalled tools are not updated, so it’s your responsibility to keep up with bugfixes and security patches. - **Removed**: These stacks are no longer available to use. #### State transitions for Xcode stacks During the lifecycle of a stack it will transition between states when triggered by new Xcode and macOS releases. Stacks transition as follows: - Edge to Stable. - Stable to Frozen. - Frozen to Removed. ##### Edge stack updates Edge stacks provide a way to preview and test upcoming changes. Xcode Beta versions become available as Edge stacks while final Xcode releases become available as new Stable stacks. Xcode Edge stacks change when: 1. The first Beta version of a new major Xcode version is released. 1. The first Beta version of a new minor Xcode version is released. 1. A new version of an Xcode Beta version is released. When an Xcode minor version is released as a beta, it becomes available as an Edge stack. Other Edge stacks do not transition to Stable until the beta version in question is released as a GA version. **First Beta version of a new major Xcode version** In this example: - The current latest Xcode version is 15.3. - A new Beta version of a new major Xcode version is released: Xcode 16.0 Beta 1. ![stack-updates-edge.png](/img/_paligo/uuid-1aecaab6-06d6-4a03-4d67-f6e4e5efaf7e.png) Once the new Beta version is released, we update our stacks: - The new Xcode release becomes available on Bitrise as an Edge stack. In our example, Xcode 16.0 Beta 1 becomes available as the Edge stack. - Current Edge stacks are phased out, and users are automatically migrated to the new Edge stack. This happens a few days after the new Xcode release. In this example, this means phasing out Xcode 15.x Edge stacks. - Stable stacks are not affected at this point. **First Beta version of a new minor Xcode version** In this example: - The current latest Xcode version is 15.2. - A new Beta version of a new minor Xcode version is released: Xcode 15.3 Beta 1. ![stack-updates-edge-minor.png](/img/_paligo/uuid-1045ef58-753d-f496-2c8a-4e4c9542ad63.png) Once the new Beta version is released, we update our stacks: - The new Xcode release becomes available as an Edge stack. In this example, Xcode 15.3 Beta 1 becomes available as an Edge stack. - Stable stacks are not affected at this point. **A new Beta version of an Xcode Beta version** In this example: - The current latest Xcode version is 16.0 Beta 1. - A new Beta version is released: 16.0 Beta 2. ![stack-updates-edge-beta.png](/img/_paligo/uuid-f91e8132-cff5-b5c3-142e-2184b4883382.png) Once the new Beta version is released, we update our stacks: - Xcode 16.0 Beta 2 replaces 16.0 Beta 1 on the Xcode 16.0 Edge stack. - Stable stacks are not affected at this point. ##### Stable stack updates Stable stacks change less often than Edge stacks as we want to avoid unexpected breaking changes on these stacks. Existing Stable stacks change when: 1. A new major Xcode version is released. 1. A new minor Xcode version is released. **A new major Xcode version** In this example: - The current latest Xcode version is 15.3.0. - A new major Xcode version is released: Xcode 16.0. ![stable-stack.png](/img/_paligo/uuid-0d392a7d-4fcd-13cb-e67a-7326e954c87a.png) When the new major version is released, we update our stacks: - New Stable stack: Xcode 16.0 becomes available on Bitrise as a new Stable stack. - Oldest Stable stacks become Frozen. In this example, Xcode 14.x stacks become Frozen, but still available for building. Tool versions are not changing on these stacks: their latest state is frozen. - Old Frozen stacks are removed: in this example, Xcode 13.x stacks are removed. The remaining users are migrated to newer stacks. **A new minor Xcode version** In this example: - The current latest Xcode version is Xcode 15.2. - A new minor Xcode version is released: Xcode 15.3. When the new minor version is released, we update our stacks: - New Stable stack: Xcode 15.3 becomes available on Bitrise as a Stable stack. - Xcode 15.3 Edge stack is updated with the final Xcode version. ![stack-updates-stable-xcode-minor.png](/img/_paligo/uuid-166098b3-ad6e-d65e-fe83-e0819fcf52a3.png) ##### macOS releases The exact macOS version is always highlighted on the [stack report pages](https://stacks.bitrise.io/stack_reports/). When a new major macOS version is released, we upgrade the Edge stacks to the new OS after an internal testing period. As a general rule, we don’t upgrade macOS on Stable stacks to avoid unexpected build failures. We wait until a future Xcode release starts requiring the new OS version (for example, Xcode 15.0, 15.1 and 15.2 are compatible with macOS Ventura, but 15.3 requires Sonoma). Once this happens, the Stable stack variant of this Xcode version is based on the new major OS version, while older Stable Xcode stacks remain on the older OS version. While the new major OS is not available as a Stable stack, we recommend testing it on one of the Edge stacks. We are looking for your feedback, including edge cases and performance regressions. ##### Events not triggering a state transition Not all Xcode releases trigger a transition. For example, Xcode beta minor version releases do not trigger an Edge to Stable stack transition: the new beta version simply replaces the old one. Xcode patch releases do not trigger an Edge to Stable stack transition. Instead, the Stable stacks will be updated in place with the new patch version. #### Simulator runtimes on Xcode stacks You can find the list of preinstalled tools, including simulator runtimes on our stacks on the [stack reports pages](https://stacks.bitrise.io/stack_reports/). You can expect the following simulator runtimes to be installed: - The matching runtime versions of a given Xcode version: these are the iOS, watchOS, tvOS and visionOS runtime versions that Xcode prompts you to download at first launch. - For iOS, we also install two additional versions: the two previous major versions, of which the latest minor version is installed. - For watchOS, we also install the previous major release’s latest minor version. For example, when selecting the Xcode 15.0 stack, you can expect: - iOS 17.0: the matching runtime of this Xcode. - iOS 16.4: the latest minor release of the previous major iOS version. - iOS 15.5: the latest minor release of the second-previous major iOS version. - watchOS 10.0: the matching runtime of this Xcode. - watchOS 9.4: the latest minor release of the previous major version. - tvOS 17.0: the matching runtime of this Xcode. - visionOS 1.0: the matching runtime of this Xcode ### Changelog #### June 2025 **Changed** Mentions of Linux stack update policy has been moved on its own page, [Linux stack update policy](/bitrise-build-hub/infrastructure/build-stacks/linux-stack-update-policy), with more information on Edge, Stable and Frozen stacks. It also describes the yearly cadence of new Linux stacks, as well as the deprecation and removal of older Linux stacks. Removed how to use previous versions of a stack from this page and added it to [Stack update policy](/bitrise-build-hub/infrastructure/build-stacks/stack-update-policy). #### July 2024 **Removed**: Mentions of dependency manager cache updates. Both Cocoapods and Homebrew have better mechanisms now than cloning the entire registry git repo, and these newer mechanisms (Cocoapods CDN, Homebrew API) are enabled on stacks now. When stacks are updated, you can expect the on-disk repos to be up-to-date, but Stable stacks are no longer strictly updated weekly if there are no other changes to release. **Changed**: The breaking changes to stable macOS stacks (once a year when a new Xcode major version is released) no longer apply to older, existing stable stacks, only the newly released stable stack. For example, when Xcode 16.0 is released, the planned breaking changes only apply to the Xcode 16.0 stable stack. Xcode 14.x and 15.x stable stacks won’t receive breaking changes. #### March 2024 **New**: Define what happens when an Edge stack is phased out in favor of a newer edge stack. **Removed**: When a new Xcode Edge stack is released, it no longer brings tooling changes to the Stable stacks. **Changed**: New, simpler simulator runtime policy. The same number of older iOS major versions are installed, but only the latest minor version is installed for each. --- ## Stack deprecation and removal policy We don't keep all stacks around forever: our aim is to provide you with the latest tools to help you build the best app you can. However, we don't expect you to rework your build configuration every time a stack update comes out: you can keep using your reliable older stacks for a long time. Some older stacks are frozen when a new major version of Xcode is released. When a stack is frozen, you can still keep using it, but the stack will no longer get any updates, and at that point, we strongly recommend switching to a newer, active stack. After stacks have been frozen for a year, they are removed when the next major version of Xcode is released. ### Maintaining Xcode stacks We offer a wide variety of Xcode stacks in order to make sure you do not need to immediately switch when a new version comes out. Our policy is as follows: - Keep the three most recent major versions of Xcode. - Keep the two most recent minor versions for each major version of Xcode. We base our policy on Apple's current release cadence: first beta in June, general availability in September. 1. The life cycle of a major Xcode version on our stacks is 36 months. 1. For 24 months, the stack is active and maintained according to our stack update policy. 1. After 24 months, the stack becomes frozen for 12 months and it will no longer receive updates. At this point, we strongly recommend migrating to an active stack. 1. After the end of the 36th month, the stacks of the major Xcode version are removed. **Maintaining Xcode stacks** When Xcode version 15.2.x is released, we will keep: All the latest patch releases for the two most recent minor versions of Xcode 15: - 15.2 - 15.1 Xcode 15.0 will be removed. The two latest versions from the previous two Xcode major versions: - Xcode 14.3 - Xcode 14.2 - Xcode 13.4 (frozen) - Xcode 13.3 (frozen) In all cases, there will be a minimum of four weeks' notice provided for the removal of these stacks. You can see all upcoming stack deprecations [on this page](https://stacks.bitrise.io/announcements/upcoming-stack-deprecations/). We also recommend subscribing to [RSS updates](https://stacks.bitrise.io/tips/get-notified/) of important announcements about stacks. ### Deprecating Linux stacks A Linux stack is supported for about two years, roughly in sync with [Ubuntu LTS (long term support)](https://endoflife.date/ubuntu) releases. When a previous Linux stack reaches end of maintenance, we deprecate the stack and earmark it for removal. At that point you can no longer select the stack for your apps. But the apps that are already using those stacks can keep using them until removal. In all cases, there will be a minimum of four weeks' notice provided for the removal of these stacks. You can see all upcoming stack deprecations [on this page](https://stacks.bitrise.io/announcements/upcoming-stack-deprecations/). We also recommend subscribing to [RSS updates](https://stacks.bitrise.io/tips/get-notified/) of important announcements about stacks. --- ## Stack update policy Bitrise stacks include the most important tools for mobile development pre-installed and ready for use. Our goal is to make Workflows simple and make your builds fast and efficient. These tools change continuously: old versions become deprecated and unsupported while new versions are released with new features and breaking changes. Stacks on [bitrise.io](https://www.bitrise.io) are updated regularly. The updates contain one or more of the following kinds of changes: - Tool upgrade: An already installed tool is upgraded to the latest version (for example, the git CLI is upgraded from 2.9.1 to 2.9.5). - Tool addition: A new tool is added (for example, the latest Android emulator system image becomes preinstalled when a new Android version is released). - Tool removal: A tool version is removed if it reaches end-of-life and poses a security risk, making another version of the tool the default (for example, Ruby 2.7 is removed, making Ruby 3.0 the new default). - Platform changes: Changes to major components, like Xcode on macOS stacks, OS versions, Android SDK. If you wish to read more on our Linux and MacOS stack update policies, check out: - [macOS stack update policy](/bitrise-build-hub/infrastructure/build-stacks/macos-stack-update-policy) - [Linux stack update policy](/bitrise-build-hub/infrastructure/build-stacks/linux-stack-update-policy) :::note[Using the previous version of a stack] Updating a stack to a new version might cause problems with some builds. To help ease the transition, you can use the previous version of a stack for 2-3 days after an update: [Using the previous version of a stack](/bitrise-build-hub/infrastructure/build-stacks/stack-update-policy#using-the-previous-version-of-a-stack). ::: For more information on what tools are available on the different stacks, check out our relevant guide: [Preinstalled tools on Bitrise stacks](/bitrise-platform/infrastructure/build-stacks/preinstalled-tools-on-bitrise-stacks) ### Using the previous version of a stack We regularly update the Bitrise stacks based on user requests and external tooling changes. These updates can potentially introduce breaking changes, despite our efforts to avoid those. For those cases, we provide a temporary option to use the previous version of a given stack for a few days after the release of a new version. - This is meant to be a temporary mechanism only. Because of infrastructure reasons, we can't keep the previous release available forever. Usually, the previous version is removed a few days after a successful release. - Once the previous version becomes unavailable, new builds run on the latest version even if this feature is enabled. - If a previous version is not available for a given stack at a given time, the switch is inactive and the feature can't be turned on. Any build triggered will run on the current version of the stack. To use the previous version of your stack: **Workflow Editor** 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. ![workflows-button.png](/img/_paligo/uuid-99bb894c-3e79-91c8-9e62-7e475573495d.png) 1. Go to the **Stacks & Machines** tab. 1. Find the stack you want to configure: either the default stack or one of the Workflow-specific stacks. 1. Under the machine type for the chosen stack, toggle the **Use previous version** switch. This modifies the `bitrise.yml` file: it adds the previous version of the stack to the `meta` block. ![prev-vers.png](/img/_paligo/uuid-eefe9d3d-ab41-f2c3-9657-97994dab1f73.png) **Configuration YAML** 1. Find the `meta` block in your `bitrise.yml` file. 1. Add a `stack_rollback_version` field with the given version string. :::tip[Finding out the previous version number] To find out the previous version string, open an older build, switch to the **Details** tab, and look for the **Stack image version** field. ::: ```yaml meta: stack: osx-xcode-15.0.x machine_type_id: g2-m1.8core stack_rollback_version: 2-16-2 ``` --- ## IP addresses for the build machines For most users, who host their repositories on cloud-based service providers, there is no need for any network configuration to be able to use Bitrise. All we need is permission to access the repository and for that, [an SSH key](/bitrise-platform/repository-access/configuring-ssh-keys) or [an access token](/bitrise-platform/repository-access/configuring-https-authorization-credentials) is enough. However, your company security policy might not allow unknown and unauthorized IP addresses to communicate with the servers where your code is being stored - either on your own datacenter or in a private cloud. In that case, Bitrise won’t work unless the relevant IP addresses are added to your allow list. You will see IP addresses from the following ranges as source when your Bitrise build machines reach out to your services like Git to download your source code, or call into your test backend services, or any other services you run outside Bitrise that are required to be reached as part of your CI workflow. :::warning[Allowlist the entire subnet] If the provided public IP address is a subnet, you need to allow the entire subnet on your network! For example, 208.52.166.128/28 means all IP addresses between 208.52.166.128 and 208.52.166.143 (208.52.166.128, 208.52.166.129, 208.52.166.130, and so on, all the way to and including 208.52.166.143) have to be allowlisted. ::: :::warning[Multi-tenant vs Single-tenant] The build machine IP ranges listed below are for the Bitrise multi-tenant environment. Depending on your organization's security requirements, it may not be advisable to allow access to your network from the Bitrise multi-tenant IP range. For organizations with enhanced security requirements, you can: - [Connect by VPN](/bitrise-platform/integrations/connecting-to-a-vpn-during-a-build). - [Select a single-tenant environment](/bitrise-platform/infrastructure/customizable-enterprise-build-platforms). - [Deploy runners to your own AWS account](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates). Feel free to [contact us](https://bitrise.io/contact) if you have questions. ::: macOS IP addresses Linux IP addresses 74.122.200.224/27(74.122.200.224 - 74.122.200.255)74.122.201.224/27(74.122.201.224 - 74.122.201.255)74.122.202.224/27(74.122.202.224 - 74.122.202.255)74.122.203.224/27(74.122.203.224 - 74.122.203.255) 74.122.200.224/27(74.122.200.224 - 74.122.200.255)74.122.201.224/27(74.122.201.224 - 74.122.201.255)74.122.202.224/27(74.122.202.224 - 74.122.202.255)74.122.203.224/27(74.122.203.224 - 74.122.203.255) 185.55.252.224/27(185.55.252.224 - 185.55.252.255)185.55.253.224/27(185.55.253.224 - 185.55.253.255)185.55.254.224/27(185.55.254.224 - 185.55.254.255)185.55.255.224/27(185.55.255.224 - 185.55.255.255) 185.55.252.224/27(185.55.252.224 - 185.55.252.255)185.55.253.224/27(185.55.253.224 - 185.55.253.255)185.55.254.224/27(185.55.254.224 - 185.55.254.255)185.55.255.224/27(185.55.255.224 - 185.55.255.255) 208.52.166.154/32 104.197.15.74/32 208.52.166.128/28 34.123.172.192/32 207.254.0.248/29 34.125.50.224/32 207.254.0.208/28 34.125.82.130/32 207.254.34.148/32 34.134.193.138/32 207.254.33.176/28 34.138.187.10/32 34.150.152.190/32 34.162.185.129/32 34.162.202.37/32 34.162.229.32/32 34.162.29.153/32 34.162.88.79/32 34.23.207.105/32 34.85.139.176/32 34.85.240.93/32 34.86.56.118/32 35.202.121.43/32 35.225.44.167/32 35.231.56.118/32 35.237.165.17/32 35.243.148.182/32 35.245.56.67/32 --- ## Adding and managing apps You can add new projects on Bitrise with the API: add the project, generate SSH keys, and set up the project’s initial configuration. In addition, you can list all projects belonging, for example, to a single user or to a specific Workspace. ### Adding a new app with the API | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | POST /apps/register | Add a new app. | N/A | | POST /apps/\{app-slug\}/register-ssh-key | Add an SSH key to a specific app. | Owner or Admin | | POST /apps/\{app-slug\}/finish | Save the application at the end of the application add process. | N/A | | POST /apps/\{app-slug\}/bitrise.yml | Upload a new bitrise.yml for your application. | Owner or Admin | :::note[Apps with HTTPS Git URLs] The procedure and the examples are aimed at adding a private app with an SSH git URL. If you want to add an app with an HTTPS git URL, you can skip adding an SSH key. ::: 1. Register the app by calling the `register` endpoint and setting all required parameters. You need to set your git provider, the repository URL, and the slug of the repository as it appears at the provider. You also need to add the slug of the Workspace that will own the app: due to legacy naming conventions, you need the `organization_slug` parameter. ```yaml curl -X POST -H 'Authorization: ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/register' -d \ '{ "provider": "github", "is_public": false, "organization_slug": "$ORG_SLUG" "repo_url": "git@github.com:api_demo/example-repository.git", "type": "git", "git_repo_slug": "example-repository", "git_owner": "api_demo" }' ``` :::tip[Changing the name of your app] By default, when you register an app, it will inherit the name of your git repository. If you would like to add the app with a different name, you can append the "title" parameter to your POST request using the following syntax: ```yaml curl -X POST -H 'Authorization: ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/register' -d \ '{ ... ... "title": "string" }' ``` You can also change the name of your app after creating it, by sending a PATCH request and calling the `apps` endpoint. For more information, see [Managing an existing app](/bitrise-ci/api/adding-and-managing-apps#managing-an-existing-app). ::: 1. Once done, call the `register-ssh-key` endpoint to set up the SSH keys you created so that Bitrise can clone your repository when running a build. You need to provide both your private and public SSH key. Please note that if you wish to copy the private key manually, you need to escape all the line breaks with `\n`. You can also set whether you want to automatically register the public key at your git provider: set the `is_register_key_into_provider_service` parameter to either true or false. ```yaml curl -X POST -H 'Authorization: ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/register-ssh-key' -d \ '{ "auth_ssh_private_key": "your-private-ssh-key", "auth_ssh_public_key": "your-public-ssh-key", "is_register_key_into_provider_service": false }' ``` 1. Finish the app registration process by calling the `finish` endpoint. This endpoint allows you to configure your apps: set the project type, the stack on which the build will run (this may vary based on your app), and the initial configuration settings. You can also set Environment Variables, as well as immediately specify a Workspace that will be the owner of the application. Please note that the `mode` parameter must be set to the value of `manual`. ```yaml curl -X POST -H 'Authorization: ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/finish' -d \ '{ "project_type": "ios", "stack_id": "osx-xcode-13.2.x", "config": "default-ios-config", "mode": "manual", "envs": { "env1": "val1", "env2": "val2" }, "organization_slug": "e1ec3dea540bcf21" }' ``` ### Managing an existing app | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | GET /apps | Get list of your apps. | Any | | GET /apps/\{app-slug\} | Get a specific app. | Any | | GET /apps/\{app-slug\}/bitrise.yml | Get the bitrise.yml of a specific app. | Owner or Admin | | GET /apps/\{app-slug\}/branches | List the branches of an app’s repository. | Any | | GET /organizations/\{org-slug\}/apps | Get list of the apps for a Workspace. | Any | | GET /users/\{user-slug\}/apps | Get list of the apps for a user. | Any | | PATCH /apps/\{app-slug\} | Update an existing app's parameters | Owner or Admin | The response to any GET request regarding one or more apps will contain the app slug, its project type, the git provider, the repository’s owner and URL: ```json { "data": [ { "slug": "eeeeefffff00000", "title": "sample-app", "project_type": "android", "provider": "github", "repo_owner": "example-user", "repo_url": "git@github.com:example-user/sample-app.git", "repo_slug": "android-gradle-kotlin-dsl", "is_disabled": false, "status": -1, "is_public": false, "owner": { "account_type": "organization", "name": "Test Org", "slug": "fffffeeeee00000" }, "avatar_url": null }, { ``` You can also download the existing bitrise.yml file of any app: the response will contain the full YAML configuration. Would you like to change the title or the default git branch of an existing app? You can update an existing app's parameters by calling the PATCH method of the `apps` endpoint. :::important[Required role] You must have an admin or owner role on the app's team to update an existing app's parameters using the Bitrise API. For a complete list of user roles and role cheatsheets, check [User roles on app teams](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: The required parameter is: - slug The optional parameters are: - apple_api_credential_slug: The new Apple API key's slug (recommendation: use the UI to set this) - apple_credential_user_id: The new apple credential user ID (recommendation: use the UI to set this) - apple_credential_user_slug: The new apple credential user slug (recommendation: use the UI to set this) - default_branch: The new default branch for the application. - is_public: The new the value if the application should be publicly visible. - repository_url: The new repository URL for the application. - services_credential_user_id: The new service credential user ID (recommendation: use the UI to set this). - title: The new title of the application. **Changing the name and the default branch of an existing app** Request: ```bash curl -X 'PATCH' 'https://api.bitrise.io/v0.1/apps/THE-APP-SLUG' -H 'accept: application/json' -H 'Authorization: ACCESS-TOKEN' -H 'Content-Type: application/json' -d '{"default_branch": "main", "title": "Example_app_title_3"}' ``` ### Managing app access roles for Workspace groups You can grant [Workspace groups](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups#creating-groups-for-workspaces) access to application teams on Bitrise. It means that all members of the group will be able to work on the app in [the role assigned to the group](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). List all groups that have been granted a given role on an app's team by using the `GET /apps/{app-slug}/roles/{role-name}` endpoint. The role-name parameter takes the following values: - `owner` - `admin` - `manager` - `member` - `release_manager` - `platform_engineer` In this example, we're querying a list of Workspace groups that have been granted Admin role to a specific app: ```bash curl -X 'GET' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/roles/admin' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' ``` Grant access to existing Workspace groups by using the `PUT /apps/{app-slug}/roles/{role-name}` endpoint. This endpoint requires a `groups` object that contains the slugs of all the groups that are granted access with the specified role. :::important[Specify all groups] This endpoint replaces all previous groups that had the specified role on the app's team. If, for example, you call the endpoint to grant the groups Alpha and Beta the Admin role on the app's team, only Alpha and Beta will have Admin access to the app afterwards. If another group - let's call it Delta - previously had Admin role on the team, it will be removed. ::: :::tip[Getting the group slugs] To get the group slugs of your Workspace, use the `[GET /organizations/{org-slug}/groups](https://api-docs.bitrise.io/#/organizations/organzation-groups-list)` endpoint. ::: In the following example, we'll be granting several groups Admin access: ```bash curl -X 'PUT' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/roles/admin' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "groups": [ "GROUP-SLUG-1", "GROUP-SLUG-2" ] }' ``` ### Deleting an app using the API :::warning[Deletion is final] Be aware that you cannot undo deleting an app. Once you delete it, there is no way to recover the app. ::: You can delete apps with the Bitrise API. The only required parameter is the app slug of the app you want to delete: ```bash curl -X DELETE -H 'Authorization: ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/THE-APP-SLUG' ``` ### Uploading a new bitrise.yml file :::note[Required role] You must have an admin or owner role on the app's team to upload a new `bitrise.yml` file. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: The bitrise.yml file contains the configuration of your builds. You can modify the current one via the API by posting a full YAML configuration. In the below example, we are: - Creating a `bitrise.yml` with format version 11. - Setting the Bitrise Step Library as the default Step source. - Setting the stack to Xcode 14. - Setting the BITRISE_PROJECT_PATH Environment Variable to point to the `build.gradle` file. - Adding a **Script** Step. - Creating a trigger map that triggers the primary Workflow if code is pushed to any branch of the app's repository. ```bash curl --fail -X POST -H "Authorization: $ACCESS_TOKEN" "https://api.bitrise.io/v0.1/apps/$APP_SLUG/bitrise.yml" -d \ '{ "app_config_datastore_yaml": { "format_version": 11, "default_step_lib_source": "https://github.com/bitrise-io/bitrise-steplib.git", "meta": { "bitrise.io": { "stack": "osx-xcode-14.0.x" } }, "app": { "envs": [ { "BITRISE_PROJECT_PATH": "build.gradle", "opts": { "is_expand": false } } ] }, "workflows": { "primary": { "steps": [ { "script@1": {} } ] } }, "trigger_map": [ { "push_branch": "*", "workflow": "primary" } ] } }' ``` By calling this endpoint, you replace the app’s current `bitrise.yml` file. You can, of course, modify this uploaded `bitrise.yml` either via the API or on the website itself. ### Changing the location of the app's bitrise.yml file The app's `bitrise.yml` configuration file can be stored in two places: - On bitrise.io. This is the default setting for all apps. - [In your app's repository.](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository) This way you have full control over the versioning and maintenance of the config file. You can still use the graphical Workflow Editor on bitrise.io to modify your configuration but you will need to commit your changes to the repository. You can get and change the location of the file using the API. :::important[Admin access required] Both endpoints related to the location of the `bitrise.yml` file require admin level access to the app. ::: With the `GET/apps/{app-slug}/bitrise.yml/config` endpoint, you can get the location of the file. Location here means that calling the endpoint tells you whether the file is stored on bitrise.io or in the repository. The endpoint takes no parameters and it returns one of two values in the response: - `"location": "bitrise.io"` - `"location": "repository"` ```bash curl -X 'GET' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/bitrise.yml/config' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' ``` With the `PUT/apps/{app-slug}/bitrise.yml/config` endpoint, you can change the location of the file: that is, you can tell Bitrise whether to look for the config file on bitrise.io or in your repository. This endpoint takes one of two values in a JSON object: - `"location": "bitrise.io"` to store the config file on bitrise.io. - `"location": "repository"` to store the config file in your repository. :::important[Commit the config file into your repository] Please note that changing the location to `repository` merely tells Bitrise to look for the `bitrise.yml` file in the app's repository. If the file does not exist in the repository, the endpoint won't return an error but you won't be able to run builds because Bitrise won't find the config file. ::: ```bash curl -X 'PUT' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/bitrise.yml/config' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "location": "bitrise.io" }' ``` ### Changing machine types in all apps at the same time | Endpoints | Function | Required role | | --- | --- | --- | | PATCH /users/\{user-slug\}/apps/machine_types | Migrate a specified machine type to another in all apps owned by the same user. | N/A | | PATCH /organizations/\{org-slug\}/apps/machine_types | Migrate a specified machine type to another in all apps owned by the same Workspace. | Workspace owner | The Bitrise API provides two endpoints that allow you to switch between one [machine type](/bitrise-platform/infrastructure/build-machines/about-build-machines) and another for all apps owned by either a user or a [Workspace](/bitrise-platform/workspaces/workspaces-overview). The endpoints parse the `bitrise.yml` file of each app, look for all occurrences of a specified machine type, and replace them with another type. For example, you can switch from M1 Medium to M1 Large on all your apps with this endpoint. Both endpoints take two parameters: - from_machine: The machine type you want to switch from. - to_machine: The machine type you want to switch to. You can find the list of available machine types here: [Build machine types](/bitrise-build-hub/infrastructure/build-machine-types). If the endpoints don't find the machine type specified in the from_machine parameter, they will still return a 200 response, with an empty `migrated_apps` object. :::note[Default and Workflow-specific stacks] The endpoints can change the machine types for both default stacks and Workflow-specific stacks. ::: **Migrating all apps owned by a user from M1 Medium machines to M1 Large machines:** ```bash curl -X 'PATCH' \ 'https://api.bitrise.io/v0.1/users/USER-SLUG/apps/machine_types' \ -H 'accept: application/json' \ -H 'Authorization: PERSONAL-ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "from_machine": "g2-m1.4core", "to_machine": "g2-m1.8core" }' ``` **Migrating all apps owned by a Workspace from M4 Pro Large machines to M4 Pro X Large machines:** ```bash curl -X 'PATCH' \ 'https://api.bitrise.io/v0.1/organizations/WORKSPACE-SLUG/apps/machine_types' \ -H 'accept: application/json' \ -H 'Authorization: PERSONAL-ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "from_machine": "g2.mac.4large", "to_machine": "g2.mac.4x-large" }' ``` **Successful respose** ```json { "message": "The migration was successful.", "migrated_apps": [ "android-sample (8f41200-e5a5eee17)", "sample-swift-project (c291b04-784ca8773)", ] } ``` ### Managing app notifications You can change [the email notification settings](/bitrise-ci/configure-builds/configuring-build-settings/configuring-email-notifications#changing-your-email-notification-settings) of your apps via an API call at any time with the `PATCH/apps/{app-slug}/update-email-notifications` endpoint. The endpoint takes two parameters: - on_failure: Email notification settings for failed builds. - on_success: Email notification settings for successful builds. Both parameters take three possible values: - `always`: Always send notification. - `never`: Never send notification. The default value for both failed and successful builds. - `change`: Send notification only when the [build status](/bitrise-ci/run-and-analyze-builds/build-statuses) changes compared to the previous build on the same branch. For example, if you wish to receive a notification for a failed build only when the previous build was successful, you need to set the value of the on_failure parameter to `change` (replace the APP-SLUG in the example with your app's slug and ACCESS-TOKEN with your [personal access token](/bitrise-platform/accounts/personal-access-tokens)): ```bash curl -X 'PATCH' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/update-email-notifications' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "on_failure": "change", }' ``` --- ## API overview The Bitrise API allows you to build deep, custom integrations with your preferred tools and processes to create even more efficient development pipelines. The API provides you with control of - and access to - the features and data available through the Bitrise website and CLI. By using the API, you gain the ability to fully customize Bitrise’s functionality to fit your process. :::note[The API is work-in-progress] The API is work-in-progress: we will add new endpoints and possibly update the existing ones in the future. You can track the progress of the API: [join the discussion](https://discuss.bitrise.io/t/bitrise-api-v0-1-work-in-progress/1554)! Follow it and get notified about new endpoints and changes, we announce those there. ::: Feel free to contribute! If you want to request a new API feature or a new endpoint, [you can do so!](http://discuss.bitrise.io/t/bitrise-public-api/37) The Bitrise API’s host is: [https://api.bitrise.io/](https://api.bitrise.io/) Every endpoint except the root one is versioned. The version has to be included in the URL right after the host: for example, [https://api.bitrise.io/v0.1/me](https://api.bitrise.io/v0.1/me) is the endpoint for your own user account. Right now we have only one version, `v0.1`. There’s no long term compatibility promise for `v0.1`, although we try to do our best to not to break anything unless we have to. Once we’re happy with `v0.1` we’ll “freeze” it as `v1.0`, for which we’ll provide long term support. --- ## Authenticating with the Bitrise API The current API supports two types of authentication: - User-generated **personal access tokens**. - Workspace API tokens. Every API endpoint requires authentication, except the “root” URL ([https://api.bitrise.io](https://api.bitrise.io)). 1. Create either a [personal access token](/bitrise-platform/accounts/personal-access-tokens#creating-a-personal-access-token) or [a Workspace API token](/bitrise-platform/workspaces/workspace-api-token#creating-a-workspace-api-token). 1. Save it in a secure way. 1. Add an `Authorization` header with the access token to your API calls. For example, the following call retrieves a list of apps you or your Workspace has access to: ```yaml curl -X 'GET' \ 'https://api.bitrise.io/v0.1/apps' \ -H 'Authorization: ' -H 'accept: application/json' ``` --- ## GitHub app configuration API After you successfully [installed a Bitrise GitHub app](/bitrise-platform/repository-access/github-app-integration#installing-the-github-app-integration), you can use it as your default Git connection method. Configure the [Bitrise GitHub app integration](/bitrise-platform/repository-access/github-app-integration) via the API: - Change the connection type from [OAuth](/bitrise-platform/repository-access/repository-access-with-oauth) to the GitHub app. - Enable the [full permissions](/bitrise-platform/repository-access/github-app-integration#extending-github-app-permissions-to-the-builds) defined for the GitHub app. - Set additional [linked repositories](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app). - Remove the service credential user and other authorization methods as they aren't required for the GitHub app. ### Changing the connection type from OAuth to the GitHub app :::important[Important considerations] Reverting to OAuth via API is not fully supported. Reverting projects to OAuth requires manual intervention through the Bitrise UI. Customers should test the migration process with a subset of projects before executing bulk migrations. ::: Change your GitHub connection from an OAuth application to the Bitrise Github app through the API via the `POST /apps/{app-slug}/change-connection-type` endpoint. The accepted values are: - `github` - `github-app` To change the connection type to the GitHub app: ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/change-connection-type' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "connection_type": "github-app" }' ``` Changing a connection is a non-destructive action: other authentication methods aren't removed. You can check if your builds still work. If there is an issue, you can change back to an OAuth connection. To revert the connection: ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/change-connection-type' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "connection_type": "github" }' ``` ### Extending GitHub app permissions to builds The Bitrise GitHub App generates a short-term, temporary token for each build that is triggered via the app. This token has only one permission by default: contents:read. This means the build can access the GitHub repository but can't do anything else. You can extend these permissions so that you can perform other operations during a build. For example, this can enable users to push Git tags from their builds, create custom status reports, put a label on a pull request, or push a new version number. Use the `use_full_permission` parameter of the `PUT /apps/APP-SLUG/github-app-connection-configuration` endpoint to extend permissions: ```bash curl -X 'PUT' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/github-app-connection-configuration' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "use_full_permission_set": true }' ``` :::tip[More information] Read more about extending permissions and how to do it on the GUI: [Extending GitHub App permissions to the builds](/bitrise-platform/repository-access/github-app-integration#extending-github-app-permissions-to-the-builds). ::: ### Setting additional linked repositories A linked repository is a repository that a Bitrise project can access using a GitHub app installation but it's not the project's primary repository. When an additional repository is linked to your Bitrise GitHub app installation, the tokens generated for the build can access the additional repository. Read more about additional linked repositories: [Additional linked repositories](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app). Use the `POST /apps/APP-SLUG/github-app-connection-configuration/update-linked-repositories` to link an additional repository. You have two choices: - Manually listing the full names of the repository. ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/github-app-connection-configuration/update-linked-repositories' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "repositories": ["org1/repo1", "org1/repo2"] }' ``` - Set the `unlimited_repo_access` field to true to let the builds access all the current and future repositories. ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/github-app-connection-configuration/update-linked-repositories' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "unlimited_repo_access": true }' ``` ### Removing the OAuth connection If your GitHub app connection works, you can remove the components of the OAuth connection. This includes: - Removing the [service credential user](/bitrise-platform/integrations/the-service-credential-user). - Removing either the SSH key or the HTTP token. #### Removing the service credential user To remove the service credential user: ```bash curl -X 'DELETE' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/service-credential-user' \ -H 'Authorization: ACCESS-TOKEN' ``` #### Removing SSH or HTTP authorization To remove previous authorization methods: ```bash curl -X 'DELETE' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/repository-authorization ' \ -H 'Authorization: ACCESS-TOKEN' ``` --- ## Identifying Workspaces and apps with their slugs The API (and the Bitrise support team) often asks for slugs: a Workspace slug or a project slug. A slug is a unique identifier of one of these resources, consisting of hexadecimal numbers. You can find the slugs of a given Workspace or project both on the UI and in the API. ### Finding a slug on the Bitrise website You can find both Workspace slugs and project slugs on the Bitrise website. **Workspace slugs** 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the **Workspace settings** page, select `**General settings** from the left navigation menu. 1. Find the Workspace slug in the **Workspace information** section. You can copy the slug by clicking the copy button next to it. ![workspace-slug.png](/img/_paligo/uuid-c82d552a-8d31-148f-82e4-bb4ec929c183.png) **Project slugs** 1. Open [Bitrise CI](https://app.bitrise.io/ci) and select your project. 1. Once on the project's page, go to your browser's address bar. The URL will look like this: `https://app.bitrise.io/app/5c89d92-8be6-4892-b11d-efbc1fdd607`. 1. Find the hexadecimal number after the `/app/` section of the URL. That is your project's slug. ### Finding a slug with the Bitrise API You can get the slug for all Workspaces and apps you have access to with simple API calls. **Workspace slugs** 1. [Authenticate](/bitrise-ci/api/authenticating-with-the-bitrise-api) with the Bitrise API. 1. Call the `GET /organizations` endpoint with your Personal Access Token: ```yaml curl -X 'GET' \ 'https://api.bitrise.io/v0.1/organizations' \ -H 'accept: application/json' \ -H 'Authorization: ' ``` 1. Find the slug in the response: ```json { "data": [ { "name": "TestOrg", "slug": "2dec5c71bbce73d9", "avatar_icon_url": "https://bitrise-public-content-production.s3.amazonaws.com/org-icons/default_avatar-09.png", "concurrency_count": null, "owners": [ { "slug": "1b3f130835b1c09ef2", "username": "bitbot", "email": "bit.bot@bitrise.io" } ] } ] } ``` **App slugs** 1. [Authenticate](/bitrise-ci/api/authenticating-with-the-bitrise-api) with the Bitrise API. 1. Call the `GET /apps` endpoint with your Personal Access Token. ```yaml curl -X 'GET' \ 'https://api.bitrise.io/v0.1/apps' \ -H 'accept: application/json' \ -H 'Authorization: ' ``` 1. Find the slug in the response: ```json { "data": [ { "slug": "13aa9897-3891-4fe7-8cf5-5b2f75638b0e", "title": "TestApp", "project_type": "ios", "provider": "github", "repo_owner": "bitrise", "repo_url": "git@github.com:bitrise/TestApp.git", "repo_slug": "TestApp", "is_disabled": false, "status": 1, "is_public": false, "is_github_checks_enabled": false, "owner": { "account_type": "organization", "name": "Bitrise", "slug": "03a9543ede4d12bd" }, "avatar_url": null }, ``` --- ## Incoming and outgoing webhooks Both incoming and outgoing webhooks can be set up with the Bitrise API. They are important for automatic build triggering and the reporting of build events to other services. | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | POST /apps/\{app-slug\}/register-webhook | Register an incoming webhook for a specific application. | Owner or Admin | | GET /apps/\{app-slug\}/outgoing-webhooks | List the outgoing webhooks of an app. | Owner or Admin | | POST /apps/\{app-slug\}/outgoing-webhooks | Create an outgoing webhook for an app. | Owner or Admin | | PUT /apps/\{app-slug\}/outgoing-webhooks/\{app-webhook-slug\} | Update an outgoing webhook of an app. | Owner or Admin | | DELETE /apps/\{app-slug\}/outgoing-webhooks/\{app-webhook-slug\} | Delete an outgoing webhook of an app. | Owner or Admin | ### Registering an incoming webhook with the API Incoming webhooks enable users to set up automatic triggers for their apps on Bitrise: for example, a Bitrise webhook registered on GitHub can automatically trigger a build when code is pushed to the GitHub repository. :::note[Required role] You must have an admin or owner role on the app's team to manage incoming or outgoing webhooks using the API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: To set up a webhook, you must [connect your Bitrise account to your Git provider account](/bitrise-platform/repository-access/repository-access-with-oauth): this allows Bitrise to register the webhook automatically. Register a webhook by calling the `register-webhook` endpoint with an existing app slug: ```bash curl -X POST -H 'Authorization: ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/register-webhook' ``` This will register a webhook to the Git provider of the app. Afterwards, you can set up [automatic triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) either on the website or via the Trigger Map in the app’s `bitrise.yml` file. ### Creating outgoing webhooks with the API Outgoing webhooks enable integration with other services: specifically, they are used to notify other services. Currently, only build event notifications are supported. There are two supported build events: triggering a build and finishing a build. :::note[Build status reports] Notifying your Git provider about the build status does not require outgoing webhooks. ::: To set up an outgoing webhook for an application, you need to specify the app itself and at least two of the creation parameters: - The webhook URL: you can get this from the service you want to integrate with Bitrise. - The events that trigger the webhook. Currently, this takes three possible values: `all`, `build`, and `pipeline`. :::note[Required role] You must have an admin or owner role on the app's team to manage incoming or outgoing webhooks using the API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: You can also set up custom headers by specifying a key/value pair in the request. **A new outgoing webhook with the URL 'example.webhook.com'** Request: ```bash curl -X POST "https://api.bitrise.io/v0.1/apps/APP-SLUG/outgoing-webhooks" -H "accept: application/json" -H "Authorization: ACCESS-TOKEN" -H "Content-Type: application/json" -d "{ \"events\": [ \"build\" ], \"url\": \"example.webhook.com\", \"headers\": { \"KEY\": \"value\" }}" ``` Response: ```json { "slug": "01D72ARNH4KR7KMW3DG3NBKXRK", "url": "example.webhook.com", "events": [ "build" ], "headers": { "KEY": "value" }, "registered_by_addon":false, "created_at": "2019-03-28T14:20:22.436825Z", "updated_at": "2019-03-28T14:20:22.436825Z" } ``` ### Modifying and deleting outgoing webhooks with the API To modify an existing webhook, you need to specify all the mandatory parameters in your request. In other words, even if you only want to change the URL, the request still has to contain a valid value for the `events` parameter. :::note[Required role] You must have an admin or owner role on the app's team to manage incoming or outgoing webhooks using the API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: **Modifying an outgoing webhook** Request: ```bash curl -X PUT "https://api.bitrise.io/v0.1/apps/APP-SLUG/outgoing-webhooks/WEBHOOK-SLUG" -H "accept: application/json" -H "Authorization: ACCESS-TOKEN" -H "Content-Type: application/json" -d" { \"events\": [ \"all\" ], \"headers\": { \"Modified\": \"1212\" }, \"url\": \"example2.webhook.com\"}" ``` Response: ```json { "data": { "slug": "WEBHOOK-SLUG", "url": "example2.webhook.com", "events": [ "all" ], "headers": { "Modified": "1212" }, "registered_by_addon": false, "created_at": "2019-03-28T14:20:22.436825Z", "updated_at": "2019-03-28T14:20:22.436825Z" } } ``` To delete an outgoing webhook, all you need to do is provide the app slug and the webhook slug in your request: ```bash curl -X DELETE "https://api.bitrise.io/v0.1/apps/APP-SLUG/outgoing-webhooks/WEBHOOK-SLUG" -H "accept: application/json" -H "Authorization: ACCESS-TOKEN" ``` --- ## Managing an app's builds You can use the Bitrise API to list an app's build, get all information about a specific build, view the build logs, and view archived builds that are older than 200 days. | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | GET /apps/\{app-slug\}/archived-builds | List archived builds of a specified app. | Tester/QA | | GET /apps/\{app-slug\}/build-workflows | List the workflows that were triggered at any time for a specified app. | Tester/QA | | GET /apps/\{app-slug\}/builds | List all the builds of a specified app. | Tester/QA | | GET /apps/\{app-slug\}/builds/\{build-slug\} | Get the specified build of a given app. | Tester/QA | | GET /apps/\{app-slug\}/builds/\{build-slug\}/bitrise.yml | Get the `bitrise.yml` file of one of the builds of a specified app. | Developer | | GET /apps/\{app-slug\}/builds/\{build-slug\}/log | Get the build log of a specified build of an app. | Developer | | GET /builds | List all the Bitrise builds that can be accessed with the authenticated account. | N/A | ### Viewing the build data of an app You can access all relevant build information with the help of the API. You can get all builds of an app with the `GET /apps/{app-slug}/builds` endpoint. You can set additional parameters, such as the Workflow that was used for the build, to act as filters. Set parameters in the following format: ```text GET /apps/{app-slug}/builds?parameter_name=parameter_value&other_parameter_name=other_parameter_value ``` The full list of parameters can be found in the [API reference](/bitrise-api/api-reference/bitrise-api) documentation. :::note[Build retention for 200 days] On the **Builds** page of your app, we only show builds from the last 200 days. The same limit applies if you are [searching for specific builds](/bitrise-ci/run-and-analyze-builds/finding-a-specific-build) on the page. This limitation also applies to most API calls: the `GET/apps/{app-slug}/builds` endpoint and related endpoints can only return builds from the last 200 days. However, there are two methods to get a build that is older than 200 days: - If you know the exact build URL, you can access the build. - You can use the `GET/apps/{app-slug}/archived-builds` API endpoint: [Listing the archived builds of an app](/bitrise-ci/api/managing-an-app-s-builds#listing-the-archived-builds-of-an-app). ::: **Listing builds that built the `development` branch with the primary Workflow** Request: ```bash curl -X GET 'https://api.bitrise.io/v0.1/apps/$APP-SLUG/builds?branch=development&workflow=primary' -H 'accept: application/json' -H 'Authorization: $ACCESS_TOKEN' ``` Response (in this example, the response shows only a single build): ```json { "data": [ { "triggered_at": "2022-07-18T13:12:35Z", "started_on_worker_at": null, "environment_prepare_finished_at": null, "finished_at": "2022-07-18T13:12:47Z", "slug": "294e02x8-554c-44f8-84a5-59867a66df83", "status": 3, "status_text": "aborted", "abort_reason": "User X requested to abort this build.", "is_on_hold": false, "is_processed": true, "is_status_sent": false, "branch": "development", "build_number": 8, "commit_hash": null, "commit_message": null, "tag": null, "triggered_workflow": "primary", "triggered_by": null, "machine_type_id": "g2.4core", "stack_identifier": "osx-xcode-13.3.x", "original_build_params": { "branch": "development" }, "pipeline_workflow_id": null, "pull_request_id": 0, "pull_request_target_branch": null, "pull_request_view_url": null, "commit_view_url": null, "credit_cost": null } ], "paging": { "total_item_count": 1, "page_item_limit": 50 } } ``` To get the same data for a specific build, call `GET /apps/{app-slug}/builds/{build-slug}`. You can also view the `bitrise.yml` file of the build by adding `/bitrise.yml` to the end of the URL. **Listing failed builds using the status integer** You can use the status integer to filter your builds based on build statuses. The status integers are: - 0 - Not finished (these are builds that are either starting, running, or on hold) - 1 - Successful - 2 - Failed - 3 - Aborted with failure - 4 - Aborted with success Request: ```bash curl -X GET 'https://api.bitrise.io/v0.1/apps/$APP-SLUG/builds?branch=development&status=2' -H 'accept: application/json' -H 'Authorization: $ACCESS_TOKEN' ``` Response (in this example there were two failed builds): ```json { "data": [ { "triggered_at": "2022-08-01T09:20:11Z", "started_on_worker_at": "2022-08-01T09:20:15Z", "environment_prepare_finished_at": "2022-08-01T09:20:15Z", "finished_at": "2022-08-01T09:21:32Z", "slug": "104d4527-f6a0-4362-b595-77349ccc1264", "status": 2, "status_text": "error", "abort_reason": null, "is_on_hold": false, "is_processed": true, "is_status_sent": false, "branch": "main", "build_number": 26, "commit_hash": null, "commit_message": null, "tag": null, "triggered_workflow": "Appetize.io", "triggered_by": "manual-danicsorba", "machine_type_id": "g2.4core", "stack_identifier": "osx-xcode-13.2.x", "original_build_params": { "branch": "main", "workflow_id": "Appetize.io" }, "pipeline_workflow_id": null, "pull_request_id": 0, "pull_request_target_branch": null, "pull_request_view_url": null, "commit_view_url": null, "credit_cost": 4 }, { "triggered_at": "2022-04-27T10:25:47Z", "started_on_worker_at": "2022-04-27T10:26:24Z", "environment_prepare_finished_at": "2022-04-27T10:26:24Z", "finished_at": "2022-04-27T10:27:16Z", "slug": "b8599c39-201d-4cc9-8ef5-f28b75b7d910", "status": 2, "status_text": "error", "abort_reason": null, "is_on_hold": false, "is_processed": true, "is_status_sent": false, "branch": "main", "build_number": 25, "commit_hash": null, "commit_message": null, "tag": null, "triggered_workflow": "Appetize.io", "triggered_by": "manual-danicsorba", "machine_type_id": "g2.4core", "stack_identifier": "osx-xcode-13.2.x", "original_build_params": { "branch": "main", "workflow_id": "Appetize.io" }, "pipeline_workflow_id": null, "pull_request_id": 0, "pull_request_target_branch": null, "pull_request_view_url": null, "commit_view_url": null, "credit_cost": 2 } ], "paging": { "total_item_count": 2, "page_item_limit": 50 } } ``` You can try any of these endpoints in the [API reference](/bitrise-api/api-reference/bitrise-api) documentation. ### Listing the archived builds of an app By default, you can only view builds that aren't older than 200 days. This is true for most API endpoints, too. However, you can also view older, archived builds by calling the `GET /apps/{app-slug}/archived-builds` endpoint. The endpoint has two required parameters: - after - before Both parameters are dates represented using Unix timestamps and both are required! In other words, you have to specify the exact time period in which you want to see your archived builds. **Listing all archived builds between 2021-01-01 and 2022-01-01** ```bash curl -X 'GET' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/archived-builds?after=1609459200&before=1640995200' \ -H 'accept: application/json' \ -H 'Authorization: THE_ACCESS_TOKEN' ``` --- ## Managing Android keystore files This guide describes how to manage your Android keystore files with the Bitrise API. If you’d like to learn more about how to do the same on the UI, please check out [Android code signing](/bitrise-ci/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step). | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | GET/apps/\{app-slug\}/android-keystore-files | Get a list of Android keystore files | Owner or Admin | | POST/apps/\{app-slug\}/android-keystore-files | Create an Android keystore file | Owner or Admin | | DELETE/apps/\{app-slug\}/android-keystore-files/\{android-keystore-file-slug\} | Delete an Android keystore file | Owner or Admin | ### Listing the Android keystore files of an app :::important[Required role] You must have an admin or owner role on the app's team to manage Android keystore files using the Bitrise API. For a complete list of user roles and role cheatsheets, check [User roles on app teams](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: Retrieve a list of the Android keystore files of an app with the GET method of the `android-keystore-files` endpoint. The returned data includes, among other things, the names of the files, their size, as well as their current status. The required parameter is: - app slug Optional parameters are: - next: slug of the first file in the response (as a string) - limit: max number of elements per page (as an integer) where the default is 50. **Getting all Android keystore files of an app** Request: ```bash curl -X GET -H  'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/android-keystore-files' ``` Response: ```json { "data": [ { "upload_file_name": "simplesample.jks", "upload_file_size": 2062, "slug": "01GDFZW5DZED3DQD4VK835FKTP", "processed": true, "is_expose": true, "is_protected": false, "user_env_key": "ANDROID_KEYSTORE", "exposed_meta_datastore": { "PASSWORD": "", "ALIAS": "", "PRIVATE_KEY_PASSWORD": "" } } ], "paging": { "total_item_count": 1, "page_item_limit": 50 } ``` ### Creating and uploading Android keystore files :::important[Required role] You must have an admin or owner role on the app's team to manage Android keystore files using the Bitrise API. For a complete list of user roles and role cheatsheets, check [User roles on app teams](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: To add an Android keystore file to your app using the API, you will need to: 1. Call the POST method of the `android-keystore-files` endpoint with the `upload_file_name` and `upload_file_size` parameters. 1. Upload the file to AWS using the `upload_url parameter` from the response. 1. Confirm the file upload with a POST call of the `uploaded` endpoint. This sets the processed flag of the file to `true`. This flag can't be changed again afterwards! The create call also accepts these optional parameters, to store the keystore's credentials alongside the file: - password: The keystore's password. - alias: The alias of the key you want to use. - private_key_password: The password of the key. - keystore_file_name: The keystore's file name. Required if the app already has another keystore file. **Creating and uploading a new Android keystore file** Creating the file: ```bash curl -X POST -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/android-keystore-files' -d '{"upload_file_name":"simplesample.jks","upload_file_size":2062,"password":"KEYSTORE-PASSWORD","alias":"KEY-ALIAS","private_key_password":"KEY-PASSWORD","keystore_file_name":"simplesample.jks"}' ``` Response: ```json { "data": { "upload_file_name": "simplesample.jks", "upload_file_size": 2062, "slug": "01GDFYTF2DXZZSWGMCF0ZTVSB9", "processed": false, "is_expose": true, "is_protected": false, "upload_url": "https://concrete-userfiles-production.s3.us-west-2.amazonaws.com/project_file_storage_documents/uploads/129261/original/simplesample.jks?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIV2YZWMVCNWNR2HA%2F20220921%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20220921T120206Z&X-Amz-Expires=600&X-Amz-SignedHeaders=content-length%3Bhost&X-Amz-Signature=ce3c66fa144ba6ca9478cff3b72c49e024779f64ba961ddfc84060f65ea92562", "user_env_key": "ANDROID_KEYSTORE", "exposed_meta_datastore": { "PASSWORD": "", "ALIAS": "", "PRIVATE_KEY_PASSWORD": "" } } } ``` The file name, its size, slug, and a pre-signed upload URL are retrieved (along with some attributes that you can modify). This pre-signed upload URL is a temporary link which you will use to upload the Android keystore file to its destination. Uploading the file to AWS using the value of the `upload_url` parameter: ```bash curl -T simplesample.jks 'https://concrete-userfiles-production.s3-us-west-2.amazonaws.com/build_certificates/uploads/30067/original/certs.p12?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAIOC7N256G7J2W2TQ%2F20180216%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20180216T124240Z&X-Amz-Expires=600&X-Amz-SignedHeaders=content-length%3Bhost&X-Amz-Signature=2bf42176650f00405abfd7b7757635c9be16b43e98013abb7f750d3c658be28e' ``` Confirming the upload: ```bash curl -X POST -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/android-keystore-files/ANDROID-KEYSTORE-FILE-SLUG/uploaded' ``` ### Downloading an Android keystore file Uploaded Android keystore files are stored in the General File Storage. You can retrieve them at any time by getting the download URL from the `android-keystore-files` endpoint. To call the endpoint, you need the file slug returned when [uploading the keystore file](/bitrise-ci/api/managing-android-keystore-files#creating-and-uploading-android-keystore-files) and the [app slug](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs). ```bash curl -X GET "https://api.bitrise.io/v0.1/apps/APP-SLUG/android-keystore-files/ANDROID-KEYSTORE-FILE-SLUG" -H "accept: application/json" -H "Authorization: ACCESS-TOKEN" ``` The response will contain a `download_url` property, containing the URL in a string. You can use that URL to download the file itself. :::note[Availability of the `download_url`] Note that the `download_url` is generated only when the file’s `is_protected` attribute is false. ::: --- ## Managing build artifacts If you add the `Deploy to bitrise.io` Step to your Workflow, once the build has run, you can access the build artifacts in the build's **Artifacts** tab on bitrise.io. You can also manage the generated artifacts with the Bitrise API. :::important[IMPORTANT: Artifact retention policy] Artifacts, including [build logs](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/build-logs), [build files](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online), installable artifacts, or [CodePush](/release-management/codepush/about-codepush) packages, are only stored for a limited amount of time. For details, see [Artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy). ::: | Endpoint | Function | Required role on the app's team | | --- | --- | --- | | [GET/apps/\{app-slug\}/builds/\{build-slug\}/artifacts](/bitrise-api/api-reference/bitrise-api) | Listing build artifacts | Any | | [GET/apps/\{app-slug\}/builds/\{build-slug\}/artifacts/\{artifact-slug\}](/bitrise-api/api-reference/bitrise-api) | Retrieving data of a specific build artifact | Any | | [PATCH/apps/\{app-slug\}/builds/\{build-slug\}/artifacts/\{artifact-slug\}](/bitrise-api/api-reference/bitrise-api) | Updating a build artifact | Owner, Admin, or Developer | | [DELETE/apps/\{app-slug\}/builds/\{build-slug\}/artifacts/\{artifact-slug\}](/bitrise-api/api-reference/bitrise-api) | Deleting a build artifact | Owner, Admin, or Developer | ### Listing build artifacts :::note[Required role] You must have a tester/QA, developer, admin, or owner role on the app's team to list build artifacts using the API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: To be able to use build artifact endpoints, you have to first list all artifacts that belong to an app’s build. The response will list all artifacts along with their slug which you will need later. The required parameters are: - app slug - build slug You can use the generated build artifact slug/s from the response output with other build artifact endpoints where the build artifact slug is a required parameter. **Listing the artifacts of an app** Request: ```bash curl -X GET "https://api.bitrise.io/v0.1/apps/87a5991e180d91a9/builds/b234f959745082e0/artifacts" -H "accept: application/json" -H "Authorization: THE-ACCESS-TOKEN" ``` Response: ```json { "data": [ { "title": "another_app-debug.apk", "artifact_type": "android-apk", "is_public_page_enabled": true, "slug": "92e0b6ecae87b832", "file_size_bytes": 1574799 }, { "title": "app-debug.apk", "artifact_type": "android-apk", "is_public_page_enabled": true, "slug": "54ae701761c4f956", "file_size_bytes": 1574793 } ], "paging": { "total_item_count": 2, "page_item_limit": 50 } } ``` ### Retrieving a specific build artifact's data :::note[Required role] You must have a tester/QA, developer, admin, or owner role on the app's team to retrive a specific build's artifact data using the API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: You can retrieve detailed data of a specific build's artifacts with the artifacts endpoint. The response shows the filename, the artifact type, the download URL, and the file size. The required parameters are: - app slug - build slug - artifact slug **Retrieving the data of a specific artifact** Request: ```bash curl -X GET "https://api.bitrise.io/v0.1/apps/87a5991e180d91a9/builds/b234f959745082e0/artifacts/92e0b6ecae87b832" -H "accept: application/json" -H "Authorization: THE-ACCESS-TOKEN" ``` Response: ```json { "data": { "title": "another_app-debug.apk", "artifact_type": "android-apk", "expiring_download_url": "https://bitrise-prod-build-storage.s3.amazonaws.com/builds/b234f959745082e0/artifacts/7626902/another_app-debug.apk?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAIV2YZWMVCNWNR2HA%2F20190426%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190426T131627Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=9f1af26787f34b5cf0cbc18b2372313607b1e3c0203a9ce7e42da884a6ddf70f", "is_public_page_enabled": true, "slug": "92e0b6ecae87b832", "public_install_page_url": "https://www.bitrise.io/artifact/7626902/p/8e5b2c62abe28fecef09b271de767920", "file_size_bytes": 1574799 } } ``` By default, the value of the `is_public_page_enabled` input is set to `true`. This way the `public_install_page_url` becomes available and you can view some basic information about the artifact via this URL. You can also download the artifact using the download URL from the response output. ### Disabling the public install page of an artifact :::note[Required role] You must have a developer, admin, or owner role on the app's team to disable the public install page of an artifact using the API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: You can update the `is_public_page_enabled` parameter of your APK and IPA files. Please note this parameter’s value is set to `true` by default so you can only disable it with this endpoint. The required parameters are: - app slug - build slug - artifact slug **Disabling the public install page for an APK file** Request: ```bash curl -X PATCH "https://api.bitrise.io/v0.1/apps/87a5991e180d91a9/builds/b234f959745082e0/artifacts/54ae701761c4f956" -H "accept: application/json" -H "Authorization: THE-ACCESS-TOKEN" -H "Content-Type: application/json" -d "{ \"is_public_page_enabled\": false}" ``` Response: ```json { "data": { "title": "app-debug.apk", "artifact_type": "android-apk", "expiring_download_url": "https://bitrise-prod-build-storage.s3.amazonaws.com/builds/b234f959745082e0/artifacts/7626904/app-debug.apk?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAIV2YZWMVCNWNR2HA%2F20190503%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190503T082800Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=7251fcbc0574ffac60b3f1d4a8c398658e49f0b86fb3cfec1500bde125738abc", "is_public_page_enabled": false, "slug": "54ae701761c4f956", "public_install_page_url": "", "file_size_bytes": 1574793 } } ``` If you check the build’s `Artifacts` tab, you will see that the `Public install page` toggle is disabled. ### Deleting a build artifact :::note[Required role] You must have a developer, admin, or owner role on the app's team to delete a build artifact using the API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: You can delete an app’s specific build artifact. The required parameters are: - app slug - build slug - artifact slug **Deleting an APK file** Request: ```bash curl -X DELETE "https://api.bitrise.io/v0.1/apps/87a5991e180d91a9/builds/b234f959745082e0/artifacts/54ae701761c4f956" -H "accept: application/json" -H "Authorization: THE-ACCESS-TOKEN" ``` Response: ```json { "data": { "title": "app-debug.apk", "artifact_type": "android-apk", "expiring_download_url": null, "is_public_page_enabled": true, "slug": "54ae701761c4f956", "public_install_page_url": "", "file_size_bytes": 1574793 } } ``` --- ## Managing files in Generic File Storage You can upload, delete, update, and list any project files in the `GENERIC FILE STORAGE` section of Bitrise. | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | [POST/apps/\{app-slug\}/generic-project-files](/bitrise-api/api-reference/bitrise-api) | Create a generic project file | Owner or Admin | | [POST/apps/\{app-slug\}/generic-project-files/\{generic-project-file-slug\}/uploaded](/bitrise-api/api-reference/bitrise-api) | Confirm the upload process | Owner or Admin | | [PATCH/apps/\{app-slug\}/generic-project-files/\{generic-project-file-slug\}](/bitrise-api/api-reference/bitrise-api) | Update an uploaded project file | Owner or Admin | | [GET/apps/\{app-slug\}/generic-project-files](/bitrise-api/api-reference/bitrise-api) | Get a list of the uploaded project files | Owner or Admin | | [GET/apps/\{app-slug\}/generic-project-files/\{generic-project-file-slug\}](/bitrise-api/api-reference/bitrise-api) | Retrieve data of a specific project file | Owner or Admin | | [DELETE/apps/\{app-slug\}/generic-project-files/\{generic-project-file-slug\}](/bitrise-api/api-reference/bitrise-api) | Delete an uploaded project file | Owner or Admin | ### Creating and uploading files to the Generic File Storage :::note[Required role] You must have an admin or owner role on the app's team to manage files in the Generic File Storage using the Bitrise API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: You can add new files to an application and store it in the `GENERIC FILE STORAGE` . When calling the relevant API endpoint, a new temporary pre-signed upload URL is created which you will use to upload the file to the `GENERIC FILE STORAGE`. (Please note that this pre-signed URL is time-limited and expires after 10 minutes.) You'll need to: 1. Call the POST method of the `generic-project-files` endpoint. This call creates a temporary pre-signed upload URL that contains a file slug which you will need later. The required parameters are: - slug: the app slug of the Bitrise app. You can get the slug by opening the app on Bitrise and copying it from the URL of the main page, or by calling the `GET /apps` endpoint and finding your app in the list. - upload_file_name: the name of the file, including the file extension. For example, `MyFile.txt`. The file should be in the same folder where the command is run. - upload_file_size: the size of the file in bytes. On macOS, you can get the file size by running the `stat -f%z ` command. - user_env_key: you can add any name to the user env key. 1. Upload the file to AWS using the pre-signed upload URL. 1. Confirm the file upload with the POST method of the `generic-project-files/GENERIC-PROJECT-FILES-SLUG/uploaded` endpoint, using the slug from the response containing your pre-signed upload URL. This sets the `processed` flag to `true` which means the file is now available on Bitrise. This flag can't be changed again afterwards! **Creating and uploading a file** Creating the temporary pre-signed upload URL: ```bash curl -X POST "https://api.bitrise.io/v0.1/apps//generic-project-files" -H "accept: application/json" -H "Authorization: " -H "Content-Type: application/json" -d "{ \"upload_file_name\": \"Test_File.md\", \"upload_file_size\": 4865, \"user_env_key\": \"Test_File\"}" ``` Response: ```json { "data": { "upload_file_name": "Test_File.md", "upload_file_size": 4865, "slug": "", "processed": false, "is_expose": true, "is_protected": false, "upload_url": "https://concrete-userfiles-production.s3.us-west-2.amazonaws.com/project_file_storage_documents/uploads/24043/original/Test-File?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAIV2YZWMVCNWNR2HA%2F20190402%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20190402T125827Z&X-Amz-Expires=600&X-Amz-SignedHeaders=content-length%3Bhost&X-Amz-Signature=e1557901d5a07b1b3578d9ffdf84a9b0188b742bfff9c8175a3e87f12c7e2c4e", "user_env_key": "Test_File", "exposed_meta_datastore": null } } ``` Uploading the file to AWS: ```bash curl -T Test_File.md "" ``` Confirming the file upload: ```bash curl -X POST -H 'Authorization: ' 'https://api.bitrise.io/v0.1/apps//generic-project-files//uploaded' ``` Response: ```json { "data": { "upload_file_name": "Test_File.md", "upload_file_size": 4865, "slug": "", "processed": true, "is_expose": true, "is_protected": false, "user_env_key": "Test_File", "exposed_meta_datastore": null } } ``` ### Retrieving a specific file's data :::note[Required role] You must have an admin or owner role on the app's team to manage files in the Generic File Storage using the Bitrise API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: Retrieve a specific file’s data from the Generic File Storage with the GET method of the `generic-project-files` endpoint. The returned data includes, among other things, the file's name, size, and download URL, as well as its current status. The required parameters are: - App slug - Generic project file slug **Retrieving a file** Request: ```bash curl -X GET -H 'Authorization: ' 'https://api.bitrise.io/v0.1/apps//generic-project-files/' ``` Response: ```json { "data": { "upload_file_name": "Test_File.md", "upload_file_size": 4865, "slug": "01D7F228E7N8Q8WQJKJM8FV3XM", "processed": true, "is_expose": true, "is_protected": false, "download_url": "https://concrete-userfiles-production.s3.us-west-2.amazonaws.com/project_file_storage_documents/uploads/24043/original/Test-File?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAIV2YZWMVCNWNR2HA%2F20190402%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20190402T132712Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=241be52184b63867262360743931c546c166a99719787ce417e3be11bc12bbed", "user_env_key": "Test_File", "exposed_meta_datastore": null } } ``` :::note[Availability of the `download_url`] Note that the `download_url` is generated only when the file’s `is_protected` attribute is false. ::: ### Listing the uploaded files of a project :::note[Required role] You must have an admin or owner role on the app's team to manage files in the Generic File Storage using the Bitrise API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: Get a list of a project's files that were [uploaded to the Generic File Storage](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy) using the `GET` method. Please note that the **maximum number of files is 50**. The required parameter is: - App slug Optional parameters are: - `next`: slug of the first file in the response (as a string) - `limit`: max number of elements per page (as an integer) **Listing the apps** Request: ```bash curl -X GET -H 'Authorization: ' 'https://api.bitrise.io/v0.1/apps//generic-project-files' ``` Response: ```json { "data": [ { "upload_file_name": "Test_File.md", "upload_file_size": 4865, "slug": "01D7F228E7N8Q8WQJKJM8FV3XM", "processed": true, "is_expose": true, "is_protected": false, "user_env_key": "Test_File", "exposed_meta_datastore": null } ], "paging": { "total_item_count": 2, "page_item_limit": 50 } } ``` As you can see, the example response shows the list of files specific to a project. ### Deleting a file from the Generic File Storage You can delete your uploaded file from the Generic File Storage using the `DELETE` method. :::note[Required role] You must have an admin or owner role on the app's team to manage files in the Generic File Storage using the Bitrise API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: The required parameters are: - App slug - Generic project file slug ```bash curl -X DELETE -H "Authorization:" "https://api.bitrise.io/v0.1/apps//generic-project-files/" ``` --- ## Managing iOS code signing files This guide describes how to manage your iOS code signing files with the Bitrise API. If you’d like to learn more about how to do the same on the UI, please check out [iOS code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). You can upload, update, list, and delete iOS code signing files with the API. In this guide we show you how and in what order to use those code signing endpoints. | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | POST/apps/\{app-slug\}/provisioning-profiles | Create a provisioning file | Owner or Admin | | POST/apps/\{app-slug\}/provisioning-profiles/\{provisioning-profile-slug\}/uploaded | Confirm the upload process | Owner or Admin | | PATCH/apps/\{app-slug\}/provisioning-profiles/\{provisioning-profile-slug\} | Update an uploaded provisioning file | Owner or Admin | | GET/apps/\{app-slug\}/provisioning-profiles | Get a list of the uploaded provisioning files | Owner or Admin | | GET/apps/\{app-slug\}/provisioning-profiles/\{provisioning-profile-slug\} | Retrieve data of a specific provisioning file | Owner or Admin | | DELETE/apps/\{app-slug\}/provisioning-profiles/\{provisioning-profile-slug\} | Delete an uploaded provisioning file | Owner or Admin | | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | POST/apps/\{app-slug\}/build-certificates | Create a build certificate | Owner or Admin | | POST/apps/\{app-slug\}/build-certificates/\{build-certificate-slug\}/uploaded | Confirm the upload process | Owner or Admin | | PATCH/apps/\{app-slug\}/build-certificates/\{build-certificate-slug\} | Update an uploaded build certificate | Owner or Admin | | GET/apps/\{app-slug\}/build-certificates | Get a list of the uploaded build certificate | Owner or Admin | | GET/apps/\{app-slug\}/build-certificates/\{build-certificate-slug\} | Retrieve data of a specific build certificate | Owner or Admin | | DELETE/apps/\{app-slug\}/build-certificates/\{build-certificate-slug\} | Delete an uploaded build certificate | Owner or Admin | ### Uploading an iOS code signing file :::note[Required role] You must have an admin or owner role on the app's team to manage iOS code signing files using the Bitrise API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: You can upload an iOS code signing file (either a .p12 certificate or a provisioning profile) to a Bitrise app of your choice. This process does NOT create a new code signing file: it uploads an existing file (created and downloaded from the Apple Developer Portal) to an AWS URL. It is functionally the same as uploading your code signing files on the Bitrise website: [Managing iOS code signing files - manual provisioning](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---manual-provisioning). To upload an iOS code signing file file via the API: 1. Call the POST method of the `provisioning-profiles` or `build-certificates` endpoint to create a temporary pre-signed upload URL that expires in ten minutes. The call requires an existing code signing file (certificate or provisioning profile) and two parameters: - `upload_file_name`: The filepath to the existing code signing file. For example, `/path/to/sample.p12`. - `upload_file_size`: The size of the file in bytes. ```bash // Calling the endpoint to create the temporary upload URL curl -X POST -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/provisioning-profiles' -d '{"upload_file_name":"sample.provisionprofile","upload_file_size":2047}' ``` ```json // The successful response: you will need the "upload_url" and the "slug". { "data":{ "upload_file_name":"sample.provisionprofile", "upload_file_size":2047, "slug":"01C6FA6P6HRQT5PQ8RMMVVXE6W", "processed":false, "is_expose":true, "is_protected":false, "upload_url":"https://concrete-userfiles-production.s3-us-west-2.amazonaws.com/build_certificates/uploads/30067/original/certs.p12?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAIOC7N256G7J2W2TQ%2F20180216%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20180216T124240Z&X-Amz-Expires=600&X-Amz-SignedHeaders=content-length%3Bhost&X-Amz-Signature=2bf42176650f00405abfd7b7757635c9be16b43e98013abb7f750d3c658be28e" } } ``` 1. The response to the first call contains an `upload_url` parameter. You need to use this and the `upload_file_name` parameter to upload the file to AWS with a `curl` call. ```bash curl -T sample.provisionprofile 'https://concrete-userfiles-production.s3-us-west-2.amazonaws.com/build_certificates/uploads/30067/original/certs.p12?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAIOC7N256G7J2W2TQ%2F20180216%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20180216T124240Z&X-Amz-Expires=600&X-Amz-SignedHeaders=content-length%3Bhost&X-Amz-Signature=2bf42176650f00405abfd7b7757635c9be16b43e98013abb7f750d3c658be28e' ``` 1. Confirm the file upload with a POST call of the `uploaded` endpoint: use the `slug` from the response to the first POST call. This sets the `processed` flag of the file to `true`. This flag can't be changed again afterwards! ```bash curl -X POST -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/provisioning-profiles/FILE-SLUG/uploaded' ``` ### Updating an uploaded iOS code signing file You can perform minor updates to an uploaded iOS code signing file using the `PATCH` method. If you’ve uploaded your file to [Bitrise](https://www.bitrise.io), you can visually check any changes to it on the **Code Signing & Files** tab. :::note[Required role] You must have an admin or owner role on the app's team to manage iOS code signing files using the Bitrise API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: For example, to make a **provisioning profile** protected, you can set the `is_protected` flag of your provisioning profiles to `true`. ```bash curl -X PATCH -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/provisioning-profiles/PROVISIONING-PROFILE-SLUG -d '{"is_protected":true}' ``` For a **build certificate** you can set the same attributes as above but you can modify the password too: ```bash curl -X PATCH -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/build-certificates/BUILD-CERTIFICATE-SLUG -d '{"certificate_password":"s0m3-v3ry-s3cr3t-str1ng"}' ``` :::note[Availability of the `certificate_password`] Note that, the same way as the `download_url`, the `certificate_password` is only returned in the response when the file's `is_protected` attribute is false. ::: :::warning[Be careful when setting attributes] You can set the `is_protected`, `is_exposed` and `processed` attributes of the files you've uploaded: - Once the `is_protected` flag is set to `true,` it cannot be changed anymore. - When the value of `is_protected` is true, then the `is_expose` flag cannot be set to another value. - Once the `processed` flag is set to true, then its value cannot be changed anymore. ::: ### Getting a specific iOS code signing file's data :::note[Required role] You must have an admin or owner role on the app's team to manage iOS code signing files using the Bitrise API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: Retrieve a specific iOS code signing file’s data with the GET method of the `provisioning-profiles` and `build-certificates` endpoints. The returned data includes, among other things, the file's name, size, and download URL, as well as its current status. The required parameters are: - app slug - file slug **Retrieving a provisioning profile's data** Request: ```bash curl -X GET -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/provisioning-profiles/PROVISIONING-PROFILE-SLUG' ``` Response: ```json { "data": { "upload_file_name":"sample.provisionprofile", "upload_file_size":2047, "slug":"01C6FA6P6HRQT5PQ8RMMVVXE6W", "processed":false, "is_expose":true, "is_protected":false, "download_url":"https://concrete-userfiles-production.s3-us-west-2.amazonaws.com/prov_profile_documents/uploads/80144/original/sample.provisionprofile?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAIOC7N256G7J2W2TQ%2F20180322%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20180322T091652Z&X-Amz-Expires=600&X-Amz-SignedHeaders=host&X-Amz-Signature=6dd7bb3db72aafb2d434da7b1a8f80a82a3a7a0276e84620137ed64de5025ab2" } } ``` :::note[Availability of the `download_url`] Note that the `download_url` is generated only when the file’s `is_protected` attribute is false. ::: ### Listing the iOS code signing files of an app :::note[Required role] You must have an admin or owner role on the app's team to manage iOS code signing files using the Bitrise API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: Wondering how many iOS code signing files belong to an app? Get a list of them using the `GET` method of the `provisioning-profiles` and `build-certificates` endpoints. The required parameter is: - app slug Optional parameters are: - next: slug of the first file in the response (as a string) - limit: max number of elements per page (as an integer) where the default is 50. **Getting all provisioning profiles of an app** Request: ```bash curl -X GET -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/provisioning-profiles' ``` Response: ```json { "data": [ { "upload_file_name":"sample.provisionprofile", "upload_file_size":2047, "slug":"01C6FA6P6HRQT5PQ8RMMVVXE6W", "processed":false, "is_expose":true, "is_protected":false }, { "upload_file_name":"sample2.provisionprofile", "upload_file_size":2047, "slug":"01C6FA6P6HRQT5PQ8RMMVVXE5T", "processed":true, "is_expose":true, "is_protected":true } ], "paging": { "page_item_limit": 50, "total_item_count": 2 } } ``` --- ## Managing Secrets with the API This guide describes how to manage your secrets with the Bitrise API. If you’d like to learn more about how to do the same on the UI, check out [Secrets](/bitrise-ci/configure-builds/secrets). | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | GET/apps/\{app-slug\}/secrets | Get a list of Secrets of a specified app. | Owner or Admin | | GET/apps/\{app-slug\}/secrets/\{secret-name\}/value | Get the value of an (unprotected) Secret. | Owner or Admin | | PUT/apps/\{app-slug\}/secrets/\{secret-name\} | Create or update a Secret. | Owner or Admin | | DELETE/apps/\{app-slug\}/secrets/\{secret-name\} | Delete a Secret. | Owner or Admin | ### Viewing the Secrets of an app :::important[Required role] You must have an admin or owner role on the app's team to view Secrets using the Bitrise API. For a complete list of user roles and role cheatsheets, check [User roles on app teams](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: You can view the Secrets of an app with the help of the API. You can get a list of all the Secrets of an app with the `GET/apps/{app-slug}/secrets` endpoint. You can view a specific Secret if its `is_protected` value is set to `false`. **Viewing an app's Secret called "test"** Request: ```bash curl -X GET -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/APP-SLUG/secrets/test/value' ``` The response will give the value of the Secret if its `is_protected` value is set to `false`: ```json { "value": "123ld" } ``` ### Creating or updating Secrets :::important[Required role] You must have an admin or owner role on the app's team to create/update Secrets using the Bitrise API. For a complete list of user roles and role cheatsheets, check [User roles on app teams](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: You can create or update Secrets using the PUT method of the `secrets` endpoint. If a Secret does not exist with the `secret-name` you provide, a new Secret will be created. If the Secret already exists, it will be updated with the new values you provided. The required parameter are: - app slug - secret's name Optional parameters are: - expand_in_step_inputs: Set to true if you want Bitrise CLI to expand Secret before passing it on to Steps. - is_exposed_for_pull_requests: Set to true if you want Secret to be exposed for pull requests. - is_protected: Set to true if you want your Secret's value to be protected. (You will not be able to view Secret's value using the GET method.) - value: The value stored in the Secret. **Creating a new Secret called "test"** Request: ```bash curl -X PUT -H 'Authorization: THE-ACCESS-TOKEN' 'https://api.bitrise.io/v0.1/apps/THE-APP-SLUG/secrets/test' -d '{"expand_in_step_inputs": true, "is_exposed_for_pull_requests": true, "is_protected": false, "value": "123ld2"}' ``` --- ## Pagination of API calls When you call an endpoint that returns a list of items, you might not get the whole list in a single response. You’ll have to iterate through the pages to retrieve all the items. The response of such endpoints include a `paging` object, with `total_item_count` and `page_item_limit` properties. If there is a “next” page available, it’ll also include a `next` “anchor” item. For example, the response will show the app slug of the first app on the next page. ```json { "data": [ ... ], "paging": { "total_item_count": 3, "page_item_limit": 2, "next": "518e869d56f2adfd" } } ``` :::note[The `next` property of the `paging` object] The `next` property of the `paging` object is only included if there’s at least one more page available. If there’s no `next` property inside `paging` that means that there’s no more page to retrieve. ::: Limit the number of response pages with the `limit` parameter: ``` https://api.bitrise.io/v0.1/apps?limit=10 ``` This call sets the `page_item_limit` property to 10. The default (and maximum) value of the parameter is 50. Iterate through response items: 1. Call the endpoint without any pagination parameters. 1. From the response process the `paging` object. 1. If the `paging` object includes a `next` item, call the exact same endpoint with an additional `next=` query parameter, and pass the value you got in the response as the value of the `next` parameter. **Iterating through all your registered apps** 1. Call `https://api.bitrise.io/v0.1/apps`. 1. Process the items (`data` property). 1. Check the `paging` (root) property. 1. If there’s a `next` property inside `paging`, call the endpoint again, with the `next` query parameter - Example: `https://api.bitrise.io/v0.1/apps?next=NEXTVALUE`, where `NEXTVALUE` is the value of the `next` property you got in your previous response. 1. Repeat this until the `paging` object does not include a `next` property, which means that the page you received was the last one. --- ## Triggering and aborting builds | Endpoints | Function | Required role on the app's team | | --- | --- | --- | | POST /apps/\{app-slug\}/builds | Trigger a new build. | Owner, Admin, or Developer | | POST /apps/\{app-slug\}/builds/\{build-slug\}/abort | Abort a specific build. | Owner, Admin, or Developer | You can trigger and abort builds with the Bitrise API. Define parameters for the build: for example, branch, tag or git commit to use. Custom [Environment Variables](/bitrise-ci/configure-builds/environment-variables) can be defined as well. ### Triggering a new build with the API To trigger a new build with the Bitrise API, call the `POST /apps/{APP-SLUG}/builds` endpoint. You need to specify an app slug and at least one build parameter in a JSON object: - A git tag or git commit hash - A branch - A Workflow ID or a Pipeline ID :::note[Required role] You must have a developer, admin, or owner role on the app's team to trigger a new build using the API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: The JSON object must also contain a `hook_info` object with a `type` key and `bitrise` as the value of the key. Here’s a minimal sample JSON body which specifies `main` as the value of the `branch` parameter: ```json { "hook_info": { "type": "bitrise" }, "build_params": { "branch": "main" } } ``` And here’s the curl request syntax for triggering a build with the `prod` Workflow on the `main` branch: ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/builds' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "build_params": { "branch": "main", "workflow_id":"prod" }, "hook_info": { "type": "bitrise" } }' ``` :::tip[Interactive cURL call configurator] You can find an interactive cURL call configurator by clicking on the `Start/Schedule a build` button on your app’s [bitrise.io](https://www.bitrise.io) page and switching to `Advanced` mode in the popup. At the bottom of the popup you can find a `curl` call, based on the parameters you specify in the popup. ::: In the previous example, we passed this JSON payload as a string: to be precise, as a JSON object serialized to a string. You can also pass it as an object (for example, if you want to call it from JavaScript). To do so, include a root `payload` element or, alternatively, set the JSON object as the value of the `payload` POST parameter. Here’s a jQuery example using the `payload` parameter: ```javascript $.post("https://api.bitrise.io/v0.1/apps/APP-SLUG/builds/", { "payload":{ "hook_info":{ "type":"bitrise" }, "build_params":{ "branch":"main", "workflow_id":"prod" } } }) ``` You can specify several different build parameters when triggering a build. The parameters should be set in the `build_params` object. #### Setting a branch, commit or tag to build You can set Git-specific parameters in your call. The `branch` parameter specifies the source branch to be built. This is either the branch of the git commit or, in the case of a pull request build, the source branch of the pull request. ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/builds' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "hook_info": { "type": "bitrise" }, "build_params": { "branch": "main", "workflow_id":"prod" } }' ``` You can also build a specific git commit or even a git tag: you just need to set either the commit hash or the tag in the `build_params` object. You can also set a commit message for the build with the `commit_message` parameter. ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/builds' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "hook_info":{ "type":"bitrise" }, "build_params": { "commit_hash": "0000ffffeeeee", "commit_message": "testing", "workflow_id":"prod" } }' ``` :::important[Parameter priority] The `Git Clone` Step has the following parameter priority: 1. commit_hash 1. tag 1. branch If you provide multiple parameters, the parameter with lower priority will be ignored. The ignored parameters will still be logged. They will be available for Steps and they will be visible on the Build’s **Details** page but the `Git Clone` Step will use the most specific parameter for checkout. ::: #### Setting parameters for pull request builds For a pull request build, use the `branch_dest` parameter to set up the destination or target branch of the pull request. The PR will be merged into this branch but before that, Bitrise will build your app based on how the code would look like after merging. This is what happens when a PR build is automatically triggered by a webhook, for example. :::note[GitHub stacked pull requests] When a webhook triggers a build for a pull request in a [GitHub stack](https://docs.github.com/en/pull-requests/get-started/about-stacked-prs), Bitrise sets `branch_dest` to the base branch of the stack. ::: The `branch_repo_owner` and `branch_dest_repo_owner` parameters are used to identify the owners of the repositories, to unambiguously identify the branches involved in the pull request. :::important[Pull request builds from forks] If you do not specify the `branch_repo_owner` and `branch_dest_repo_owner` parameters, the API will assume pull request builds are coming from a fork. As such, they might be put on hold pending manual approval: [Approving Pull Request builds](/bitrise-ci/run-and-analyze-builds/starting-builds/approving-pull-request-builds). ::: To identify the PR itself, use the `pull_request_id` parameter: it takes an integer; for example, the number of the PR on GitHub. ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/builds' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "hook_info":{ "type":"bitrise" }, "build_params": { "branch": "the-pr-branch", "branch_dest": "main", "commit_hash": "fffff000000eeeeee", "pull_request_id": 1, "workflow_id":"prod" } }' ``` If your git provider supports it, you can also use the `pull_request_merge_branch` parameter to build the pre-merged state of the branch of the PR. Another alternative is the `pull_request_head_branch` parameter: this is a special git ref that should point to the source of the PR. If you want to trigger a build from a PR opened from a fork of your repository, use the `pull_request_repository_url` parameter. The value should be the URL of the fork. #### Skipping Git status reports If you have a [webhook](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks) set up, Bitrise will send status reports to your git provider about your builds. However, this can be disabled via the API: use the `skip_git_status_report` parameter. If it is set to `true`, no build status report will be sent. ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/builds' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "hook_info":{ "type":"bitrise" }, "build_params": { "branch": "the-pr-branch", "branch_dest": "main", "skip_git_status_report": true, "workflow_id":"prod" } }' ``` #### Specifying Environment Variables You can define additional [Environment Variables](/bitrise-ci/configure-builds/environment-variables) (Env Vars) for your build. These additional variables will be handled with priority between `Secrets` and `App Env Vars`, which means that you can not overwrite Env Vars defined in your build configuration (for example, App Env Vars), only [Secrets](/bitrise-ci/configure-builds/secrets). Define additional Env Vars with the environments parameter. This parameter must be an **array of objects**, and every item of the array must include at least a `key` property. This must contain: - The key of the Env Var. - The value of the Env Var. :::note[Replacing Env Var names] By default, Env Var names inside values will be replaced in triggered build by actual value from the target environment. This behavior can be disabled by setting the `is_expand` flag to `false`. ::: ```yaml "environments":[ {"key":"API_TEST_ENV","value":"This is the test value","is_expand":true}, {"key":"HELP_ENV","value":"$HOME variable contains user's home directory path","is_expand":false}, ] ``` #### Setting a Workflow for the build By default, the Workflow for a triggered build will be selected based on the content of `build_params` and your app’s [trigger map](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers). This is the same as how webhooks select the Workflow for the build automatically, based on the Trigger Map. With the API, you can overwrite this selection and specify exactly which Workflow you want to use. Add a `workflow_id` parameter to your `build_params` and specify the workflow you want to use for that specific build. Here’s an example call where we specify the `deploy` workflow: ```bash curl -X 'POST' \ 'https://api.bitrise.io/v0.1/apps/APP-SLUG/builds' \ -H 'accept: application/json' \ -H 'Authorization: ACCESS-TOKEN' \ -H 'Content-Type: application/json' \ -d '{ "hook_info": { "type": "bitrise" }, "build_params": { "branch": "main", "workflow_id": "deploy" } }' ``` ### Aborting a build You can abort running builds, and set the reason for aborting, as well as specify if email notifications should be sent about the build. :::note[Required role] You must have an owner, admin, or developer role on the app's team to abort a build using the API. For a complete list of user roles and role cheatsheets, check [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: To simply abort the build, call the `/apps/APP-SLUG/builds/BUILD-SLUG/abort` endpoint. It requires three parameters: - The app slug. - The build slug. - The build abort parameters body. This can be left empty if you don't want to set any specific parameters for the abort: `-d "{}"`. ```bash curl -X POST -H "Authorization: ACCESS-TOKEN" "https://api.bitrise.io/v0.1/apps/APP-SLUG/builds/BUILD-SLUG/abort" -d "{}" ``` You can set a reason for aborting the build by using the `abort_reason` parameter. This parameter takes a string and it will show up on your app’s build page. ```bash curl -X POST -H "Authorization: ACCESS-TOKEN" "https://api.bitrise.io/v0.1/apps/APP-SLUG/builds/BUILD-SLUG/abort" -d '{"abort_reason": "aborted for a reason"}' ``` Normally, aborted builds count as failed builds. Use the `abort_with_success` parameter to abort a build but still count it as a successful one. The status report sent to your git provider will show the build as successful though on [bitrise.io](https://www.bitrise.io) it will be displayed as `Cancelled`. ```bash curl -X POST -H "Authorization: ACCESS-TOKEN" "https://api.bitrise.io/v0.1/apps/APP-SLUG/builds/BUILD-SLUG/abort" -d '{"abort_with_success": true}' ``` Depending on your app settings, Bitrise might send email notifications to team members when a build is aborted. If you do not want notifications, set the `skip_notifications` parameter to `true`. ```bash curl -X POST -H "Authorization: ACCESS-TOKEN" "https://api.bitrise.io/v0.1/apps/APP-SLUG/builds/BUILD-SLUG/abort" -d '{"skip_notifications": true}' ``` --- ## Adding a new project from a CLI You can easily register a new Bitrise project from any command line interface: the process is guided and simple to follow. And it’s fast: if, for example, you have the `bitrise.yml` file you want to use for the project, you do not have to wait for the project scanner to detect the project type and generate your `bitrise.yml` file. Just plug in the existing file and you are good to go! :::tip[Adding a project with the API] You can also use the Bitrise API to add a new project: [Adding and managing apps](/bitrise-ci/api/adding-and-managing-apps) ::: ### Preparing the project Before you try adding a new project to Bitrise via our CLI, make sure a few things are in order: - You need a Bitrise account, with a connected Git provider. - Your project must have a local Git repository on your machine and a remote repository at a Git provider. If you want to use an SSH key to access the repository, [the remote repository URL must be an SSH URL](https://help.github.com/en/articles/which-remote-url-should-i-use)! For example, `git@github.com:example-user/example.git`. You can also create a `bitrise.yml` in advance and you will be able to add that to your project during the creation process. This is optional: you can have the project scanner generate one for you during the process, just like on our website! This procedure guides you through adding a project which Bitrise will access with an SSH key. This requires that the project’s remote repository has an SSH URL, such as `git@github.com:example-user/example.git`. You can, of course, use an HTTPS URL to access your remote repository, too: in that case, you will not set an SSH key for your project. We only recommend using HTTPS URLs for public projects (open source projects). And that’s it! You are done: the URL to your new project will be printed out, and you can also view the project on your [Bitrise CI page](https://app.bitrise.io/ci). ### Adding the project 1. Go to the [New CI project from CLI](https://app.bitrise.io/apps/add/cli) page. You can reach this page from your [Bitrise CI page](https://app.bitrise.io/ci): click the **New CI project** button on the right, and then select **New CI project from CLI**. ![2025-12-10-adding-project-with-cli.png](/img/_paligo/uuid-a6c8e931-615c-8697-8cf6-ab8d5269420b.png) 1. Set the account that will own the project, and the privacy of the project. 1. Copy the curl command you find there. ![2025-12-10-cli-project-choice.png](/img/_paligo/uuid-8ca5abc9-91d0-2f49-c804-dd8b60f92c39.png) 1. Open a command line interface. 1. Change the directory to your project’s location. 1. Paste the curl command and hit Enter. 1. Select the repository URL: choose the `SSH` option. This prompt only comes up if your local repository’s remote has an SSH URL. If the remote repository has an HTTPS URL, you won’t see this prompt. ```yaml Remote URL: git@github.com:example-user/example.git ? Select repository URL:: https://github.com/example-user/example.git > ssh://git@github.com:example-user/example.git ``` 1. Register an SSH key. ```yaml Specify how Bitrise will be able to access the source code: > Automatic Add own SSH ``` You can select either the automatic registration or choose to add your own. - If you choose automatic, Bitrise will automatically generate a key pair. If you need to use additional private repositories or submodules, choose the I need to option when prompted and follow the instructions. If not, select the No, auto-add SSH key option: this automatically adds the public key to your repository. - If you choose to add your own, you have to provide the path to the SSH key file: either enter it manually, or drag and drop the file, as that will input the path. 1. Decide what `bitrise.yml` file you want to upload. ```text ? What bitrise.yml do you want to upload? > Run the scanner to generate a new bitrise.yml Use the bitrise.yml found in the current directory or specify manually ``` You can either have the scanner generate one based on your project files or you can provide a file. If your repository already contains a `bitrise.yml` file, the path to it will be automatically filled in. 1. Select the branch you want to use. The default option is the current active branch. ```yaml The current branch is: master (tracking: origin master), ? Do you want to run the scanner for this branch? > Yes No ``` If you select `No`, you will be prompted to check out the branch you wish to use, and then hit Enter again so the scanner can start. Once the scanner is done, it will either detect your project’s type or it will switch to manual configuration. Manual configuration means you have to select the type of your project (iOS, Android, React Native, Flutter, and so on) and you have to provide the path to the relevant configuration file. For example, a `config.xml` in the case of an Ionic project. In this guide, we’ll proceed with automatic detection. 1. Select the stack you want to use. If the scanner detects your project type, a stack will be automatically recommended but you can change it in the CLI if you want to. If you performed manual configuration as described above, you will have to choose the stack, too. 1. Finish the process with setting up webhooks and code signing files. - You can decide to skip webhook registration but it’s required to automatically trigger builds on Bitrise. For more information: [Webhooks](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks) - You can upload code signing files: depending on your project’s type, you will be asked if you want to upload iOS code signing files and/or an Android keystore file. You can upload these files any time on the website. --- ## Initializing a Bitrise project locally When you add a new app to Bitrise, we detect the type of your project and generate a basic `bitrise.yml` file for you, with Workflows that are appropriate for your project type. With the Bitrise CLI, you can make this work on your own computer: 1. [Install the Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli) on your computer. 1. `bitrise init` needs Go to run. :::note[Installing Go] If you don't have Go installed on your computer, `bitrise init` will automatically install it for you. ::: 1. Start the `bitrise init` plugin: ```bash bitrise init ``` 1. Wait while the plugin runs all available scanners to determine your project type. 1. Depending on the detected project type, the scanner asks for some input. Follow the instructions. For example, with an iOS project, it asks the user to specify an export method: ```yaml Select: ipa export method Please select from the list: [1] : app-store [2] : ad-hoc [3] : enterprise [4] : development (type in the option's number, then hit Enter) : ``` Based on the scanner outputs, the plugin generates a Bitrise configuration, with a `bitrise.yml` file. In the automatically generated Workflows, every required input will have a valid value. The plugin also generates a `.bitrise.secrets.yml` file. You can store your Secrets in this file. --- ## Installing and updating the Bitrise CLI The Bitrise CLI is Bitrise's open source runner. The CLI is used to run your builds on [bitrise.io](https://www.bitrise.io) and you can install and run it on your own computer to run builds locally. The Bitrise CLI is distributed as a single binary for macOS and Linux. You can download it using curl or Homebrew. ### Installing the Bitrise CLI with curl 1. Run the following command in a bash shell: ```bash curl -fL https://github.com/bitrise-io/bitrise/releases/latest/download/bitrise-$(uname -s)-$(uname -m) > /usr/local/bin/bitrise ``` You can check the latest release of the Bitrise CLI on its [releases](https://github.com/bitrise-io/bitrise/releases) page. 1. Make the downloaded binary executable: ```bash chmod +x /usr/local/bin/bitrise ``` 1. Run `bitrise setup`. This will verify if everything that is required for Bitrise to run is installed and available. If you skip this, the CLI will perform the setup anyway the first time you call `bitrise run`. ### Installing the Bitrise CLI with Homebrew If you have the Homebrew package manager installed on your Mac, you can use it to install the Bitrise CLI. 1. Open the `Terminal` app on your Mac and run: ```bash brew update && brew install bitrise ``` 1. Perform a first-time setup for the Bitrise CLI: ```bash bitrise setup ``` This will verify if everything that is required for Bitrise to run is installed and available. If you skip this, the CLI will perform the setup anyway the first time you call `bitrise run`. ### Updating the Bitrise CLI Updating the Bitrise CLI is easy, and it doesn’t matter if you installed it with Homebrew or from the GitHub release. Simply run `bitrise update` - that’s it! The CLI checks for updates once every day and notifies you as soon as there is a new version. --- ## Installing and upgrading the offline Workflow Editor You can run the Bitrise Workflow Editor offline, on your own computer, without logging in to [bitrise.io](https://www.bitrise.io/). The Workflow Editor is open source: check out the [bitrise-workflow-editor repository](https://github.com/bitrise-io/bitrise-workflow-editor) on GitHub. ### About the offline Workflow Editor The offline Workflow Editor is a local copy of the Workflow Editor that ships with the Bitrise CLI. It runs in your browser on your own computer and edits your project's configuration YAML file locally. Use it when: - You want to edit your configuration without logging in to bitrise.io. - Your security policy requires that your configuration never leaves your own network. - You prefer editing the configuration YAML file in a GUI instead of editing it by hand. ### Limitations The offline Workflow Editor supports most features of the Workflow Editor on bitrise.io, including Step bundles, containers, and target-based triggers. One exception: you can't select a stack or machine type, because the **Stacks & Machines** page isn't available locally. You can still set the stack by editing the configuration YAML file directly, but the offline Workflow Editor doesn't validate the stack value: the list of available stacks depends on your account, and the offline Workflow Editor doesn't log in to bitrise.io. To check that a stack value is valid for your project, open **Stacks & Machines** in the Workflow Editor on bitrise.io. Full feature support requires Bitrise CLI 2.43.0 or newer. On an older version, update the CLI or update the Workflow Editor plugin: ```bash bitrise plugin update workflow-editor ``` ### Installing the offline Workflow Editor to your computer 1. [Install the Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli). 1. Run `bitrise setup` to install offline Workflow Editor as part of the Bitrise Plugins. Running `bitrise setup` also checks if Bitrise Core tools, Bitrise Plugins and Toolkits are installed on your local machine. If not, it will automatically install them. On macOS, it also checks for Homebrew, prompting you to install it manually if missing. ### Starting the offline Workflow Editor 1. `cd` into a directory where you have your `bitrise.yml`. 1. Run `bitrise :workflow-editor` command to start your offline session. The offline Workflow Editor opens in your browser: ![The offline Workflow Editor with the Workflows tab open, showing a Workflow's Steps](/img/bitrise-cli/2026-09-02-offline-workflow-editor.png) ### Upgrading Workflow Editor version You can upgrade to the latest version of the Workflow Editor by running `bitrise plugin update workflow-editor` command. --- ## Managing Secrets locally When you run a build locally, with the Bitrise CLI, the Secrets are read from a `.bitrise.secrets.yml` file, which is expected to be in the same directory where the `bitrise.yml` is, and where you run the `bitrise run` command. If you want to store your Secrets somewhere else, you can specify the location of the Secrets file with the `--inventory` flag of the `bitrise run` command. For example: . ```bash bitrise run my-workflow --inventory /path/to/secrets.yml ``` :::tip[Make sure to `gitignore` your Secrets file] As a best practice, you should always make sure that the `.bitrise.secrets.yml` is added to your `.gitignore`, so that it will never be committed into your repository! The best is if you `gitignore` everything that starts with `.bitrise`, which can be done by adding the line: `.bitrise*` to your `.gitignore` file. ::: The Secrets YAML file has to include a root `envs:` item and then the list of Secret Environment Variables. ```yaml envs: - SECRET_ENV_ONE: first Secret value - SECRET_ENV_TWO: second Secret value ``` The Secrets defined in the `.bitrise.secrets.yml` file can be used just like any other Environment Variable. ```yaml format_version: 11 default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git workflows: test: steps: - script@1.1.3: inputs: - content: | #!/bin/bash echo "SECRET_ENV_ONE: ${SECRET_ENV_ONE}" echo "SECRET_ENV_TWO: ${SECRET_ENV_TWO}" ``` You can just `bitrise run test` in the directory, and the Script Step will print the values specified in the secrets file: ```yaml SECRET_ENV_ONE: first secret value SECRET_ENV_TWO: second secret value ``` As Secrets are the first Environment Variables processed when you execute a `bitrise run` command, you can use the Secrets everywhere in your `bitrise.yml`. --- ## Running your first local build with the CLI To run a Bitrise build locally, you only need to: 1. [Install the Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli). 1. A build configuration: that is, a `bitrise.yml` file. If you use [bitrise.io](https://www.bitrise.io), you can download your app’s `bitrise.yml` from there: open the Workflow Editor of the app on [bitrise.io](https://www.bitrise.io), under the `bitrise.yml` section. If you want to create a `bitrise.yml` yourself, simply create a `bitrise.yml` file in the root of your project. You can use this as the base content of the `bitrise.yml`: ```yaml format_version: '26' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git app: envs: - MY_NAME: My Name workflows: test: steps: - script@1.1.3: inputs: - content: echo "Hello ${MY_NAME}!" ``` This defines an [Environment Variable](/bitrise-ci/configure-builds/environment-variables) with your name and a Workflow called `test`. To run this build: 1. Open the Terminal or some other CLI app. 1. Go to the directory where you saved the `bitrise.yml` file. 1. Run `bitrise run` with the name of the Workflow you defined in the file. ```bash bitrise run test ``` That’s it: your first build is running with the Bitrise CLI. --- ## Android code signing in Gradle You can manually specify the code signing configuration in your Gradle configuration so that your app gets signed during the build process. 1. Open your module-level `build.gradle` file. 1. Add the `signingConfigs` codeblock to your code and define the following entries specific to your project: - `storeFiled` - `storePassword` - `keyAlias` - `keyPassword` 1. Attach the signing config to a build type. 1. Build your app on Bitrise. For more information, check out how to [configure Gradle to sign your app](https://developer.android.com/studio/publish/app-signing). **Signing configuration in the build.gradle file** In this example, your keystore path should have the same path locally and on [bitrise.io](https://www.bitrise.io) to ensure the build can use the keystore file. ``` android { // Make sure signingConfigs is defined before buildTypes. signingConfigs { release { keyAlias 'MyAndroidKey' keyPassword '***' storeFile file("/path/to/my/keystore.jks") storePassword '***' } } buildTypes { release { // Use signing config for build type signingConfig signingConfigs.release // ... } } // ... ``` **Using Environment Variables in the build.gradle file** You can avoid having the same keystore path locally and on [bitrise.io](https://www.bitrise.io) by using configuration values and Environment Variables in the keystore path (`storeFile`) and in the keystore password. You can use the `System.getenv("ENV_KEY")` file to access Environment Variables in the `build.gradle` file. Make sure to define the Environment Variables you use in your `build.gradle` file on [bitrise.io](https://www.bitrise.io) as well. If your keystore path is `$HOME/keystores/my_keystore.jks`, then your `build.gradle` file should look like this: ``` android { signingConfigs { release { keyAlias 'MyAndroidKey' keyPassword '***' storeFile file(System.getenv("HOME") + "/keystores/my_keystore.jks") storePassword '***' } } ... ``` You can then download the keystore file [using the File Downloader Step](/bitrise-ci/run-and-analyze-builds/managing-build-files/using-files-in-your-builds#downloading-a-file-using-the-file-downloader-step), using the `$HOME/keystores/my_keystore.jks` as the destination path. If you use Environment Variables as `keyPassword` and `storePassword` on the **Code signing** tab, your `build.gradle` will look like this: ``` android { signingConfigs { release { keyAlias System.getenv("BITRISEIO_ANDROID_KEYSTORE_ALIAS") keyPassword System.getenv("BITRISEIO_ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD") storeFile file(System.getenv("HOME") + "/keystores/my_keystore.jks") storePassword System.getenv("BITRISEIO_ANDROID_KEYSTORE_PASSWORD") } } buildTypes { release { // Use signing config for build type signingConfig signingConfigs.release // ... } } ... ``` --- ## Android code signing using the Android Sign Step You can create a signed APK or AAB using the [**Android Sign**](https://github.com/bitrise-steplib/steps-sign-apk) Step in your Bitrise Workflow. The **Android Sign** Step is not required if signing is configured in your project's `build.gradle` file. If so, running the [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build) Step (or the [**Gradle Runner**](https://github.com/bitrise-io/steps-gradle-runner) Step) signs the output (APK or AAB) automatically. Nevertheless, we recommend that you use the **Android Sign** Step to sign your project in an easy and secure way. To sign your app with the Android Sign Step: 1. [Upload your keystore file to Bitrise](/bitrise-ci/code-signing/android-code-signing/uploading-android-keystore-files-to-bitrise). This creates the following Environment Variables from your keystore's credentials: - `$BITRISEIO_ANDROID_KEYSTORE_URL` - `$BITRISEIO_ANDROID_KEYSTORE_PASSWORD` - `$BITRISEIO_ANDROID_KEYSTORE_ALIAS` - `$BITRISEIO_ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD` 1. Add the [**Android Sign**](https://github.com/bitrise-steplib/steps-sign-apk) Step to your Workflow, after the Step that builds your APK or AAB file. The Step's **Keystore url**, **Keystore password**, **Key alias**, and **Key password** inputs default to the Environment Variables generated from your keystore credentials, so you don't need to set them if you uploaded a single keystore file. If you uploaded multiple keystore files or set a custom keystore ID, point these inputs at the matching Environment Variables instead (see [Uploading Android keystore files to Bitrise](/bitrise-ci/code-signing/android-code-signing/uploading-android-keystore-files-to-bitrise)). 1. Optional: on the **Signer tool** input, choose whether the Step signs with `apksigner`, `jarsigner`, or decides automatically (the default: `apksigner` for APKs, `jarsigner` for AABs). AAB files can only be signed with `jarsigner` regardless of this setting. 1. Optional: on the **APK Signature Scheme** input, choose which signature scheme(s) `apksigner` applies, or leave it on automatic (the default) to let it decide based on your app's minimum and target SDK versions. Once the Step runs, it produces a signed APK or AAB. Use the signed output in a deploy Step, for example the [**Google Play Deploy**](https://github.com/bitrise-io/steps-google-play-deploy) Step or the **Deploy to Bitrise.io** Step, which publishes it on the **Artifacts** tab. You can also use [Release Management](/release-management) to deploy your app once you've built a signed artifact. :::note[Downloading your keystore file] You can download your keystore file to the project directory using the **[File Downloader](https://github.com/bitrise-steplib/steps-file-downloader)** Step: ```yaml - file-downloader: inputs: - source: $BITRISEIO_ANDROID_KEYSTORE_URL - destination: "$HOME/keystores/my_keystore.jks" #native android# ``` If a Step requires the keystore file, make sure to include that Step AFTER the [**File Downloader**](https://github.com/bitrise-steplib/steps-file-downloader) Step. After this Step, `my_keystore.jks` will be available at `$HOME/keystores/my_keystore.jks`. ::: --- ## Android code signing with Android Studio You can specify the code signing configuration for your project in [Android Studio](https://developer.android.com/studio/). You will need a keystore file, a key alias and a key password - have these ready before you start the procedure! 1. Open Android Studio. 1. Go to **Project navigator**. 1. Select your project and open **Module Settings**. 1. From **Modules**, select your module. 1. On the **Signing** tab, fill out the signing information. In our example, we used the following values: - Name: `release` - Key alias: `MyAndroidKey` - Key password: `***` - Store file: `/path/to/my/keystore.jks` - Store password: `***` Once you filled out the signing information, the `signingConfigs` block will be created in your module’s `build.gradle` file. On Bitrise, you just need to build the app, either with the **Android Build** or the **Gradle Runner** Step. --- ## Downloading a keystore file A keystore file is required for Android code signing. You can define the location of the keystore file of an Android app in your `build.gradle` file: [Android code signing in Gradle](/bitrise-ci/code-signing/android-code-signing/android-code-signing-in-gradle). You can upload your keystore file to Bitrise and use the **File Downloader** Step to download the keystore file from Bitrise and put it in the location defined in the `build.gradle` file. :::note[The Android Sign Step] If you use the **Android Sign** Step to sign your app, you don't need to download the keystore file. The Step will find the file: [Android code signing using the Android Sign Step](/bitrise-ci/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step). ::: 1. Add the **File Downloader** Step to your Workflow. The Step should be added BEFORE any Step that requires the keystore file, such as **Gradle Runner**. 1. Fill out the following two input fields: - **Download source url**: Set the generated keystore URL you get when you [upload your file to Bitrise](/bitrise-ci/code-signing/android-code-signing/uploading-android-keystore-files-to-bitrise)). - **Download destination path**: Set the location of the keystore file as a relative path. This path should be the same as the keystore path already defined in your `build.gradle` file (for example, `$HOME/keystores/project_release.keystore`). 1. Add the **Gradle Runner** Step right after your file downloading Step. With that said, if you have successfully added the Steps to download your keystore file to the same location that you specified in your `build.gradle` file, you do not need the **Android Sign** Step in your workflow. Our **Gradle Runner** Step will sign and assemble your project. --- ## Uploading Android keystore files to Bitrise To be able to digitally sign your Android apps, and distribute them on the Google Play Store, you need [a keystore file](https://developer.android.com/training/articles/keystore). You can store the keystore file in any accessible location and our Steps can use them but the easiest, most convenient way is to upload them directly to Bitrise. To do so: :::note[Multiple files] You can upload multiple keystore files to Bitrise. If you do, make sure your Steps use the right one, as they will have different URLs. ::: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Code signing** and go to the **Android** tab. 1. Click the **Add keystore file** button. 1. In the dialog box, drag and drop your keystore file onto the field, or click the field to browse your files. A keystore URL automatically gets generated once you upload the keystore file. Bitrise assigns an Environment Variable (`$BITRISEIO_ANDROID_KEYSTORE_URL`) to the download URL (which is a time-limited, read-only download URL) of the file as the value. No need to download it manually as the [Android Sign](https://github.com/bitrise-steplib/steps-sign-apk) Step downloads it automatically. 1. Fill out the displayed three input fields with your Android keystore credentials: - **Keystore password** - **Key alias** - **Private key password** ![Add keystore file dialog](/img/code-signing/android-code-signing/2026-07-14-add-android-keystore-file.png) You can set the passwords and the alias when creating the key: [Generate an upload key and keystore](https://developer.android.com/studio/publish/app-signing#generate-key). 1. Click **Continue**. The next page will show the new Environment Variables that will be available to your builds once you finish the file upload process: - `$BITRISEIO_ANDROID_KEYSTORE_ALIAS` - `$BITRISEIO_ANDROID_KEYSTORE_PASSWORD` - `$BITRISEIO_ANDROID_KEYSTORE_PRIVATE_KEY_PASSWORD` - `$BITRISEIO_ANDROID_KEYSTORE_URL` Each time you upload an additional keystore file after the first, the new file's respective Env Vars will have a number inserted before the field name. For example, `$BITRISEIO_ANDROID_KEYSTORE_1_ALIAS`, `$BITRISEIO_ANDROID_KEYSTORE_2_ALIAS`. 1. Review your keystore data to make sure you've uploaded the correct file. 1. Optionally, you can set up a custom ID for the keystore file: in the **Custom keystore ID** field, add the ID you want to use to identify your keystore file. The ID will replace the unique part of the keystore-related Env Vars: for example, if you set the ID to `My_Best_App`, the URL will be `$BITRISEIO_ANDROID_KEYSTORE_My_Best_App_URL`. 1. Click **Add keystore**. --- ## Creating a signed IPA for Xcode projects :::note[Overview on iOS code signing in Bitrise] For a comprehensive overview on what Steps are available for code signing asset management, visit the [iOS code signing page](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). ::: You can easily create a signed IPA file for your Xcode project with Bitrise. - You have set up [Apple service connection](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) on Bitrise. - Your [code signing files are managed correctly](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). - You set the relevant inputs of our **Xcode Archive & Export for iOS** Step. :::important[Upload the distribution AND the development signing certificates] We strongly recommend uploading BOTH the development and distribution signing certificates for your project. If you don't have an uploaded development signing certificate, Steps with automatic provisioning options will generate one on the fly every time you start a build. This can eventually lead to reaching the maximum number of certificates, blocking you from starting new builds. ::: If you’re all set, proceed to setting up IPA export in your Workflow. **Workflow Editor** 1. Make sure the necessary [code signing files have been collected and uploaded](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning#uploading-ios-code-signing-certificates-to-bitrise). 1. Make sure you have the [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive) Step in your Workflow. 1. Set the **Distribution method** input of the Step. ![xcode-archive.png](/img/_paligo/uuid-fced107c-9b69-e5af-1472-4d96fbada364.png) The options are: - `app-store`: Choose this if you want to deploy the app to the App Store. Requires a Distribution certificate and an App Store provisioning profile. - `ad-hoc`: Choose this if you want to deploy the app to ad-hoc testers. Requires a Distribution certificate and an Ad Hoc provisioning profile. - `enterprise`: Choose this if you have an Apple Enterprise account and want to use that to distribute your app. - `development`: Choose this for internal testing. Requires a Developer certificate and a Development provisioning profile. 1. Set the **Automatic code signing** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t use automatic code signing. - `api-key` [if you use API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` [if you use Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Save the Workflow, and start a new build. **Configuration YAML** 1. Make sure all the [necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) are available for your build. 1. Open the `bitrise.yml` file of your app. 1. Make sure you have the `xcode-archive` Step in your Workflow. ```yaml my-workflow: steps: - xcode-archive: inputs: ``` 1. Set the `distribution_method` input to the correct value. The available options are: - `app-store`: Choose this if you want to deploy the app to the App Store. Requires a Distribution certificate and an App Store provisioning profile. - `ad-hoc`: Choose this if you want to deploy the app to ad-hoc testers. Requires a Distribution certificate and an Ad Hoc provisioning profile. - `enterprise`: Choose this if you have an Apple Enterprise account and want to use that to distribute your app. - `development`: Choose this for internal testing. Requires a Developer certificate and a Development provisioning profile. ```yaml my-workflow: steps: - xcode-archive: inputs: - distribution_method: development ``` 1. Set the `automatic_code_signing` input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t do automatic code signing. - `api-key` [if you use API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` [if you use Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). ```yaml my-workflow: steps: - xcode-archive: inputs: - automatic_code_signing: api-key - distribution_method: development ``` That’s all. Xcode will automatically select the right signing files based on your project’s Bundle ID and Team ID settings, and the export method you set. ### Signing an IPA file with a different team’s code signing file You might want to sign the IPA file with a different team’s code signing files. For example: - If you use your company’s code signing files for internal builds, but your client’s code signing files are used for App Store distribution. - If you use Apple ID for automatic code signing and the Apple ID belongs to multiple teams, use The Developer Portal team to use for this export input to specify which team should be used for automatic code signing asset management. To do so: 1. Make sure the right code signing files of the new development team are uploaded to Bitrise. 1. Set the The Developer Portal team to use for this export option as well (in addition to the **Distribution method**). 1. Set the **Distribution method**. --- ## Exporting iOS code signing files without codesigndoc You can export iOS code signing certificates and provisioning profiles manually, or using Xcode. ### Exporting iOS code signing certificates with Xcode 1. Start Xcode. 1. Select `Xcode > Preferences` from the navigation bar. 1. At the top of the window select `Accounts`. 1. Select your Apple ID and your team from the right side bar, then click on `View Details...`. 1. A dialog will appear where you will see your code signing identities and the provisioning profiles. 1. Select the certificates and choose `Export` from the pop-up menu. ![Export_certificate.png](/img/_paligo/uuid-a2ef477b-91fa-fd15-a651-76faeb65a665.png) 1. Enter a filename in the Save As dialog. You can set a password and a verification to store it securely, but it’s not necessary. 1. Xcode will export the requested certificate in .p12 format. ### Exporting iOS code signing certificates manually 1. Start Keychain Access. 1. On the top left sidebar select `login` and on the bottom left select `My Certificates`. 1. This will list all your installed certificates and the associated private key. 1. Select the one that you would like to export and choose `Export` from the pop-up menu. ![Export_certificate.png](/img/_paligo/uuid-10b69d2d-9cf7-8577-04a4-d035a5f06ad9.png) 1. Enter a filename in the Save As dialog. You can set a password and a verification to store it securely, but it’s not necessary. 1. Keychain Access will export the requested certificate in .p12 format. ### Exporting iOS provisioning profiles with Xcode 1. Start Xcode. 1. Select `Xcode > Preferences` from the navigation bar. 1. At the top of the window select `Accounts`. 1. Select your Apple ID and your team from the right side bar, then click on `View Details...`. 1. A dialog will appear where you will see your code signing identities and the provisioning profiles. 1. Locate the profile that you are looking for under Provisioning Profiles. 1. If you don’t have it installed on the system, click on the `Download` button next to it. 1. Choose `Show in finder` from the pop-up menu, that will show you the installed provisioning profile for you. ### Exporting iOS provisioning profiles manually 1. Go to [https://developer.apple.com](https://developer.apple.com) and log in. 1. Select Certificates, Identifiers & Profiles from the left sidebar. 1. Navigate to Provisioning Profiles > All. 1. Find the Provisioning Profile you are looking for from the list or use the search to filter. 1. Click on the selected Provisioning Profile, this will expand the details. 1. If its status is invalid, you can click on the `Edit` button and save again. 1. Click on the `Download` button to download it and double click to install on your macOS. --- ## Generating iOS code signing files You'll need two kinds of files to sign your app: certificates and provisioning profiles. The certificates - development or distribution - are the guarantee that you, the named developer, built this code, that you are a member of the developer program, and that Apple have issued you with a certificate to do so. To get a certificate, you need to generate a Certificate Signing Request with Keychain Access and send it to Apple. This will create a public/private key pair for you if you don't have one already. Apple will then verify the information, and create a certificate for you. Provisioning is the process of preparing and configuring an app to launch on devices and to use app services. Development provisioning profiles holds the device identifiers (UUID) that is eligible to run your app. Distribution provisioning profiles can include App Store profiles that allow you to distribute your app to the App Store. Ad-hoc profiles are good for distributing to your testers. ### Generating a code signing certificate with Xcode First, add your Apple Account to Xcode. If you've already done this, skip ahead to creating the certificate. 1. Start Xcode. 1. Choose **Xcode > Settings**. 1. In the toolbar, click **Accounts**. 1. Click the **+** button in the lower-left corner and select **Add Apple ID…**. 1. In the dialog that appears, enter your Apple Account credentials and select **Sign in**. If you don't have an account yet, select **Create Apple ID**. 1. Select your Apple Account and team from the list, then click **Manage Certificates**. 1. In the signing certificates sheet, click the **+** button in the lower-left corner and choose a certificate type, such as **Apple Development** or **Apple Distribution**, from the pop-up menu. Xcode generates and installs the certificate for you. 1. Click **Done**. :::note[Removing a certificate] To remove a certificate, Control-click it in the signing certificates sheet and select **Delete Certificate**. You can only delete certificates that you or a team member has revoked in your developer account. ::: ### Generating a code signing certificate manually 1. Open your **Keychain Access** app on macOS. 1. Select **Keychain Access > Certificate Assistant > Request a Certificate From a Certificate Authority…**. 1. Fill in your **User Email Address** and **Common Name**, and select **Saved to disk**. 1. Click **Continue** and save the generated `.certSigningRequest` file locally. 1. Go to [developer.apple.com](https://developer.apple.com) and log in to your account. 1. Select **Certificates, Identifiers & Profiles** from the left sidebar. 1. Go to **Certificates** and click the **+** button in the top-right corner. 1. Select a certificate type, such as **Apple Development** for development or **Apple Distribution** for distribution, and click **Continue**. 1. Upload the `.certSigningRequest` file you created and click **Continue**. Apple generates your code signing certificate. 1. Download the certificate and double-click it to install it in **Keychain Access**. ### Generating a provisioning profile with Xcode Xcode automatically generates an App ID for your project that matches your project's unique bundle ID. An App ID identifies one or more of your apps: it can be an explicit App ID that matches only one bundle identifier, or a wildcard App ID that matches multiple ones. With automatic signing enabled, Xcode also creates and manages a provisioning profile for your project automatically (sometimes called an Xcode Managed Profile), so you can start deploying to your device without any manual steps. If you hit any issues, make sure the device is eligible (for example, you'll get an error if the device doesn't match the deployment target) and that your app is connected to the correct team. To generate a provisioning profile using Xcode: 1. Select your project file from Xcode's project navigator. 1. Go to the **Signing & Capabilities** tab and select your correct team from the **Team** menu. 1. Build your project in Xcode. To download a provisioning profile from Xcode: 1. Start Xcode. 1. Choose **Xcode > Settings**. 1. In the toolbar, click **Accounts**. 1. Select your Apple Account and team, then click **Download Manual Profiles**. 1. Your profiles are downloaded to `~/Library/MobileDevice/Provisioning Profiles/`. ### Generating a provisioning profile manually To generate a provisioning profile manually, you need a working Apple Developer account, and you need to set up an App ID for your project. #### Setting up an App ID 1. If you haven't already created an App ID for your project, go to [developer.apple.com](https://developer.apple.com) and log in. 1. Select **Certificates, Identifiers & Profiles** from the left sidebar. 1. Navigate to **Identifiers > App IDs**. 1. In the **App ID Description**, add a recognizable name for your App ID. 1. Select **Explicit App ID** and add your bundle identifier to the field. 1. Select any additional **App Services** that you need. 1. Click **Continue**. #### Generating a provisioning profile 1. Go to [developer.apple.com](https://developer.apple.com) and log in. 1. Select **Certificates, Identifiers & Profiles** from the left sidebar. 1. Navigate to **Profiles**. 1. Select the **+** from the top-right corner. 1. For development, select the correct project type under `Development`, or for distribution, select the correct one under `Distribution`, and click **Continue**. 1. Select the App ID you would like to use, and click **Continue**. 1. Select the certificates you wish to include in the provisioning profile. These certificates will be able to build with this profile. Click **Continue**. 1. Select all the devices you would like to use with this profile and click **Continue**. 1. Name your provisioning profile and click **Generate**. 1. Your profile is generated. Download it and double-click it to install it on your Mac. --- ## iOS code signing for Ionic and Cordova projects Naturally, Bitrise supports iOS applications built with either **Ionic** or **Cordova**. However, the code signing process is slightly different compared to a native Xcode project. Bitrise supports both manual and automatic provisioning for Ionic and Cordova apps as well - and once again, the processes are somewhat different. ### Ionic/Cordova code signing with manual code signing asset management 1. Generate the native Xcode project locally from your Ionic or Cordova project by calling `cordova platform add ios` or `ionic cordova platform add ios`. 1. Upload the files to [bitrise.io](https://www.bitrise.io): open the **Project settings** page and select **Code signing** on the left. Upload a certificate and a provisioning profile. 1. Make sure you have the **Certificate and profile installer** Step in your Workflow. 1. Add the **Generate cordova build configuration** Step to your Workflow. It must come after the **Certificate and profile installer** Step. 1. Fill in the required inputs for the Step. Please note that both the **Code Signing Identity** and the **Provisioning Profile** are required inputs for iOS apps even though they are not marked as such. - **Build configuration**: you can set it to either `debug` or `release`. - **Code Sign Identity**: enter a Developer or a Distribution identity. - **Provisioning Profile**: enter the appropriate provisioning profile. - **Packaging Type**: this controls what type of build is generated by Xcode. Set the type of code signing you need. 1. Add the **Cordova archive** or the **Ionic archive** Step to your Workflow. 1. Fill in the required inputs. - The **Platform** input needs to be set to: `device`. - The **Build command configuration** input must match the **Build configuration** input of the **Generate cordova build configuration** Step. This Step must come after the **Generate cordova build configuration** Step in the Workflow. 1. Run your build! ### Ionic/Cordova code signing with automatic code signing asset management 1. Make sure your .p12 signing certificates are uploaded to [bitrise.io](https://www.bitrise.io). 1. Add the **Cordova prepare** or the **Ionic prepare** Step to your Workflow. These Steps call the `platform rm` and `platform add` commands. 1. Add the **[Manage iOS Code Signing](https://www.bitrise.io/integrations/steps/manage-ios-code-signing)** Step to your Workflow. If you have both the **Certificate and Profile Installer** and the **Manage iOS Code Signing** Steps in your Workflow, your build might encounter unexpected issues. The Step will export: - The project’s development team. - The installed codesign identity’s name. - The installed provisioning profile. :::caution[One code signing Step only] If you have both the **Certificate and profile installer** and the **Manage iOS Code Signing** Steps in your Workflow, your build might encounter unexpected issues. ::: 1. Select the **Apple service connection method** (based on the [Apple service you have set up in Bitrise](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services)) and the **Distribution method**. 1. Add the **Generate cordova build configuration** Step to your Workflow. 1. Configure the Step to use the code signing settings exported by the **Manage iOS Code Signing** Step: **Development distribution example**: ```yaml - generate-cordova-build-configuration: inputs: - development_team: $BITRISE_DEVELOPER_TEAM - package_type: development - code_sign_identity: iPhone Developer - configuration: debug ``` **Production distribution example**: ```yaml - generate-cordova-build-configuration: inputs: - development_team: $BITRISE_DEVELOPER_TEAM - package_type: app-store - code_sign_identity: iPhone Developer - configuration: release ``` 1. Add the **Cordova Archive** or the **Ionic Archive** Step to your Workflow. 1. Fill in the required inputs. - The **Platform** input needs to be set to: `device`. - The **Build command configuration** input must match the **Build configuration** input of the **Generate cordova build configuration** Step. 1. Run your build! --- ## iOS code signing To install your iOS app on a new device or to [distribute your app to App Store](/bitrise-ci/deploying/ios-deployment/deploying-an-ios-app-to-app-store-connect), you will need to provide code signing files. The code signing of iOS projects requires: - Signing certificates issued by Apple. - Provisioning profile file(s) matching your project (team ID, bundle ID, and so on). :::note[Broken builds] If your builds break down and you suspect code signing issues, check out [our troubleshooting page](/bitrise-ci/code-signing/ios-code-signing/troubleshooting-ios-code-signing). ::: | Methods | How it works | When to use it | | --- | --- | --- | | [Automatically managed provisioning profiles (recommended)](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning) | You only need to upload the code signing certificate(s) to Bitrise and to establish an [Apple Service connection](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) (either via App Store Connect API key or through an Apple ID). Bitrise will download, create or renew the provisioning profile(s) and handle App ID and test device registration automatically. | This is the recommended option for most apps. With this option, managing your provisioning profiles is seamless and it's much easier to set up your Workflows. | | [Manually managed provisioning profiles](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---manual-provisioning) | You need to upload the code signing certificate(s) and also the provisioning profile(s) to Bitrise and keep the provisioning profile(s) updated with your iOS project. | Choose this option if:You cannot connect your App Store Connect API key or Apple ID to Bitrise.You store or handle your code signing files in a unique way.You wish to use code signing files from multiple Apple Developer Accounts. | --- ## Managing iOS code signing files - automatic provisioning On Bitrise, we're aiming to make iOS code signing as simple as possible for you. As such, we've done our best to automate a lot of the process. Several of our Steps have a built-in option for automatic code signing management to make configuration a lot more streamlined. Automatic code signing in this context means automatically managing the provisioning profiles that are available on your Apple Developer Portal account. If you set up some form of authentication to your Apple account, Bitrise can download and install the provisioning profile for your app during the build process. To use this feature, you need to: 1. [Upload the code signing certificates to Bitrise.](#uploading-ios-code-signing-certificates-to-bitrise) 1. Connect your Apple Developer Portal account to Bitrise either via [Apple ID](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) or via the [App Store Connect API](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key). 1. [Use one of the Steps that support automatically managing code signing assets.](#configuring-the-steps-for-automatic-provisioning) ### Uploading iOS code signing certificates to Bitrise All iOS code signing methods require you to export and upload your iOS code signing certificates to Bitrise. :::tip[Generating code signing files] If you don't have the necessary code signing files ready, you can generate new files: [Generating iOS code signing files](/bitrise-ci/code-signing/ios-code-signing/generating-ios-code-signing-files) ::: To upload the certificates to Bitrise, first you need to export the files in the .p12 file format. Once you successfully exported the files, you need to upload them to Bitrise. You have two options: - [Via an API call](/bitrise-ci/api/managing-ios-code-signing-files#uploading-an-ios-code-signing-file). - Uploading it manually. This guide focuses on this option. :::important[Upload the distribution AND the development signing certificates] We strongly recommend uploading BOTH the development and distribution signing certificates for your project. If you don't have an uploaded development signing certificate, Steps with automatic provisioning options will generate one on the fly every time you start a build. This can eventually lead to reaching the maximum number of certificates, blocking you from starting new builds. ::: To export your certificates and upload them to Bitrise in the Workflow Editor: 1. Make sure you have your .p12 certificates exported and ready. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select the **Code signing** menu option. 1. Click **Add .p12 file** to add a certificate. 1. In the dialog box, drag and drop the certificate file onto the field, or click the field to browse your files. ![Add .p12 file dialog](/img/code-signing/ios-code-signing/2026-07-14-add-p12-file.png) :::important[Certificate password] If your certificate is protected by a password, you need to set the password here, too. ::: 1. When done, click **Continue**. 1. Check the summary and if everything is okay, click **Add certificate**. ### Apple services authentication for automatic provisioning To take advantage of the Bitrise Steps that offer built-in, automated iOS code signing options, you need to set up [Apple service authentication](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). For these Steps, you have two options. | Authentication method | How it works | When to use | | --- | --- | --- | | [API key authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) (recommended) | You connect your App Store Connect account to Bitrise using an API key. | We recommend using this option unless you are using an account with Apple Developer Enterprise Program. If you do not receive the option to create an API key and the request access is greyed out, you need to contact your account holder to accept a license agreement with Apple to use API authentication. | | [Apple ID authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) | You connect your Apple ID to Bitrise. If two-factor authentication is enabled on your Apple account, you will have to provide the App-specific password during this process. Your authentication expires in 30 days and you will have to refresh the connection. | You should only use this solution if: - You cannot access API key for any reason. - you are using an account with Apple Developer Enterprise Program. You can also consider using [manual provisioning](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---manual-provisioning). | ### Configuring the Steps for automatic provisioning There are two ways to handle automatic provisioning on Bitrise: - Using the official Xcode Steps that can both manage code signing files and build your app. - Using the **Manage iOS Code Signing** Step. The following table describes the use cases for the two methods. To be able to configure the necessary Steps, check out either: - [Using the Xcode Steps](#using-the-xcode-steps) - [Using the Manage iOS Code Signing Step](#using-the-manage-ios-code-signing-step) :::important[Don't use the Certificate and profile installer Step] If you use automatic provisioning, you never need to use the **Certificate and profile installer** Step. ::: | Steps | How they work | When to use | | --- | --- | --- | | Xcode Steps: - **Xcode Archive & Export for iOS** - **Export iOS and tvOS Xcode Archive** - **Xcode build for testing for iOS** | These Steps set up code signing in your Xcode project automatically with nearly zero configuration. | We recommend using these Steps in most scenarios. | | **Manage iOS Code Signing** Step | This Step will set up code signing in your Xcode project before running a build. | You can use this dedicated Step if: - You are building the app from script or fastlane. - You have a cross-platform project. For example, React Native, Flutter, Ionic or Cordova. - You are building a macOS app. | #### Using the Xcode Steps You can use any of the Xcode Steps with built-in automatic management of code signing assets. 1. Set up connection to Apple services. You can choose between [API key authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) or [Apple ID authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id). We generally recommend API key authentication. 1. Add any of the following Steps to your Workflow, depending on what you need: - **Xcode Archive & Export for iOS**: Builds your Xcode app and exports an IPA of the type you choose. - **Export iOS and tvOS Xcode Archive**: Exports an IPA from an already existing archive. - **Xcode build for testing for iOS**: Builds your Xcode app with the `build-for-testing` action. 1. Set the **Automatic code signing method** input to the Apple service authentication type you set up. For example, if you chose API key authentication, choose the **api-key** option. **YAML example for setting code signing method** In this example, the **Xcode Archive & Export for iOS** Step is set to use API key authentication. ```yaml - xcode-archive@4: inputs: - automatic_code_signing: api-key ``` In most cases, the default values for all other inputs are sufficient if you set up your Apple connection correctly. #### Using the Manage iOS Code Signing Step Use our dedicated Step for automatically managing code signing assets if you do not use one of the Xcode Steps to build your iOS app, or if you have a cross-platform app. 1. Add the **Manage iOS Code Signing** Step after any dependency installer Step in your Workflow, such as **Run CocoaPods install** or **Carthage**. ![manage-ios-code.png](/img/_paligo/uuid-1b7bc413-da80-4910-5b25-f2a057bbf4d0.png) 1. Set the **Apple service connection method** input to the Apple service connection you want to use. You can choose between [API key authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-step-inputs#authenticating-in-a-step-with-api-key) or [Apple ID authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-step-inputs#authenticating-in-a-step-with-apple-id-and-password). 1. If you use Apple ID authentication, you should also enter your team ID to **The Developer Portal team ID** input. 1. Make sure you do NOT modify your Xcode project after this Step. For example, don't change the bundle ID. 1. Add a Step that builds and archives the app, such as the **fastlane** Step. ### Generating export options plists The `ExportOptions.plist` file is automatically generated based on the [Xcode Archive for iOS](https://bitrise.io/integrations/steps/xcode-archive) Step inputs. You can, however, override these inputs and use it in the **Xcode Archive & Export for iOS** Step. 1. Open your project on a local development machine Xcode. 1. Archive the project. 1. In the Organizer, select the newly created `.xcarchive` file. Click **Distribute App** to export it into an IPA file. Xcode will copy the used `ExportOptions.plist` file next to the generated IPA file. 1. Open this `ExportOptions.plist` file in your favorite text editor and copy its content. 1. Paste its content to the **Xcode Archive & Export for iOS** Step's **Export options plist** content input. **An example plist file:** ```xml destination export method debugging signingStyle automatic stripSwiftSymbols ``` --- ## Managing iOS code signing files - manual provisioning To manage your code signing files manually, you need to upload your .p12 signing certificates and the app's provisioning profiles to Bitrise. You always need to upload at least a Developer certificate and a Development type provisioning profile! That is necessary for our Xcode Steps to be able to test and build your apps properly. :::tip[Generating code signing files] If you don't have the necessary code signing files ready, you can generate new files: [Generating iOS code signing files](/bitrise-ci/code-signing/ios-code-signing/generating-ios-code-signing-files) ::: To upload the code signing files to Bitrise, first you need to export the files in the .p12 file format. Once you successfully exported the files, you need to upload them to Bitrise. You have two options: - [Via an API call](/bitrise-ci/api/managing-ios-code-signing-files#uploading-an-ios-code-signing-file). - Uploading it manually to Bitrise. This guide focuses on this option. To manually upload your code signing files to Bitrise: 1. Make sure you have your .p12 certificates and provisioning profiles exported and ready. Check out [Exporting iOS code signing files](/bitrise-ci/code-signing/ios-code-signing/exporting-ios-code-signing-files-without-codesigndoc) for more information. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Code signing** from the menu. 1. Add your files: - To add a certificate, click the **Add .p12 file** button. In the dialog box, upload the file and, if required, provide the password for the certificate. - To add provisioning profiles, click the **Add profile(s)** button. In the dialog box, upload the file(s). 1. Make sure you have the [**Certificate and profile installer**](https://github.com/bitrise-steplib/steps-certificate-and-profile-installer) Step in your app’s Workflow. You can check it on the **Workflow** tab of the Workflow Editor. Please note that these Steps must be **BEFORE** the Steps that archive and export your app (for example, [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive)) in your Workflow. ![certificate_and_profile_installer.png](/img/_paligo/uuid-fda915ec-d2ed-00a0-707c-b8a120221095.png) --- ## Protecting your code signing files You can set your code signing files to **Protected** mode: this means they cannot be downloaded from your [bitrise.io](https://www.bitrise.io) account. Your builds will be able to use these protected files but no one will be able to reveal them and there is no way to overwrite them: you can only delete the files and upload new ones instead. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Code signing** from the menu. 1. Locate the file you wish to make protected and open the dropdown menu by clicking the ellipsis button on the right. 1. Select the **Make protected** option. A dialog box will warn you that this change is irreversible once you confirm it. You do not need to separately save your changes. Once you are done, your only option in the file’s dropdown menu will be **Delete**. --- ## Signing an IPA with multiple code signing identities :::note Overview on iOS code signing asset management For a comprehensive overview on what Steps are available for code signing asset management, visit the [iOS code signing page](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). ::: You can create multiple IPA files with different code signing identities within a single Bitrise build. During the development of your iOS app you will need multiple types of distributions for different purposes, such as internal testing or deployment to the App Store. The good news is that this does not require setting up two separate workflows on [bitrise.io](https://www.bitrise.io). In this example we'll be setting up a Workflow to create two signed IPA files: one with the `development` and one with the `app-store` export method. :::tip[Advanced configuration options] The procedure lists the bare minimum requirements to configure these Steps to export Xcode archives. Check out the Step in the Workflow Editor or the Step's `step.yml` in GitHub to see all potential configuration options, including but not limited to overriding the Bitrise-managed automatic code signing options, recompiling from and including bitcode, or using a specific `.plist` file to configure exporting. ::: **Workflow Editor** 1. Make sure all the [necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) are available for your build. 1. Make sure you have the **[Xcode Archive & Export for iOS](https://www.bitrise.io/integrations/steps/xcode-archive)** Step in your Workflow. 1. In the list of input variables, navigate to **Distribution method** and select **development** from the dropdown menu. ![multipleexport.png](/img/_paligo/uuid-1e2babf9-a88c-0bd8-653d-9b5c7e8217a5.png) 1. Set the **Automatic code signing method** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don't do automatic code signing. - `api-key` [if you use API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` [if you use Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Add the **[Export iOS and tvOS Xcode archive](https://www.bitrise.io/integrations/steps/export-xcarchive)** Step to your Workflow. This Step reuses the archive generated by the **Xcode Archive & Export for iOS** Step and does a second export from the archive. 1. Set the **Automatic code signing method** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don't do automatic code signing. - `api-key` if you use API key authorization. - `apple-id` if you use Apple ID authorization. 1. In the list of input variables, navigate to **Distribution method** and select **app-store** from the dropdown menu. ![app-store-method.png](/img/_paligo/uuid-734ff7ef-99f2-2ad4-e962-6fb90c3f936a.png) **Configuration YAML** 1. Make sure all the [necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) are available for your build. 1. Open the Configuration YAML of your app. 1. Make sure you have the `xcode-archive` Step in your Workflow. ```yaml my-workflow: steps: - xcode-archive: inputs: ``` 1. Set the `distribution_method` input to `development`. ```yaml my-workflow: steps: - xcode-archive: inputs: - distribution_method: development ``` 1. Set the `automatic_code_signing` input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don't do automatic code signing. - `api-key` [if you use API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` [if you use Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). ```yaml my-workflow: steps: - xcode-archive: inputs: - automatic_code_signing: api-key - distribution_method: development ``` 1. Add the `export-xcarchive` Step to your Workflow. This Step reuses the archive generated by the `xcode-archive` Step and does a second export from the archive. ```yaml my-workflow: steps: - xcode-archive: inputs: - automatic_code_signing: api-key - distribution_method: development - export-xcarchive: inputs: ``` 1. Set the `automatic_code_signing` input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don't do automatic code signing. - `api-key` if you use API key authorization. - `apple-id` if you use Apple ID authorization. ```yaml my-workflow: steps: - xcode-archive: inputs: - automatic_code_signing: api-key - distribution_method: development - export-xcarchive: inputs: - automatic_code_signing: api-key ``` 1. Set the `distribution_method` input to `app-store`. ```yaml my-workflow: steps: - xcode-archive: inputs: - automatic_code_signing: api-key - distribution_method: development - export-xcarchive: inputs: - automatic_code_signing: api-key - distribution_method: app-store ``` And you're done! Feel free to add multiple **Export iOS and tvOS Xcode archive** Steps to your Workflows to create multiple different signed .ipa files if necessary. --- ## Troubleshooting iOS code signing iOS code signing can be complicated, with several potential issues. We've collected some of the most common issues and their potential solutions. Let’s look into what you can do to make sure code signing works! ### Code signing and clean virtual machines Every Bitrise build uses a clean virtual machine with no leftover files and configuration from previous builds. While you most likely have all the necessary code signing files (certificates and provisioning profiles) available on your local machine this is not the case with our virtual machines. They do not contain any code signing files relevant to your project, that is why you have to make sure: - You choose the right code signing asset management option to upload the provisioning profiles to Bitrise. From here our Steps will download the files to the virtual machine at runtime. - You upload the necessary signing certificates to the **Code Signing** tab. - You have connected your Bitrise account to the Apple Developer portal. (This step is not needed if you use the **Certificate and Profile Installer** Step.) to Apple Developer portal. If you suspect an error is related to code signing, there is almost certainly a problem with one of these three. When trying to build an iOS app on Bitrise, we strongly recommend generating an .ipa file of the app locally, on your own machine first. If that fails, the build will certainly fail on Bitrise, too. :::tip[Verbose logs] If you are getting any issues, make sure you enable the Verbose log input in your code signing asset management or building Step to get more information on the nature of the issue. ::: ### iOS code signing Steps fail Our [iOS code signing Steps](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) manage your provisioning profiles for you: they download the profiles from the Apple Developer portal and install them for you. Here’s what you can do if these Steps fail: - Before trying to use this Step, generate an .ipa file locally - with the same export method you want to use on Bitrise - to ensure that the profiles are uploaded to the Apple Developer portal. - Make sure that your Bitrise account is connected to the Apple Developer portal and that you have at least an Admin role in your Apple Developer team. ### File count limit on provisioning profiles The maximum number of provisioning profiles and .p12 certificates you can upload to the **Code Signing** tab on Bitrise is 100. If you’ve already reached this limit and wish to use even more, then here are a few tips on how to use even more provisioning profiles: - Use a Step with automatic provisioning, such as **Xcode Archive & Export for iOS**, **Export iOS and tvOS Xcode Archive**, **Xcode build for testing for iOS** , or **Manage iOS Code Signing**. These Steps only require the code signing identities (certificates with .p12 extension) to be uploaded to Bitrise. You can download the provisioning profiles from the Apple Developer portal on-the-fly during the build if you have [connected your Apple Developer account to Bitrise](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key). - You can create a .zip file containing the required certificates/profiles. In this case, you don’t need to upload any certificates/profiles on Bitrise. During the build you can download the .zip file and update the certificate/profile related inputs of the **Certificate and Profile Installer** Step to match the path to the certificate/profile on the build machine. Note that the **Certificate and Profile Installer** Step supports local paths and URLs for certificates and profiles. - You can host the profiles and certificates yourself, and only add an URL that is pointing to a given certificate/profile to the workflow. Also note that multiple URLs can be specified for both the certificate and profile inputs. Make sure you separate them with a pipe (`|`) character. ### Could not install the app on a device To install iOS apps on a given device, you have to either: - Export an IPA file with the `development` export method, with the device’s UDID registered in the provisioning profile used for the export. - Export an IPA file with the `ad-hoc` export method and install the app via the public install page generated by the **Deploy to Bitrise.io** Step. If you can't install an app on a given device: 1. Check that the device UDID is included in the app’s provisioning profile. If you use manual provisioning, check the provisioning profile you uploaded to Bitrise. 1. Check the logs to see if the **Xcode Archive & Export for iOS** Step used the provisioning profile with the device’s UDID in it. --- ## Accessing a build's configuration YAML Once you ran a build on Bitrise, you can always check the `bitrise.yml` configuration the build used. You can download it, compare it to the current `bitrise.yml` file, and you can even replace the current configuration file with the build's configuration file. To access a build's configuration file: 1. Open Bitrise CI, select a project and then select one of the builds of the project. 1. Select **Configuration YAML** on the top right. ![show-config-yaml.png](/img/_paligo/uuid-b4d1eb0b-3222-87c7-f672-82695ed71e87.png) 1. In the dropdown menu, select **View configuration YAML**. ### Checking changes in the configuration YAML On the **Configuration YAML** page of a build, you can see: - The YAML configuration used by the build. - If the build used a different configuration, you can also see the current configuration YAML. The page also shows the differences between the current configuration and the configuration used by the build: - Green means added content. - Blue means modified content. - Red means deleted content. ![compare-config-yaml.png](/img/_paligo/uuid-e0c8a32c-f635-adb8-8380-03c13b38026d.png) ### Restoring the configuration YAML You can always change the current configuration YAML to the configuration of one of your app's previous builds. This overrides the current configuration. To do so: 1. Open Bitrise CI, select a project and then select one of the builds of the project. 1. Select **Configuration YAML** on the top right. 1. In the dropdown menu, select **View configuration YAML**. 1. In the dialog, click **Restore configuration YAML**. 1. Click **Overwrite** in the confirmation dialog. ### Deleting a build's configuration YAML If you wish, you can simply delete a build’s `bitrise.yml` file. But please note that this action cannot be undone: nobody will be able to view that particular build’s `bitrise.yml` file once you delete it. 1. Open Bitrise CI, select a project and then select one of the builds of the project. 1. Select **Configuration YAML** on the top right. ![show-config-yaml.png](/img/_paligo/uuid-b4d1eb0b-3222-87c7-f672-82695ed71e87.png) 1. In the dropdown menu, select **Delete configuration YAML**. 1. In the confirmation dialog, click **Delete configuration YAML**. --- ## Configuration YAML overview Your Bitrise CI configuration is defined and stored inside YAML files. When you modify your configuration on the GUI of the Workflow Editor, you modify YAML files. The files define: - The format version of [the Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli) the build will use. The format version number determines what Bitrise CLI versions will be able to run the configuration. - The type of the project (for example, Android or iOS). - The default [source of Steps](/bitrise-ci/references/steps-reference/step-reference-id-format) used. - The [stack](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds#setting-the-stack-in-the-configuration-yaml) and [machine type](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds#setting-the-stack-in-the-configuration-yaml) of the build and of the specific Workflows or Pipelines. - [Build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/about-build-triggers) based on Git events. - App- and Workflow-level [Environment Variables](/bitrise-ci/configure-builds/environment-variables#setting-env-vars-in-the-configuration-yaml) accessible to the build. - The Workflows and Steps used in the build. The default configuration YAML file is called `bitrise.yml`. Each Bitrise project has a `bitrise.yml` file. You can find detailed reference information on the `bitrise.yml` file: [Configuration YAML reference](/bitrise-ci/references/configuration-yaml-reference). :::tip[Work on your configuration locally] The [offline Workflow Editor](/bitrise-ci/bitrise-cli/installing-and-upgrading-the-offline-workflow-editor) runs on your own computer: you can edit your project's configuration YAML file without logging in to [bitrise.io](https://www.bitrise.io/), and your configuration never leaves your network. It offers most features of the Workflow Editor. ::: Configuration YAML files can be stored on: - The Bitrise website. This is the default setting. - Your own Git repository. When you store your configuration in your own Git repository, the [Workflow Editor can push changes directly to it from the browser](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#updating-a-bitriseyml-stored-in-the-repository): select a branch to load, make your changes, and commit back without leaving Bitrise. This feature is available for repositories hosted on GitHub and GitLab. Bitbucket Cloud doesn't support it. If you store your YAML configuration in your own Git repository, you can also use a modular YAML configuration. This means that in addition to the default `bitrise.yml` configuration file, you have one or more additional YAML files containing additional configuration. This allows breaking down large configurations into smaller, modular components, as well as efficient reuse of configuration segments across multiple different repositories and Bitrise projects: [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration). :::important[Enterprise only] A modular YAML configuration is only available to Workspaces on an [Enterprise plan](https://bitrise.io/pricing). For now, it is not available if you store your YAML configuration on bitrise.io. ::: --- ## Customizing your configuration YAML :::note[Full reference] This is a basic reference for the most important aspects of CI/CD configuration in YAML. For the full reference, see [Configuration YAML reference](/bitrise-ci/references/configuration-yaml-reference). ::: Any tool that can edit a configuration YAML file can add custom properties to it. This way you can add special properties or notes to your [Env Vars](/bitrise-ci/configure-builds/environment-variables), or even try new configurations of your Workflow. All you have to add is add a `meta` field and a namespace label with key and value to the right place. Use the following format to add custom values to your configuration: ```yaml KEY: "VALUE", opts: { title: "My env var" description: "Description of my env var." summary: "Summary of env var." ... meta: { custom_namespace_id_1: { key1: "value1", key2: "value2", ... } custom_namespace_id_2: { ... } } ``` **Using your own version of the Workflow Editor** You can fork our Workflow Editor and use your own version of it. Then you can use `meta`: for example, let's say you want to keep an eye on one of the Environment Variables (Env Var), you want to know when it was last modified and by who. ```yaml app: envs: - ASXaS: "`ZX`ZX" opts: is_expand: false meta: audit: # used by the Audited Workflow Editor imaginary tool: that works like the WFE but it also saves the modifier and modification date, and displays it last_modified_at: 2018.09.12. last_modifier: Jane Doe ``` **Adding background color to an Environment Variable** You can use `meta` to add background color to an env var in your own tool: ```yaml meta: { my_fancy_new_workflow_editor: { env_var_background_color: "red" } } ``` When you change the stack configuration on the Workflow Editor UI, you modify `meta`under the hood. In this example, the `deploy` Workflow is configured to run on Xcode 16.1. ```yaml workflows: deploy: steps: - activate-ssh-key@4: run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' - git-clone@4: {} - script@1: title: Do anything with Script step - deploy-to-bitrise-io@1: {} meta: bitrise.io: stack: osx-xcode-16.1.x ``` Since this meta is only interpreted on [bitrise.io](https://www.bitrise.io/) and not locally or on the Bitrise CLI, it is categorized by a `bitrise.io` namespace (where the stack is the key and `osx-xcode-12.1.x` is the value). The Workflow Editor always validates the saved variable and throws an error if there is a syntax error, but with `meta` added, its content is fully ignored by the Workflow Editor validation process. --- ## Editing a modular configuration in the Workflow Editor If your configuration is split across several YAML files with the `include` keyword, you don't have to leave the Workflow Editor to change one of them. The editor loads your whole file tree: you can read the merged configuration, edit individual modules, and push every change back to your repository in one step. :::important[When you get the modular editor] The Workflow Editor switches to the modular experience automatically when all of the following are true: - Your configuration is modular: it has at least one `include`. - You [store your configuration in your own repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository), not on bitrise.io. - Your Workspace is on an Enterprise plan. In every other case, the Workflow Editor works exactly as it does for a single-file configuration. ::: For the `include` keyword, nesting, and merge rules, see [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration). ### Merged config and module views The modular editor adds one tab for the merged configuration, plus one tab for each module you open. The **Merged config** tab shows your entire configuration with every module assembled and every property resolved: the configuration that actually runs. It's read-only by design, so that every change stays traceable to the file that owns it. You can start builds here. A module tab shows a single file. Inside an editable module, entities that the file only refers to are read-only: a Workflow defined in another module shows up here, but you edit its definition in the module that owns it. | **Surface** | **What you see** | **Editing** | **Starting builds** | | --- | --- | --- | --- | | Merged config | The full, resolved configuration | Read-only | Yes | | A module in your repository | What the file defines, plus references to entities defined elsewhere | Full editing | No | | A module from another repository, branch, tag, or commit | What the file defines | Read-only | No | ### Finding the module you need to edit You don't have to know which file defines what. Start in **Merged config** and let the editor tell you. 1. Open the Workflow Editor and stay on the **Merged config** tab. 1. Find the Workflow, Pipeline, or other entity you want to change. Every card shows the module that defines it, for example `Defined in .bitrise/workflows/deploy.yml`. 1. Select the entity, then click **Edit definition**. The editor opens the module that defines it in a new tab, with the entity selected. ![The Merged config tab with a Workflow selected, showing the module that defines it and the Edit definition action](/img/configuration-yaml/2026-08-05-modular-merged-config-defined-in.png) If an entity is defined in more than one module, **Edit definition** lists those modules in merge order so you can pick the one you want. If you already know which file you need, open it directly: click **+** on the tab bar and select the file in the **Open module** popover. The popover mirrors your repository's folder structure. ![The Open module popover showing the configuration's file tree](/img/configuration-yaml/2026-08-05-modular-open-module-popover.png) ### Editing a module Editing a module is the same as editing a single-file configuration: you can create, edit, delete, and reorder anything the file defines, on any page of the editor: Workflows, Pipelines, Step bundles, Env Vars, Triggers, Containers, Stacks & Machines. ![A module open in its own tab with an editable Workflow](/img/configuration-yaml/2026-08-05-modular-module-tab-editing.png) Two things are specific to modular configurations: - The active tab is the file you're editing. Switching tabs switches the file. The tab shows a dot while it has unsaved changes. - Entities defined in another module are read-only here. You can still change how the module you're editing uses them: you can remove a Workflow from a Pipeline, for example. To change the definition itself, use **Edit definition** to open the module that owns it. Pickers work across the whole configuration: a Workflow defined in one module can be referenced from another. ### Starting a build Start builds from the **Merged config** tab. A single module is usually an incomplete slice of the configuration: another file can add Steps or change triggers. Running from a module could run something different from what you see. ### Pushing your changes Saving pushes your changed modules together, to one branch. On GitHub and GitLab, a save is a single commit; on Bitbucket Cloud, each changed module is committed separately. 1. Click **Save changes**. 1. Check the list of changed modules in the **Push changes** dialog. Each module is listed with its full path. 1. Choose **Current branch**, or **New branch** and name it. 1. Write a commit message. 1. Click **Push changes**. ![The Push changes dialog listing three changed modules with their full paths](/img/configuration-yaml/2026-08-05-modular-push-changes-dialog.png) Only modules you actually changed are written, and read-only modules are never touched. After a successful push, the editor reloads your configuration so that any changes to `include` take effect. If someone else pushed while you were editing, and one of the modules you changed also changed in the repository, the push is rejected as a whole. None of your modules are written, so your repository is never left half-updated. :::note[Updating your repository manually] If you commit your configuration changes by hand, click **Manual update** in the push dialog. You get every changed module with a download and a copy option, and you commit them to your repository yourself. ::: ### Limitations - You can't add or remove modules from the editor. Edit the `include` list by hand in [YAML mode](/bitrise-ci/configure-builds/configuration-yaml/editing-an-app-s-bitrise-yml-file#editing-the-bitriseyml-file-online). The editor picks up the new structure after your next successful save, when it reloads the configuration. - You can't edit `include` parameters such as `path`, `repository`, `branch`, `tag`, or `commit`. Edit these in YAML mode as well. - You can't edit modules from another repository, branch, tag, or commit. You can open and read them, but you can't change them. Until the editor reloads, the file tree and the tabs show the structure from the last load, even if you have already edited the `include` list. The merged configuration reflects your edits immediately. ### Troubleshooting modular configurations #### The Workflow Editor doesn't show my modules **Cause**: Your setup doesn't meet all three conditions in **When you get the modular editor**. **Fix**: Check that your configuration has at least one `include`, that it is stored in your repository, and that your Workspace is on an Enterprise plan. If all three hold and you still get the single-file editor, [contact our support team](https://support.bitrise.io/en/articles/11689194-how-to-submit-a-ticket-to-bitrise-support). #### The field I want to edit is greyed out **Cause**: You are either on the **Merged config** tab, which is read-only, or in a module that refers to the entity without defining it. **Fix**: Select the entity and click **Edit definition** to open the module that defines it. #### I edited the `include` list, but the tabs and the file tree didn't change **Cause**: The editor reads your file structure when it loads the configuration, so it doesn't restructure itself while you type. **Fix**: Save and push your changes. The editor reloads the configuration afterwards, and the new structure appears. #### I can't start a build from the module I'm editing **Cause**: Builds always run the merged configuration, so you can't start one from a module view. **Fix**: Switch to the **Merged config** tab and start the build there. ### Related - [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration) - [Editing an app's bitrise.yml file](/bitrise-ci/configure-builds/configuration-yaml/editing-an-app-s-bitrise-yml-file) - [Storing an app's configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml) --- ## Editing an app's bitrise.yml file Your Bitrise configuration is defined in YAML files. All Bitrise projects have a root `bitrise.yml` file which defines Pipelines, Workflows, app-level Environment Variables, the trigger map, and stack types and machine types for your project. You can edit this file in three different ways: - Using the graphical UI of the Workflow Editor. Whenever you make a change in the Workflow Editor, it automatically updates your `bitrise.yml` file. - [Editing the bitrise.yml file in the Workflow Editor](#editing-the-bitriseyml-file-online). You can do so even if you [store your configuration file in your repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository). The Workflow Editor can push your changes directly your repository. - [Editing the bitrise.yml file locally](#editing-the-bitriseyml-file-locally) in an editor of your choice. You can copy the content to the online editor or push it to your repository if you store your configuration file there. :::note[Modular configurations] If your configuration is split across several files with the `include` keyword, the Workflow Editor loads every module and lets you edit them one file at a time. See [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). ::: :::important This requires some familiarity with the structure of a Bitrise configuration YAML file. Read more: [Configuration YAML reference](/bitrise-ci/references/configuration-yaml-reference). ::: ### Editing the bitrise.yml file online You can edit your build config in yml format in the **bitrise.yml editor**. To do so, open the Workflow Editor and switch to **YAML** at the top. ![The Visual and YAML toggle in the Workflow Editor](/img/2026-06-05-workflow-editor-visual-yaml-toggle.png) You can edit the file directly here. Bitrise validates your configuration: if your `bitrise.yml` file is not valid, you won't be able to save the file. To download the current `bitrise.yml` file, click **Download**. Alternatively, you can simply select certain sections of the file and copy those into either a local `bitrise.yml` file or into another project's `bitrise.yml` file. ### Editing the bitrise.yml file locally :::tip[Work on your configuration locally] The [offline Workflow Editor](/bitrise-ci/bitrise-cli/installing-and-upgrading-the-offline-workflow-editor) runs on your own computer: you can edit your project's configuration YAML file without logging in to [bitrise.io](https://www.bitrise.io/), and your configuration never leaves your network. It offers most features of the Workflow Editor. ::: Our YAML scheme is shared on [schemastore](https://www.schemastore.org/bitrise.json). This means that syntax highlight and auto-completion is available for the following files if you edit them locally: - `bitrise.yml` - `step.yml` - `bitrise.json` The following editors support the auto-complete feature: - IntelliJ IDEA - PhpStorm - PyCharm - Rider - RubyMine - Visual Studio 2013+ - Visual Studio Code - Visual Studio for Mac - WebStorm - JSONBuddy ![autocomplete.png](/img/_paligo/uuid-949123a0-1356-b913-0a17-cd7270ba78c3.png) After editing your file locally, you can copy its contents to the online `bitrise.yml` file, or [store it in your own repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository) and use the Workflow Editor to push future changes directly from the browser. --- ## Modular YAML configuration :::important[Enterprise only] Modular YAML configuration is only available for Workspaces with Enterprise plans. You also need to [store your configuration files in your own repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository), not on bitrise.io. If you are not on an Enterprise plan but interested in modular YAML, [contact us](http://www.bitrise.io/contact)! ::: Modular YAML configuration enables you to break down large, complex YAML files into smaller, modular components. It allows easier reuse across multiple repositories. By modularizing YAML files, you can quickly locate and update configurations, reducing the risk of errors and merge conflicts. A modular YAML configuration includes: - A `bitrise.yml` file in the root of your repository. - Other YAML files in the same or a different repository. To include a file from a different repository, the repository must belong to the same Git account or organization as the primary repository. - One or more `include` keywords in the `bitrise.yml` file. These point to other YAML files and bring their configuration into the main project configuration. After an additional YAML file has been included in the `bitrise.yml` file, you can refer to any of its Workflows or Pipelines as to any other Workflow or Pipeline in your configuration. ### Including configuration from multiple YAML files To create a modular configuration, you need to: 1. Store your `bitrise.yml` file in your repository. 1. Create more YAML files in addition to `bitrise.yml` and commit them to your repository. We refer to these files as configuration modules. :::important[File limit] You can have a total of 50 configuration files, including the root level `bitrise.yml` file. ::: In `bitrise.yml`, you can include the YAML configuration modules with the `include` keyword. If the module is in the same repository as the `bitrise.yml` file, the `include` keyword requires one parameter: `path` which points to the location of the module. The provided path must be relative to the repository's root: ```yaml include: - path: file/path/common.yml ``` You can include a YAML configuration module from a different repository by specifying the repository that contains the file. In addition to the `repository` property, you need to also set at least one of the following: - `branch`: The branch containing the YAML configuration module. - `commit`: The specific commit hash from which to include the YAML configuration module. - `tag`: The Git tag that points to the YAML configuration module. The repository must belong to the same Git account or organization that your project's primary repository belongs to. You can check your [Bitrise project's repository URL](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-repository-url) on bitrise.io. For example, if your repository URL is git@github.com:MyOrg/main_repo.git, you can only refer to repositories belonging to MyOrg on GitHub. You only need to refer to the repository's name. For example, you can refer to git@github.com:MyOrg/another_repo.git with the value `another_repo`. ```yaml include: - path: shared/common.yml branch: test_branch repository: another_repo ``` :::important[Accessing other repositories] Bitrise needs `read` access to all repositories where configuration YAML files are hosted. There are two ways to make sure Bitrise can access your repo: - If you use the [GitHub App](/bitrise-platform/repository-access/github-app-integration) integration, you can [link additional repositories](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app) to your project. - For other authentication methods, check out this guide: [Apps with submodules or private repo dependencies](/bitrise-platform/repository-access/apps-with-submodules-or-private-repo-dependencies) ::: ### The `include` format | Parameter | Required? | Description | | --- | --- | --- | | `path` | Required | The location of the YAML file you want to include. The path is relative to either: - The root of the repository in a CI environment. - The current directory in a local environment. | | `branch` | Optional | The branch from which to include the YAML file. | | `tag` | Optional | The tag from which to include the YAML file. If `branch` and `tag` are both specified, tag takes priority. | | `commit` | Optional | The specific commit hash from which to include the YAML file. If `branch`, `tag`, and `commit` are all specified, the commit takes priority. | | `repository` | Optional | The repository from which to pull the YAML file. You just need to set the name of the repository, not the URL. | ### Defining configuration modules A configuration module is a full YAML configuration file. That means that all configuration elements of a valid `bitrise.yml` file are available: you can define the `format_version`, app level Environment Variables, default stacks and machine types, and of course Pipelines, Stages, and Workflows in a configuration module. For example, you can create a bare minimum `bitrise.yml` file that simply points to another module: ```yaml include: - path: path/to/config_module.yml ``` And in this case, `config_module.yml` contains the entire configuration for the build: ```yaml format_version: 13 default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: android app: envs: - MY_NAME: My Name workflows: test: steps: - script: inputs: - content: echo "Hello ${MY_NAME}!" ``` A configuration module can contain any configuration entity defined on the root level. For example, a configuration module defining only a single Workflow or just app-level Environment Variables is perfectly valid. The `bitrise.yml` file: ```yaml format_version: 13 default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git include: - path: path/to/config_module.yml ``` The `config_module.yml` file: ```yaml app: envs: - USER_NAME: UserName workflows: test: steps: - script: inputs: - content: echo "Hello ${USERNAME}!" ``` However, non-root level entities cannot stand alone in a separate module file either: you can't, for example, include Step inputs like this. #### Nesting included modules You can use the `include` property in included configuration files: Root level `bitrise.yml` file: ```yaml format_version: 13 default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git include: - path: path/to/config_module.yml ``` The `config_module.yml` file: ```yaml include: - path: path/to/another_module.yml ``` The `another_module.yml` file: ```yaml workflows: ui_test: steps: - pull-intermediate-files@1: inputs: - artifact_sources: build_tests.build_for_ui_testing ``` With this configuration, you'll be able to run the `ui_test` Workflow. Nesting has the following limitations: - A depth of 10, including the root level file. - Maximum 50 configuration files in total, including the root level file. #### Merge rules for included modules When Bitrise runs a build, we merge your configuration modules into a single `bitrise.yml` file: - Included modules are read and merged into the configuration in the order defined in the root `bitrise.yml` file. - If an included module also uses include, the nested module is merged first recursively. - After all configuration files added with include are merged together, the resulting configuration is merged with the `bitrise.yml` file on the root level. As such, you can override configuration values on the root level. :::note[Switching back to bitrise.io] If you have a modular configuration with multiple YAML files and you [switch back to storing your configuration on bitrise.io](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#moving-the-bitriseyml-file-back-to-bitriseio), we use the same merge rules to merge all your files into a single `bitrise.yml` file. ::: When merging the configurations, it is possible to encounter overlaps and override included configuration values. When merging YAML modules, the most recently read file takes priority over the existing merged configuration. Here are the rules: - Items of simple types (such as integers and booleans): The value from the most recently read file is used. - Items of object type (for example, Pipelines, Stages, Workflows): - If a property is only present in the existing merged configuration, that value is retained. - If a property is present in both, and their values are hash maps, the values are merged. - In any other case, the value from the most recently read file is used. - Items of array type (for example, lists of Environment Variables or [trigger map items](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers)): if the collection is present in both the most recently read file and the existing merged configuration, the merged value is an ordered array of values, with all values from the merged configuration followed by the values from the most recently read file. You can see the merged configuration in the Workflow Editor on the **Merged config** tab. For how to open and edit the individual modules from there, see [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). **Merging rules** We have the root `bitrise.yml` file which includes a `config_module.yml` file. The `bitrise.yml`: ```yaml format_version: 13 default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: android include: - path: path/to/config_module.yml app: envs: - USER_ID: UserId - PASSWORD: SecurePassphrase ``` The `config_module.yml`: ```yaml format_version: 10 app: envs: - USERNAME: UserName workflows: test: steps: - script: inputs: - content: echo "Hello ${USERNAME}!" ``` During the merge, the `config_module.yml` and is merged into the configuration. Then the root level `bitrise.yml` is read and then merged. The final configuration looks like this: ```yaml format_version: 13 default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: android app: envs: - USER_ID: UserId - PASSWORD: SecurePassphrase - USERNAME: UserName workflows: test: steps: - script: inputs: - content: echo "Hello ${USERNAME}!" ``` - The root level `format_version` property is present in both files. The root level `bitrise.yml` file is merged into the overall configuration last, therefore its value of `format_version` is used. - The `apps` property is present in both files so all key-value pairs are added to the overall configuration. - The `test` Workflow is only present in `config_module.yml` so it's added to the overall configuration and `bitrise.yml` does not override it. --- ## Storing an app's configuration YAML :::important[YAML files size limitation] Please note that the total, combined size of the `bitrise.yml` and the `bitrise.secrets.yml` file cannot exceed 400KB. ::: There are two ways to store the configuration YAML file of your project: - Keep the file in your Git repository: with this solution, you have full control over maintaining and versioning the file. - Keep it on [bitrise.io](http://bitrise.io/): Bitrise will store your configuration, and you can access it any time on the website. With this solution, the configuration file is fully independent from your repository. You can switch between the two solutions at any time. :::note[Reference] For full configuration YAML syntax reference, see [Configuration YAML reference](/bitrise-ci/references/configuration-yaml-reference). ::: ### Storing the bitrise.yml file in your repository When you store your configuration YAML file(s) in your repository, the build process on Bitrise will use that file to run your builds. This means that: - You have full control over versioning your configuration file. - Every time you make a change to your Workflows/Pipelines or your triggers, the changes need to be committed to the file in the repository. The Workflow Editor can do this for you directly, or you can commit the file manually. You don’t need to create your own configuration YAML file in advance: you can use the file stored on [bitrise.io](https://www.bitrise.io/). The feature requires [service credential](/bitrise-platform/integrations/the-service-credential-user) integration or the [GitHub App integration](/bitrise-platform/repository-access/github-app-integration). Hosting the YA file in a privately hosted repository where neither is available needs a [workaround](#privately-hosted-repositories). :::note To store the configuration file in your repository, you need to manually commit it the first time. On subsequent changes, [you can use the Workflow Editor to commit the file directly to your repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#updating-a-bitriseyml-stored-in-the-repository) if you use GitHub or GitLab. If you use Bitbucket Cloud, you will need to commit the file manually every time. ::: 1. Open the project on Bitrise and go to the **Project settings** page. 1. Select **Collaboration**. 1. Check the **Service credential user** section. The service credential user must be a Bitrise user who has at least `read` access to the repository. :::note[GitHub App integration] If you use the [GitHub App integration](/bitrise-platform/repository-access/github-app-integration), you don't need the service credential user to store the configuration YAML file in your repository. ::: 1. Open the Workflow Editor. 1. Click the chevron next to **Stored on Bitrise** (or the branch name) in the header and select **Change storage...**. ![Change storage dialog in the Workflow Editor](/img/configuration-yaml/2026-07-06-change-storage-dialog.png) 1. When prompted to add the `bitrise.yml` to your project's repository, you have two options: - Copy the content of the current `bitrise.yml` file to the clipboard. You can then create your own file and copy the contents into it. - Download the current `bitrise.yml` file. 1. In your repository, commit the `bitrise.yml` file. You can either: - Commit the file to the root of the repository. - Commit the file to some other location. In this case you will need to provide the path on Bitrise. :::important[Default branch] The default branch of your app must always have a `bitrise.yml` file on it. You can store different `bitrise.yml` files on other branches and load any of them in the Workflow Editor: [Storing a bitrise.yml file on multiple branches in the repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-a-bitriseyml-file-on-multiple-branches-in-the-repository). You can check your Bitrise project's default branch on [bitrise.io](https://www.bitrise.io/) by going to the **Settings** tab and finding the **DEFAULT BRANCH** option. ::: 1. Back on Bitrise, set a path to your configuration file in the **Bitrise.yml location** field: - If you store the config file in the root of your repository, leave the field empty. - If you store the file somewhere else in the repository, provide the path. 1. Click **Validate and save**. :::caution[Validation] The `bitrise.yml` file in your repository always must be valid! If it contains incorrect syntax, it can break your builds. ::: If all goes well, you should receive confirmation of successfully changing your `bitrise.yml` storage settings. :::tip[Allowlist the Bitrise website IP addresses] If you use some form of self-hosted solution for storing your code, you might need to allowlist the static IP addresses of the Bitrise website and its background workers. This allows you to use such features as storing the `bitrise.yml` file in your own repository, or receiving build status updates from Bitrise: [IP addresses for the Bitrise website](/bitrise-platform/infrastructure/build-machines/configuring-your-network-to-access-our-build-machines#ip-address-ranges-for-bitrise-backend-workers). ::: #### Privately hosted repositories Unfortunately, this feature is not yet supported for users who can't use the service credential user integration or the [GitHub App integration](/bitrise-platform/repository-access/github-app-integration); for example, if the repository is is only accessible under a private IP subnet. There's a workaround, however: [Storing the bitrise.yml in a privately hosted repository](https://support.bitrise.io/en/articles/9676637-storing-the-bitrise-yml-in-a-privately-hosted-repository). For GitHub Enterprise, we offer an integration that allows you to store your `bitrise.yml` file in a GitHub Enterprise repository: [Integrating GitHub Enterprise with Bitrise](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise). #### Setting a custom path for your configuration YAML By default, Bitrise looks for your configuration YAML in the root of your repository when running builds but you can store the file elsewhere in the repository. To do so: 1. Commit the configuration YAML file to your repository. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Click the chevron next to **Stored on Bitrise** (or the branch name) in the header and select **Change storage...**. 1. In the **Bitrise.yml location** field, set the path where you committed the file. ![config-yaml-source.png](/img/_paligo/uuid-4908f90e-3721-b82f-2d79-937d6a9b14f3.png) ### Updating a bitrise.yml stored in the repository When your `bitrise.yml` is stored in your repository, the Workflow Editor can push changes directly to it. No copy-paste or manual commits required. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. If you want to edit a branch other than your default, click the chevron next to the branch name in the header and select **Switch branch...**. ![Configuration options menu in the Workflow Editor showing Switch branch, Download YAML file, and Change storage options](/img/configuration-yaml/2026-07-06-configuration-options-menu.png) 1. Make your changes in the Workflow Editor. 1. Click **Save changes** in the top right corner. 1. Choose how to save: - **Current branch**: commits and pushes directly to the branch you loaded from. - **New branch**: pushes to a new branch of your choice, useful for code review. - **Manual update**: download or copy the YAML and commit it yourself. :::note You can only push directly from the Workflow Editor if you use GitHub or GitLab. If you use Bitbucket Cloud, you will need to commit the file manually every time. If your repository has branch protection rules that require pull requests before merging, **Current branch** can fail with a generic `Failed to push changes. Please try again.` error. If you run into this, branch protection is a likely cause: use **New branch** instead, which commits your changes to a new branch and gives you a link to open a pull request from it. ::: 1. Write a commit message and click **Push changes**. ### Storing a bitrise.yml file on multiple branches in the repository When you first add the `bitrise.yml` to your repository, it must be committed to the [default branch](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-default-branch). If you store the `bitrise.yml` file in the repository, the default branch must always have a `bitrise.yml`. However, once you did the initial configuration to set up using the `bitrise.yml` from your repository, you can store `bitrise.yml` files on other branches and use any of them to run builds. If you want to build a branch of your repository on Bitrise, you need to have a `bitrise.yml` file on that branch. And don’t forget that you always need to keep a `bitrise.yml` file on the default branch. :::tip[Loading a branch in the Workflow Editor] You can load the `bitrise.yml` from any branch directly in the Workflow Editor. Select the branch at the top of the editor before making changes, and save back to that branch when you're done. ::: **Bitrise setup with bitrise.yml files on multiple branches** Let’s say you have an app called FantasticApp. In FantasticApp’s Git repository, the default branch is called `main`. There is also a `deploy` branch. Any code push or pull request to `main` triggers a Workflow called `main-workflow`. Any code push or pull request to `deploy` triggers a Workflow called `deploy-workflow`. In the repository, there is a `bitrise.yml` file on both the `main` and the `deploy` branch, containing both Workflows. When making changes to the Workflows, the FantasticApp team commits the modified `bitrise.yml` file to both branches to ensure that their Workflows are up to date on both. ### Moving the bitrise.yml file back to bitrise.io The default setting is to store the `bitrise.yml` file on [bitrise.io](http://bitrise.io/): when you add a new app, we automatically create a `bitrise.yml` file for you and it’s stored on our website. If this works for you, then you don’t need to change anything! If, however, you changed your storage settings to keep the configuration file in your repository, you can easily change it back any time to store the file on [bitrise.io](http://bitrise.io/). 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Click the chevron next to the branch name in the header and select **Change storage...**. ![git-repo-source.png](/img/_paligo/uuid-2bda7822-cd88-2b01-ff4d-8f5eec392c66.png) 1. Choose which `bitrise.yml` file should be used on [bitrise.io](http://bitrise.io/) from now. You can copy the content of the `bitrise.yml` file stored in the app’s repository. You can copy the last version of the `bitrise.yml` file that you used on [bitrise.io](http://bitrise.io/). ![yaml-source-switchback-dialog.png](/img/_paligo/uuid-82197654-17c3-6b98-320e-cf408f16c8c9.png) 1. Click **Validate and save**. If all goes well, you should receive confirmation of successfully changing your `bitrise.yml` storage settings. --- ## Build priority By default, builds run in simple chronological order: the build that was triggered first runs first. However, you can configure build priority, allowing you to fast-track critical builds to the top of the queue. You can assign numerical priorities: a value between -100 and 100. The higher value, the higher the priority of the build. A build with a higher priority is executed sooner than a build with a lower priority. By default, all builds have a priority of 0. You can set priorities for: - Pipelines and Workflows. You can assign a priority to individual Worklows or even Pipelines. Assigning a priority to a Pipeline will assign all its constituent Workflows the same priority - Triggers: Each trigger condition can be given a priority. - Manual builds: When starting a build on the UI or via the Bitrise API, you can set a priority that determines its position in the queue. :::note[Availability] The build priority feature is only available for Workspaces on Teams, Pro, and Enterprise plans. If you are not on these plans, but interested in the feature, [contact us](https://bitrise.io/contact)! ::: ### Configuring priority when starting a build manually You can set a priority when [starting a build manually](/bitrise-ci/run-and-analyze-builds/starting-builds/starting-builds-manually). The priority only takes effect if other builds are queued when you start a build. The priority set when manually starting the build overrides all other priorities. 1. Open Bitrise CI and select your project. 1. On the main project page, click **Start build**. 1. Select the **Advanced** option. ![manual-build-priority.png](/img/_paligo/uuid-9fdfc68c-9744-f7ae-fee6-b4cc984bdf3e.png) 1. Find the **Priority** field and set an integer value between -100 and 100. The default value is 0. ### Configuring priority for build triggers You can set priority for build triggers on the GUI of the Workflow Editor and in your configuration YAML file. Trigger priority overrides Pipeline and Workflow priority. **Workflow Editor** 1. Open the Workflow Editor. 1. Select the Workflow or Pipeline you need. 1. Go to the **Triggers** tab. 1. Create a new trigger or edit an existing one and find the **Priority** input. ![trigger-priority.png](/img/_paligo/uuid-02de5b3a-d9bd-5890-cfc3-52462a3c8ff2.png) 1. Set an integer value between -100 and 100: higher number means higher priority. The default value is 0. **Configuration YAML** 1. Open your configuration YAML file. 1. Find a trigger in a Pipeline or Workflow. 1. Add the **priority** input with an integer value between -100 and 100: higher number means higher priority. The default value is 0. ```yaml workflows: primary: steps: - activate-ssh-key: {} - git-clone: {} - deploy-to-bitrise-io: {} triggers: push: - branch: main priority: 10 ``` ### Configuring priority for Pipelines and Workflows You can configure priority by setting a value between -100 and 100 for the **Priority** property of any given Workflow or Pipeline. The default value is 0. Pipeline priorities override Workflow priorities. If a pipeline is triggered and assigned a priority, all constituent workflows will be triggered with the same priority. #### Configuring Pipeline priority **Workflow Editor** 1. Open the Workflow Editor. 1. On the left, select **Pipelines**. 1. Select the Pipeline you need and click **Properties**. 1. Select the **Properties** tab. ![pipeline-priority.png](/img/_paligo/uuid-c92f6dbc-0dee-4ec9-3680-53b83a30f2a2.png) 1. In the **Priority** input field, provide an integer between -100 and 100. The default value is 0. **Configuration YAML** 1. Open your Configuration YAML file. 1. Find the Pipeline you need and add a `priority` input with an integer value between -100 and 100. If you don't have a `priority` input set, the Pipeline will have a default priority of 0. ```yaml pipelines: best-pipeline: priority: 10 ``` #### Configuring Workflow priority **Workflow Editor** 1. Open the Workflow Editor. 1. On the left, select **Workflows**. 1. Select the Workflow you need from the dropdown menu and select the **Properties** tab on the right. ![workflow-priority.png](/img/_paligo/uuid-19da748e-432f-46b4-353f-a426a92cdd75.png) 1. In the **Priority** input field, provide an integer between -100 and 100. The default value is 0. **Configuration YAML** 1. Open your Configuration YAML file. 1. Find the Workflow you need and add a `priority` input with an integer value between -100 and 100. If you don't have a `priority` input set, the Workflow will have a default priority of 0. ```yaml workflows: best-workflow: priority: 10 ``` ### Order of precedence for priority settings You can set priority levels for: - Pipelines and Workflows. - Triggers. - Manually triggered builds. These priorities can conflict. For example, you have a Workflow called test. It has a priority of 10. You also have a trigger configured for this Workflow: it is triggered if code is pushed to the development branch. This trigger has a priority of 15. In such a scenario, Bitrise determines the build priority by the order of precedence: 1. Manual overrides: Manually starting a build overrides all other priority settings. 1. Trigger-specific priority settings: A trigger's priority setting overrides the priority settings of the Pipelines or Workflows it triggers. 1. Pipeline-level priority settings: The Pipeline's priority overrides the priority settings of its constituents Workflows which are all given the same priority as the Pipeline. 1. Workflow-level settings: If no other configuration element is given a priority setting, the Workflow priority determines overall build priority. Here’s an example snippet that shows how to set priorities at various levels: ```yaml workflows: A: steps: [] B: steps: [] priority: 4 triggers: push: - branch: release priority: 2 - branch: development pipelines: P: priority: 3 workflows: A: {} B: {} ``` In this example: - If Workflow A is run as a standalone build, it has a priority of 0 (the default priority value). - If Workflow B is run as a standalone build (for example, if code is pushed to the `development` branch), it has a priority of 4. - If code is pushed to the `release` branch, Workflow B is triggered with a priority of 2. - If Pipeline P is triggered, both A and B Workflows will run with priority 3. --- ## Configuring email notifications Notifications are updates about your activity on Bitrise. Usually, they concern the state of your builds but you can receive notifications about a lot of different things. Our built-in email notification system sends emails about builds to every user who is assigned to work on an application. They are sent when a build is finished and they can be configured for both successful and failed builds. :::important[Watching the app] To receive automatic email messages, [you need to be watching the app](/bitrise-ci/configure-builds/configuring-build-settings/configuring-email-notifications#watching-a-project). If you turn off watching, you won’t receive the automated emails. ::: Email notifications are automatically set up for all applications when first creating them but you can modify these notification settings at any time: [Changing your email notification settings](#changing-your-email-notification-settings) The alternative solution is to send emails via a dedicated Step. This allows for far more customization regarding the notifications: [Sending emails with a Step](#sending-emails-with-a-step) ### Watching a project Watching a Bitrise project means getting email notifications for that project. Turning off watching the project means you won't get automatic notifications. To enable watching: 1. Open [Bitrise CI](https://app.bitrise.io/ci). 1. From the project list on the right, select your project. 1. On the left, toggle **Watching**. ![watching-app.png](/img/_paligo/uuid-ed3b91d2-8138-ca73-f9f2-048ab808f5ca.png) ### Changing your email notification settings Email notifications are automatically set up for all projects when first creating them. There are three possible settings for both successful builds and failed builds: - **Always**. This is the default setting for failed builds. - **Never**. - **Send email when build status changes on the same branch**. This is the default setting for successful builds. This means that if build #1 and build #2 both succeeded, you will not get a notification about build #2. However, if build #3 fails and then build #4 succeeds again, you will be notified. You can change your email notification settings at any time - you can even completely disable them. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Notifications**. 1. Scroll down to email notifications. ![notifications.png](/img/_paligo/uuid-c56aac7c-384f-7b63-c38e-216a32143c86.png) 1. Select the settings you need for both successful and failed builds from the appropriate dropdown menu. For example, if you want to disable receiving notifications, set both options to **Never**. ### Sending emails with a Step The **Send Email with Mailgun** Step can send emails to any email address with customized updates, in either HTML or plain text format. You can use environment variables to send information, as well as attach files to the emails. To use the Step, you need: - A Mailgun account. - A Mailgun API key. - Your Mailgun domain name. :::important[Make sure the Step runs in every build!] If you use the **Send Email with Mailgun** Step in your workflow, make sure that [it is always set to run even if the previous Step failed](/bitrise-ci/workflows-and-pipelines/steps/skipping-steps)! This is the default setting of the Step. If you change it, you will not receive emails if your builds fail. ::: 1. Create a Secret Environment Variable that holds your Mailgun API key. We recommend naming the key `$MAILGUN_API_KEY`. This is the default value of the Step’s relevant input. 1. Create a Secret Environment Variable that holds your Mailgun domain. We recommend naming the key `$MAILGUN_DOMAIN`. This is the default value of the Step’s relevant input. 1. Add the **Send Email with Mailgun** Step to the end of your workflow. 1. Find the **Send To emails** input of the Step. Click on the input and then click **Select secret variable**. 1. Create a new Secret Environment Variable that contains the list of the email addresses. You can choose any key you want. The addresses should be separated by a comma. ![Configuring_notifications.png](/img/_paligo/uuid-a7bfa471-3a28-7bb4-0335-cffbacb0bd8a.png) 1. Set the email subject, and the two potential email messages: one for a successful build, one for a failed build. - You can insert environment variables to any of the inputs (the subject and the messages). In the email, the values of the variables will be displayed. - The default messages will send the name of the app, the number of the build and whether the build succeeded or failed. 1. Attach files, if necessary: the **File attachments** input accepts a file path or an environment variable as input. Multiple files can be attached: separate their paths with commas. Run a build - and check your emails! --- ## Configuring Slack integration You can send Slack messages during a Bitrise build to individual users, groups or channels with the [**Send a Slack message**](https://github.com/bitrise-io/steps-slack-message) Step. Customize the messages, include attachments, and link buttons that will take the users to the build page. To use the Step to send messages: 1. Set up the [workspace Slack integration](/bitrise-platform/workspaces/workspace-slack-integration) and [get the integration ID](/bitrise-platform/workspaces/workspace-slack-integration). The Step needs the integration ID. 1. Add the [**Send a Slack message**](https://github.com/bitrise-io/steps-slack-message) Step to your Workflow. 1. Make sure that [it is always set to run even if the previous Step failed](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally)! This is the default setting of the Step. If you change it, messages won’t be sent if the build fails. 1. Find the **Workspace Slack Integration ID** input and add the integration ID. 1. Customize your Slack message with the relevant inputs of the Step. There are several options, including but not limited to: - Setting the target channel, group or username: this can be a name or an encoded ID. - The text of the message to send. - The bot’s username for the message - The message’s color - File attachment - Link buttons attached to the message Check out all the inputs in the Workflow Editor to see all the ways in which you can customize your Slack messages. --- ## Configuring tool versions Bitrise can automatically set up any tools with the right version for your CI project. For example, most CI workflows often start with installing the right version of Ruby or Node.js that is compatible with the project. There are two ways to set up tools: - A declarative, YAML-based method: add your tool and its version to the `tools` property on the top level of your configuration YAML file. We recommend getting started with this method: [Declarative tool setup](#declarative-tool-setup). - Installation during Workflow execution: either via a purpose-built Bitrise Step or a script that runs a CLI subcommand: [Tool setup during Workflow execution](#tool-setup-during-workflow-execution). To help you choose the right approach, consider the differences and limitations of each method: | Declarative config | Workflow execution | | --- | --- | | Executed automatically before the first Step of a Workflow. | Executed manually within the Workflow. Can be executed in the middle of the Workflow. | | Can't read config from version files: tool setup is executed before the [**Git Clone**](https://github.com/bitrise-steplib/steps-git-clone) Step. Tool versions are defined in two files (version file and your configuration YAML file). | You can read the configuration from version files if you run the command after the [**Git Clone**](https://github.com/bitrise-steplib/steps-git-clone) Step. For reusability, we recommend [creating a `step bundle`](/bitrise-ci/workflows-and-pipelines/steps/step-bundles) and reference that in all Workflows. | | No additional configuration required: tools automatically become available in `$PATH` in Workflow Steps. | Our dedicated Step requires no additional configuration. If you use your own script, shell sourcing is required before the tools become active in the current shell or script step (see details below). | | Doesn't configure the local development environment (except when running Workflows locally via `bitrise run workflow_name`). | Configures the local developer environment if tools versions are defined in a version file (for example, `.ruby-version`) and everyone in the team has a tool version manager set up (for example, `Mise`). | ### Declarative tool setup Add your tool and its version to the `tools` property on the top level of your configuration YAML file.: ```yaml tools: nodejs: 22:latest ruby: 3.3:installed golang: 1.24.5 workflows: # ... ``` When running a build, tool setup is executed before the first Step of the Workflow. You can see it in a build log: ![20250808-build-log-tool-setup.png](/img/_paligo/uuid-b80417cb-80b7-3d51-5609-11f078c68a79.png) There are three ways to define version numbers for the tools you want to set up at the start of a build: - [Set exact version numbers](#setting-exact-version-numbers). - [Set partial version numbers](#setting-partial-version-numbers). - [Use special aliases](#using-other-aliases). #### Setting exact version numbers You can define an exact version number in your `tools` property: ```yaml tools: nodejs: 22.1.0 ``` This provides the most deterministic behavior and reproducible builds, but installs could take a long time. #### Setting partial version numbers If your project doesn't require precise tool versions, you can define partial version numbers. With a partial version version number, Bitrise will check for either a version preinstalled on the Bitrise build machines or the latest released version available. For a preinstalled version of a tool, use the `x.y:installed` syntax: ```yaml tools: ruby: 3.3:installed ``` This checks which Ruby 3.3 patch version is preinstalled on the Bitrise build machines and uses that version. If no preinstalled version matches the partial version, the highest matching version is going to be downloaded and installed at runtime. It will not result in a build failure. For the latest released version of a tool, use the `x.y:latest` syntax: ```yaml tools: ruby: 3.3:latest ``` This installs the latest 3.3 patch version of Ruby, regardless of what is preinstalled on the Bitrise build machines. #### Workflow-specific definitions You can define tool version definitions globally or for one or more Workflows specifically. Instead of defining the `tools` property at the top level of the configuration, you nest it under one or more Workflows. You can also unset some tools for certain Workflows with the keyword `unset`. Unsetting means that tool won't be installed for that Workflow. Unsetting has no effect in the global context. We recommend using one of three common patterns when using Workflow-specific definitions: - Workflow-specific definitions only: ```yaml workflows: test: tools: nodejs: 22:installed ``` In this example, the `test` Workflow uses the highest preinstalled version of Node.js v22. No global tool definitions are set. - Override the global definition in one or more Workflows: ```yaml tools: nodejs: 22:installed ruby: 3.3:installed workflows: test-latest-node: tools: nodejs: "24.7.0" ``` In this example, the global setting is the highest preinstalled version of Node.js v22. The Workflow `test-latest-node`, however, uses Node.js version 24.7.0. - Unset global tool versions in one or more Workflows: ```yaml tools: nodejs: 22:installed ruby: 3.3:installed workflows: lint: tools: ruby: unset # this workflow only needs Node.js ``` In this example, the Workflow called `lint` won't have Ruby installed. #### Using other aliases It’s also possible to use the special `latest` and `installed` version strings to select the highest released or highest installed version of a tool: The `installed` value means using the highest installed version at the time of build: ```yaml tools: ruby: installed ``` The `latest` value means using the highest released version at the time of build: ```yaml tools: nodejs: latest ``` ### Tool setup during Workflow execution To perform tool setup during Workflow execution, you can use a purpose-built dependency installer Step or a CLI subcommand that you call from your own scripts. #### Tool setup with CLI subcommand Call the `bitrise tools setup` from your Workflow. The tool looks for configuration or version file paths: if you don't specify a path, the tool detects files in the working directory. In the example, we're calling the command from a **Script** Step with a `--config` flag that finds the `.tool-versions` file. ```yaml workflows: build-and-test: steps: # Project stores tool config in a .tool-versions file committed to the repo - git-clone: {} - script: title: Set up environment inputs: # Set up tools based on the .tool-versions file in the repo - content: bitrise tools setup --config .tool-versions # Rest of the workflow has access to the right tools and versions in $PATH ``` You can also install specific tools without a configuration file: ```bash bitrise tools install [--provider PROVIDER] [--format FORMAT] [:SUFFIX] # Examples: bitrise tools install nodejs 20.10.0 bitrise tools install nodejs 22:latest eval "$(bitrise tools install ruby 3.2.0 --format bash)" # activate in shell ``` By default, running `bitrise tools setup` doesn't activate tool changes in the same shell session (for example, if the tool setup and tool use happens in the same **Script** Step). In the example, we're installing a new Ruby version: ```bash #! /bin/bash bitrise tools setup --config .ruby-version ruby --version ``` If you run this command in a **Script** Step, `PATH` will still point to the previous Ruby version. You can install and activate the tool in the same shell session using `eval`: ```bash eval "$(bitrise tools setup --config .ruby-version --format bash)" ruby --version # $PATH is updated with the newly set up ruby version ``` Alternatively, you can run `bitrise tools setup` in a separate Step. ```yaml workflows: build-and-test: steps: - git-clone: {} - script: title: Set up environment inputs: # Set up tools based on the .tool-versions file in the repo - content: bitrise tools setup --config .tool-versions # Rest of the workflow has access to the right tools and versions in $PATH - cocoapods-install: {} ``` #### Tool setup with the Dependency installer Step The **[Dependency installer](https://bitrise.io/integrations/steps/dependency-installer)** Step is a wrapper for the CLI subcommand that executes tool install. It accepts several types of tool version files: for the full list, see the Step description. To use the Step, add it to your Workflow before the Steps that need the tools: ```yaml steps:  - activate-ssh-key@4: {}  - git-clone@8: {}  - dependency-installer@1:      inputs:      - tool_version_file: ".tool-versions" ``` ### Supported tools The system is designed to support a growing list of tools and languages, but Bitrise only verifies and tests the stability of the most common tools listed. If you need a tool not listed here, read more how to use community plugins. :::tip[Other tools] If you don’t find a tool listed on this page, you can use community plugins to perform the tool setup. If a community `asdf` plugin exists for the given tool, you can provide the tool-plugin’s `git clone` URL in the config. For example, this is how you set up the right version of Deno using its `asdf` plugin: ```yaml tools: deno: 2.4.3 tool_config: extra_plugins: deno: https://github.com/asdf-community/asdf-deno.git ``` ::: | Tool name | YAML example | Notes | | --- | --- | --- | | **Ruby** | Using a 3.3.x version, preferring a preinstalled version to save install time: ``` tools: ruby: 3.3:installed ``` | At the moment, Ruby versions have to be built from source using the [ruby-build project](https://github.com/rbenv/ruby-build), so each install adds a few minutes to each build. [Bitrise stacks](https://bitrise.io/stacks/) come with multiple preinstalled Ruby versions at all times, so you can avoid the install time by using a partial version that uses a preinstalled Ruby (if available). | | **Go** | Installing the 1.24.0 version: ``` tools: golang: 1.24.0 ``` | | | **Python** | Using a 3.12.x version, preferring a preinstalled version to save install time: ``` tools: python: 3.12:installed ``` | At the moment, Python versions have to be built from source, so each install adds a few minutes to each build. [Bitrise stacks](https://bitrise.io/stacks/) come with a preinstalled Python version at all times, so you can avoid the install time by using a partial version that uses a preinstalled Python (if available). | | **Node.js** | Using a 22.x.y version, preferring a preinstalled version to save install time: ``` tools: nodejs: 22:installed ``` | | | **Java** | Installing Java 25: ``` tools: java: openjdk-25.0.0 ``` | | | **Flutter** | Flutter versions need to include the release channel as a suffix: ``` tools: flutter: 3.32.5-stable ``` | | | **Tuist** | Installing the 4.54.0 version: ``` tools: tuist: 4.54.0 ``` | | ### Changing tool version managers Bitrise uses tool version managers to install and provide the required tool at runtime. The primary manager is [mise](https://mise.jdx.dev/), but [asdf](https://asdf-vm.com/) is also supported and behaves the same. If you want to switch implementations for any reason, you can do so: ```yaml tool_config: provider: asdf ``` ### Limitations and alternatives - **No visual editor**: This feature is configurable only in configuration YAML for now. - **Dedicated version manager tools**: We recommend you use the approaches described in this page for installing tools. If you need to use `mise` or another tool directly, be aware that it is not installed on the stacks. You need to install it according to the official instructions. `asdf` is installed on stacks by default. We do not make guarantees that we pin a specific version, especially on edge stacks. `asdf` may be removed in a future edge stack. --- ## Reporting the build status to your Git hosting provider Bitrise can send build status reports to your Git provider (GitHub/GitLab/Bitbucket). This helps developers make informed decisions quickly and eliminates the need to switch between platforms. We send a status report for each build, even if the same commit triggers multiple builds. You can customize the report using variables to make it more descriptive and convey specific information. You can set up status reports on the project level or the level of Workflows or Pipelines. :::important[Pipeline reports] If the triggered entity is a Pipeline, it will report its build status but the individual Workflows within the Pipeline won't report separate statuses. Other than the Pipeline status report, Bitrise also reports test result statuses for Steps that are exporting a test result. ::: ### Setting up build status reporting There are two ways to set up Git status reports on Bitrise: - By using the [GitHub App integration](/bitrise-platform/repository-access/github-app-integration). It automatically sends status reports without any additional configuration, other than optionally customizing your reports. - Via the [service credential user](/bitrise-platform/integrations/the-service-credential-user). If you use [OAuth authentication for repository access](/bitrise-platform/repository-access/repository-access-with-oauth), this is how you can send status reports. The service credential user must have their Bitrise account connected to the Git provider account and must have access to the Git repository. The following permissions are required: - GitHub: **Write** - Bitbucket: **Write** - GitLab: **Developer**. You can test the service credential user's connection at any time: [Troubleshooting build status reporting](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider#troubleshooting-build-status-reporting). :::tip[Allowlist the Bitrise website IP addresses] If you use some form of self-hosted solution for storing your code, you might need to allowlist the static IP addresses of the Bitrise website and its background workers. This allows you to use such features as storing the `bitrise.yml` file in your own repository, or receiving build status updates from Bitrise: [IP addresses for the Bitrise website](/bitrise-platform/infrastructure/build-machines/configuring-your-network-to-access-our-build-machines#ip-address-ranges-for-bitrise-backend-workers). ::: You can send both project level and Workflow or Pipeline level reports with both methods. #### Branch protection rules When updating your build status report settings, you might need to change your branch protection rules at your Git provider. If you use [Workflow/Pipeline level status reports](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider#custom-status-reports) or use the `target-id` [dynamic variable](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider#custom-status-reports), you will have a different status check for every Workflow or Pipeline that was run. This means you might need more than one branch protection rule IF all checks are mandatory for all your pull requests. ### Custom status reports You can create custom Git status reports: You can tailor the commit status message to your team's preferences and requirements. You can give your report a name that allows you to immediately identify it on the Git provider site. You can use dynamic variables in the status report's name, like the title of your project or the name of the Workflow. The default status report name is `ci/bitrise//`. For legacy GitHub Checks reports, the default name is `Bitrise`. You can set up custom reports on two levels: - Project level reports apply to all Workflows and Pipelines within a project. This provides a consistent format for the status of any build in the same project. - On the level of individual Workflows or Pipelines. These custom reports will take precedence over the general project-level status report. This is useful when you want to provide more specific information about a particular build stage or to differentiate between different types of builds. :::important[Character limit and accepted characters] Keep your status message concise. The limit is 100 characters, and BitBucket allows only 40 characters. The following characters are supported: `, . / ( ) : - _ (space) (a-z) (A-Z) (0-9) < > [ ] |` ::: #### Project level status reports To create a custom status report on a project level, add the `status_report_name` property under `app` in your configuration YAML file. It can have static values: ```yaml app: status_report_name: 'Bitrise build' ``` Or you can use dynamic values: ```yaml app: status_report_name: 'PR check for ' ``` You can also combine multiple dynamic values: ```yaml app: status_report_name: 'Executing for ' ``` We recommend using `target_id`: it's the name of the Workflow or Pipeline that the build uses. With this variable, Git commit statuses from different Workflows/Pipelines on the same commit don't override each other. Find the available variables here: [Dynamic variables](#dynamic-variables). #### Workflow/Pipeline level status reports To create a custom status report on the Workflow level, add the `status_report_name` property under the name of the Workflow in the configuration YAML file: ```yaml workflows: build-ios: status_report_name: build-report ``` Similarly, to create one on the Pipeline level, add the property under the name of the Pipeline: ```yaml pipeline: deploy-pipeline: status_report_name: build-report ``` :::important[No additional report] If a Workflow in a Pipeline has the `status_report_name` property, it does NOT produce an additional, separate status report when the Workflow runs as part of a Pipeline. It only adds a custom name to the status report when the Workflow runs as a standalone build. ::: You can also combine multiple dynamic values: ```yaml pipeline: deploy-pipeline: status_report_name: 'Executing for ' ``` We recommend using `target_id`: it's the name of the Workflow or Pipeline that the build uses. With this variable, Git commit statuses from different Workflows/Pipelines on the same commit don't override each other. Find the available variables here: [Dynamic variables](#dynamic-variables). :::note[Branch protection rules] When switching from project-based status reports to Workflow level status reports, you might need to update [branch protection rules](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider#setting-up-build-status-reporting). ::: You can also set Workflow-level status reports in the Workflow Editor: open the Workflow, and go to its **Properties** tab, then find the **Git status name** input. ![workflow-level-status-report.png](/img/_paligo/uuid-5e4c921b-80ff-3392-c91f-22e7389ce5e3.png) #### Dynamic variables You can use the following dynamic variables in your status reports: | Variable name | Description | | --- | --- | | `project_slug` | The unique alphanumeric identifier of the project on Bitrise which is part of the project’s URL. | | `project_title` | The human-readable title of the project. | | `target_id` | The name of the specific Workflow or Pipeline that was used for the build. | | `event_type` | Represents the type of event that triggered the status report. The possible values are: - `pr`: pull request (GitHub, Bitbucket) - `mr`: merge request (GitLab) - `push`: code push (GitLab, GitHub, Bitbucket - `tag`: Git tag (GitLab, GitHub, Bitbucket) | ### Passing a required check on documentation-only pull requests If a status report is set as a required check in your Git provider's branch protection rules, every pull request must produce that check before it can be merged. This is a problem for changes that don't need CI, such as a pull request that only edits documentation or Markdown files. If no build is triggered, no status is reported, and the required check stays pending, which blocks the merge. Don't skip the build, because a skipped build reports nothing. Instead, trigger a Pipeline that reports the required check but does no work: every Workflow in it is skipped by a [`run_if` expression](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#conditional-workflow-execution-in-a-pipeline). Because a skipped Workflow counts as successful, the Pipeline finishes successfully and reports a green status, and skipped Workflows don't start a build machine, so this doesn't consume credits. Give this Pipeline the same `status_report_name` as your real CI Pipeline so both satisfy the same required check, and scope each one with `changed_files`: ```yaml pipelines: # Real CI. Runs on code changes. ci: status_report_name: ci triggers: pull_request: - changed_files: "app/**" workflows: build: {} # Documentation-only pull requests. Reports the same ci check, but does no work. docs-only: status_report_name: ci triggers: pull_request: - changed_files: "**/*.md" workflows: no-op: run_if: expression: "false" workflows: build: steps: - git-clone@8: {} # ... your build and test Steps ... no-op: steps: [] ``` :::warning[Keep documentation and code changes in separate pull requests] This pattern is reliable only when a pull request contains **either** documentation changes **or** code changes, not both. A `changed_files` condition matches when any changed file matches its pattern, so a pull request that touches both a Markdown file and a code file triggers **both** Pipelines. Both then report the same `ci` check on the same commit, and the successful `docs-only` report can override the real build's result, which lets a failing build merge. Keep documentation-only changes in their own pull request. If a pull request must include both, run full CI on it rather than relying on the `docs-only` Pipeline. ::: ### Troubleshooting build status reporting If your builds do not send status reports to your Git hosting provider - GitHub, GitLab or Bitbucket -, you will need to do a little investigating to find out what causes the problem. Let’s take a look at the potential issues! #### Checking the service credential user [The service credential user](/bitrise-platform/integrations/the-service-credential-user) of the app on [bitrise.io](https://www.bitrise.io) must have connected their Bitrise account to their Git hosting account and must have access to the repository of the app on that Git account. You can check the service credential user and test their Git connection. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. Go to your app’s page on [bitrise.io](https://www.bitrise.io). 1. Find the **Service credential user** section. :::note[Current user] In the figure, the current active user is the service credential user. If the service credential user is a different user, this looks a little different, including the button's text. ::: 1. Click the **Test <Git provider> connection** button to test the user's Git connection. #### Checking repository permissions and repository URL Make sure that you granted Bitrise access to your Workspace or team. It might be that you did not grant Bitrise access or denied access to the GitHub Workspace or Bitbucket team that owns the repository. Make sure the URL repository is up to date: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **General**. 1. Find the repository URL and make sure it's correct. ![apps-repository-url.png](/img/_paligo/uuid-0d8102bf-6e48-8787-cfe2-d24617d96950.png) --- ## Rolling builds You can cancel running builds or builds on hold with the **Rolling Builds** feature. The previous builds of your project can be automatically aborted once a new one is started. Please note that manual and scheduled builds are also cancelled if you start a new build with the **Rolling builds** option enabled. :::note[When is a build aborted?] If you trigger a build on a branch where a build is already running, the running build is aborted only if it runs the same Workflow. For example, if you trigger a build on the **main** branch of your repository with the **deploy** Workflow, it will NOT cancel a build running on the same **main** branch with the **primary** Workflow. ::: ### Configuring rolling builds 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Builds**. 1. Find the **Build strategy** section. 1. Select the type(s) of builds you wish to abort when a new build is started. ![rolling-builds.png](/img/_paligo/uuid-74153d13-4c04-d223-7389-268265192245.png) - **Abort on-hold builds triggered by pull requests**: Cancel all previous builds still **on-hold** for Pull Requests and all related Pushes. **Running** builds will **not** be canceled unless **Running builds are aborted** is also enabled. - **Abort on-hold builds triggered by pushes**: Cancel all previous builds still **on-hold** for Pushes to the same branch. **Running** builds will **not** be canceled unless **Running builds are aborted** is also enabled. You can configure exclusions for push events: [Managing exclusions for push events](#managing-exclusions-for-push-events) - **Abort on-hold builds triggered by tags**: Cancel all previous builds still **on-hold** if they were triggered by Git tags. - **Abort running builds**: Auto-cancel running builds in addition to on-hold ones. ### Managing exclusions for push events You can configure Bitrise to never abort certain code push builds. To do so, add exclusions when configuring rolling builds. You can exclude: - Repository branches. - Pipelines and Workflows. A build that involves an excluded branch, Pipeline or Workflow will never be aborted. 1. [Go to the Build strategy section to configure rolling builds](#configuring-rolling-builds). 1. Enable **Abort on-hold builds triggered by pushes**. 1. Click **Add exclusions** (or **Manage exclusions** if you have existing exclusions). 1. Enter excluded branches in the **Excluded branches** field, and excluded Pipelines or Workflows in the **Excluded pipelines and workflows** field. Both fields accept a comma-separated list of values. ![add-exclusions.png](/img/_paligo/uuid-563e93b4-6feb-8322-27f7-7b86d6957992.png) --- ## Selective builds :::caution[Using build triggers instead] This is a legacy feature. Instead of using this feature, you can now [configure build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) to only trigger builds when certain files or folders have changed: to do so, create a new trigger for push or pull request events, and choose the **Files changed** trigger condition. We strongly recommend using this option instead of Selective builds. ::: The **Selective builds** setting provides change detection for your builds. Enabling it allows you to only trigger a build of an app if certain files or folders have been modified. You may want to use this setting if: - You have a monorepo; that is, you build multiple apps from a single repository. - Multiple apps share common files in your repository. :::important[Selective Builds with non-Github projects] The current version of our Selective Builds feature only works with GitHub projects. If your repository is hosted by another Git hosting service, the option will not be available. ::: **Using the Selective builds feature** Let's say you want to make sure that a commit to your app's repository triggers a Bitrise build only if the `mycode.go` file on the `develop` branch is modified in the commit. - In this example, you have a branch called `develop`. - You have a trigger that starts a build every time a code push happens on the `develop` branch. - In the selective builds feature, you specified the `mycode.go` file in the input field. If you make a commit on the `develop` branch that modifies the `mycode.go` file, Bitrise will trigger a build. If your commit doesn't modify the file in any way, Bitrise will not trigger a build. To configure selective builds: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. Make sure the appropriate [service credential user](/bitrise-platform/integrations/the-service-credential-user) is set on the **Integrations** page. This user must have admin right for the GitHub repository of the project. 1. On the left, select **Builds**. 1. Find the **Selective builds** section and toggle it on. ![selectuve-builds.png](/img/_paligo/uuid-974582cb-d9c3-a954-0909-c78a76915d55.png) 1. Click **Add path** . :::important[Can't find the button?] If you can't find the button - like in the screenshot above -, it is because of two possible reasons: - The app's repository isn't hosted on GitHub. - The [service credential user](/bitrise-platform/integrations/the-service-credential-user) isn't set correctly or doesn't have admin rights to the repo. ::: 1. In the pop-up window, set the paths you need. You can add one path at a time. ### Using patterns in the file name or file path You do not need to set an exact file name or file path for the Selective builds feature: you can set patterns. Using regular expressions is not supported but the pattern may contain certain metacharacters: - `*`: Matches all files. - `a*`: Matches all files beginning with a. - `*a`: Matches all files ending with a. - `*a*`: Matches all files that have a in them (including at the beginning or end). - `**`: Matches directories recursively. - `?`: Matches any one character. - `\`: Escapes the next metacharacter. - `[set]`: Matches any one character in set. --- ## Setting the stack for your builds [The build stack](/bitrise-build-hub/infrastructure/build-stacks/about-build-stacks) indicates the virtual machine version that we will use to run your build. You can set the stack for all your builds, or you can set Workflow-specific stacks. :::tip[Changing machine types using the API] You can also change build machine types for all apps owned by a single user or Workspace using the API: [Changing machine types in all apps at the same time](/bitrise-ci/api/adding-and-managing-apps#changing-machine-types-in-all-apps-at-the-same-time). ::: ### Setting the stack in the Workflow Editor The simplest way to configure the [build stack](/bitrise-build-hub/infrastructure/build-stacks/about-build-stacks) is in the Workflow Editor. You can set both the default stack and Workflow-specific stacks. #### Setting the default stack The default stack of your project is the stack that is used if you haven't set a specific stack for a Workflow. :::note[Project type] Note that if you change the project type on the app's **Settings** tab to a type that isn't compatible with your selected default stack, we'll automatically change the stack to a compatible one. ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Stacks & Machines**. 1. In the **Default stack & machine** section, open the dropdown menu and select the stack you need. 1. Click **Save changes** in the top right corner. #### Setting a Workflow-specific stack When you set a stack for a Workflow, that Workflow will always run on that stack, regardless of the default stack. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Stacks & Machines**. 1. Select the **Workflows** tab. ![Workflows tab on the Stacks & Machines page](/img/configure-builds/2026-07-08-stacks-workflows-tab.png) 1. Find the Workflow you need and select a stack. 1. Click **Save changes** in the top right corner. #### Setting the machine type in the Workflow Editor You can define the machine type you want to use for your build in the Workflow Editor. The available machine types depend on the type of stack you use: [Build machine types](/bitrise-build-hub/infrastructure/build-machine-types). To set the machine type: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Stacks & Machines**. 1. In the **Default stack & machine** section, choose a machine type from the machine type selector. ![Machine type selector in the Default stack & machine section](/img/configure-builds/2026-07-08-stacks-default-machine-type.png) 1. Optionally, choose a Workflow-specific machine type for any Workflow that has a Workflow-specific stack set. ### Setting the stack in the Configuration YAML You can set both the default stack and Workflow-specific tasks in your project's Configuration YAML. Use the `meta` field with the appropriate stack ID: ```yaml meta:       bitrise.io:        stack:  ``` This is particularly useful if you [keep your `bitrise.yml` file stored in your app's repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository). :::note[Stack IDs] You can find the stack IDs on the top of each stack report: [Bitrise stack reports](https://stacks.bitrise.io/stack_reports/). Alternatively, you can set a stack in the Workflow Editor and then check out the ID on the **bitrise.yml** tab, by finding the `meta` field. The stack reports also show every [pre-installed tool](/bitrise-platform/infrastructure/build-stacks/preinstalled-tools-on-bitrise-stacks) that is available on the stack. ::: #### Setting the default stack in the Configuration YAML The default stack of your project is the stack that is used if you haven't set a specific stack for a Workflow. 1. Open your project's Configuration YAML. 1. Add a `meta` entry outside the `workflows` property or at the end of your Configuration YAML: ```yaml meta:       bitrise.io:        stack: ``` Make sure you use double indentation. 1. Add the stack ID. You can find the stack IDs on the [stack reports page](https://stacks.bitrise.io/stack_reports/): the filenames without the `.log` extension are the stack IDs. ```yaml meta:       bitrise.io:        stack:  ``` #### Setting Workflow-specific stacks in the Configuration YAML When you set a stack for a Workflow, that Workflow will always run on that stack, regardless of the default stack. 1. Open your project's Configuration YAML. 1. Find the `workflows` property and find the name of the Workflow you need within. 1. Add a `meta` entry under the Workflow itself: ```yaml workflows: deploy: meta:       bitrise.io:        stack: ``` 1. Add the stack ID. You can find the stack IDs on the top of each [stack report page](https://stacks.bitrise.io/stack_reports/). ```yaml workflows: deploy: meta:       bitrise.io:        stack:  ``` #### Setting the machine type in the Configuration YAML You can also define the machine type you want to use for your build in your project's Configuration YAML. Machine type refers to the hardware resources used in your build; for example, an Elite machine has more CPU cores and available RAM than a Standard machine. To set the machine type in Configuration YAML file, you need to use the `machine_type_id` attribute in a `meta` entry: :::note[Available machine IDs] You can find the available machine type IDs here: [Build machine types](/bitrise-build-hub/infrastructure/build-machine-types). ::: 1. Open your project's Configuration YAML file. 1. Find the `workflows` property and find the name of the Workflow you need within. 1. Add a `meta` entry: ```yaml # setting an 8-core Gen2 machine for an Xcode stack as the default machine type of the app: meta: bitrise.io: machine_type_id: g2.8core # setting a 12-core Gen2 machine as a Workflow-specific machine type workflows: deploy: meta: bitrise.io: machine_type_id: ``` ### Build machine types Bitrise offers multiple build machines with different specifications You can choose between them based on your needs. You can track how much time you spent building your apps on each machine type with Insights: [Bitrise CI metrics](/insights/available-metrics-in-insights/bitrise-ci-metrics). :::tip[Machine availability by subscription plan] Not all machines are available on all subscription plans. Visit [the pricing page](http://www.bitrise.io/pricing) to find out which machines are available on your plan! ::: Machine types are divided into resource classes. The same resource class offers multiple machine types with broadly similar performances. Bitrise automatically assigns machine types from a resource class, which means that on the same day, your builds might run on different machine types. :::tip Use the machine type ID to set the machine type in your [configuration YAML](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds#setting-the-stack-in-the-configuration-yaml). ::: | OS and resource class | Hardware type | Specs | Machine type ID | | --- | --- | --- | --- | | macOS Medium | M2 Pro Medium | • 4 CPU @3.49GHz• 6 GB RAM | `g2.mac.medium` | | macOS Medium | M4 Medium | • 5 CPU @4.4 GHz• 6 GB RAM | `g2.mac.medium` | | macOS Large | M2 Pro Large | • 6 CPU @3.49GHz• 14 GB RAM | `g2.mac.large` | | macOS Large | M4 Large | • 5 CPU @4.4 GHz• 14 GB RAM | `g2.mac.large` | | macOS X Large | M2 Pro X Large | • 12 CPU @3.49GHz• 28 GB RAM | `g2.mac.x-large` | | macOS X Large | M4 X Large | • 10 CPU @4.4 GHz• 28 GB RAM | `g2.mac.x-large` | | macOS 4Large | M4 Pro Large | • 7 CPU @4.52GHz• 27 GB RAM | `g2.mac.4large` | | macOS 4X Large | M4 Pro X Large | • 14 CPU @4.52GHz• 54 GB RAM | `g2.mac.4x-large` | | Linux Medium | | • 4 vCPU @3.1 GHz• 16 GB RAM | `standard` | | Linux Large | | • 8 vCPU @3.1 GHz• 32 GB RAM | `elite` | | Linux X Large | | • 16 vCPU @3.1 GHz• 64 GB RAM | `elite-xl` | | Linux Small | AMD EPYC Zen 4/5 | • 2 vCPU• 8 GB RAM | `g2.linux.2small` | | Linux M | AMD EPYC Zen 4/5 | • 4 vCPU @3.7 GHz• 16 GB RAM | `g2.linux.medium` | | Linux 2M | AMD EPYC Zen 4/5 | • 6 vCPU @3.7 GHz• 24 GB RAM | `g2.linux.2medium` | | Linux L | AMD EPYC Zen 4/5 | • 8 vCPU @3.7 GHz• 32 GB RAM | `g2.linux.large` | | Linux 4L | AMD EPYC Zen 4/5 | • 14 vCPU @3.7 GHz• 56 GB RAM | `g2.linux.4large` | | Linux XL | AMD EPYC Zen 4/5 | • 16 vCPU @3.7 GHz• 64 GB RAM | `g2.linux.x-large` | | Linux 3XL | AMD EPYC Zen 4/5 | • 24 vCPU @3.7 GHz• 96 GB RAM | `g2.linux.3x-large` | | Linux 5XL | AMD EPYC Zen 4/5 | • 32 vCPU @3.7 GHz• 128 GB RAM | `g2.linux.5x-large` | | Linux 7XL | AMD EPYC Zen 4/5 | • 48 vCPU @3.7 GHz• 192 GB RAM | `g2.linux.7x-large` | :::note Some macOS resource classes list two hardware types with the same machine type ID. Both generations use the same ID — Bitrise automatically selects the available hardware for each build. ::: --- ## Setting your Git credentials on build machines The default Git username and user email address on our stacks are the following: ```bash git config --global user.email "noreply@bitrise.io" git config --global user.name "Bitrise CI" ``` If you want to push back (`git push`) any commits to your own repo from Bitrise while running your build, you have to set your own username and the email address. There are three ways to achieve this: - You can use a custom Script Step to set your credentials with the `git config` command. - You can set your Git credentials as Env Vars. - You can use the [**Set Git Credentials**](https://bitrise.io/integrations/steps/set-git-credentials) Step. ### Setting your Git credentials using Env Vars Git has various basic [Environmental Variables](https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables) similar to [Bitrise Env Vars](/bitrise-ci/configure-builds/environment-variables). If you would like to reduce the amount of Steps in your Workflow, you can set up Env Vars in Bitrise utilizing specific Git Environmental Variables: 1. Open the Workflow Editor. 1. Go to the **Env Vars** tab. 1. Create the following Env Vars: - GIT_AUTHOR_NAME: This is the human-readable name of the “author”. - GIT_AUTHOR_EMAIL: This is the email address of the "author". - GIT_COMMITTER_NAME: This is the human-readable name of the “committer”. - GIT_COMMITTER_EMAIL: This is the email address of the "committer". ![git_credentials.png](/img/_paligo/uuid-2b06167e-f54e-eb64-2314-315d36a5d17f.png) ### Setting your Git credentials using the [Set Git Credentials](https://bitrise.io/integrations/steps/set-git-credentials) Step 1. Add a [**Set Git Credentials**](https://bitrise.io/integrations/steps/set-git-credentials) Step as the very first step in your workflow. The Step has to come first before you’d `git commit`. This way you can make sure any changes you make to the current build will be attached to a commit associated with your username and email address. 1. In the **Git Username** field, set the value to your own user name. 1. In the **Git Email Address** field, set the value to your own email address. 1. [Start a build.](/bitrise-ci/run-and-analyze-builds/starting-builds/approving-pull-request-builds) If all went well, you should see the changes in your repository in your Git provider. The new username and email address will be visible for all future commits you push from your builds to your Git provider. --- ## Environment Variables An Environment Variable (Env Var) is a key-value pair that holds data that you can use in your builds. For example, working directory of a project's repository is often stored in an Env Var so you don't have to specify the path for every Step input that needs it. You can configure Env Vars for an entire project or for specific Pipelines and Workflows. Project level Env Vars are available for every Workflow of the app; Pipeline- and Workflow level Env Vars are only available for the given Pipeline or Workflow. :::note[Size limit of the Env Var list] By default, the Env Var list size is 120 KB. You can easily increase the list size using a [Script](https://github.com/bitrise-io/steps-script) Step as described in this [Knowledge Base article](https://support.bitrise.io/en/articles/9676692-envman-environment-list-too-large-error). ::: Secrets are a specific type of Environment Variable: they hide their information in an encrypted format and their value is not exposed in the build logs. :::warning[Protect confidential information] Unlike Secrets, Env Vars are fully exposed in builds triggered by pull requests so you should not add any sensitive information to Env Vars. ::: ### Scope of Environment Variables Users can declare Environment Variables on three different levels: - App level. - Workflow level. - Step level. In addition to the user-declared Env Vars, there are Env Vars automatically exposed by either the Bitrise CLI or bitrise.io. These are always available in any build. You can find the list of these here: [Available environment variables](/bitrise-ci/references/available-environment-variables) **Project level Env Vars** are available to every build of a given app. Whenever you create a new Workflow, for example, it immediately and automatically has access to every single project level Env Var. **A Workflow level Env Var** is only available to the specific Workflow it was defined in. If your `primary` Workflow has an Env Var with the key TEST_ENV, your `deploy` Workflow won't be able to access that Env Var. :::note[Chaining Workflows together] If you [chain Workflows together](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#chaining-workflows-together), using the `after_run` parameter, and define an Env Var in one of the Workflows, all subsequent Workflows in the chain will be able to access that Env Var. ::: **A Step level Env Var** is defined within a particular Step of a build. Such an Env Var is not available to other Workflows, or to the preceding Steps in the same Workflow. Subsequent Steps, however, can access it. Step outputs are also exposed as Environment Variables. You can set Environment Variables, regardless of level, in both the Workflow Editor, in your app's `bitrise.yml` file, or during a build with a custom Script using the [envman](https://github.com/bitrise-io/envman/) tool: - [Setting an Env Var in the Workflow Editor](/bitrise-ci/configure-builds/environment-variables#setting-an-env-var-in-the-workflow-editor) - [Exposing Env Vars and using them in another Step or Workflow](/bitrise-ci/configure-builds/environment-variables#setting-and-managing-env-vars-during-a-build) Environment Variables have a given processing order based on their level: [Availability order of Environment Variables](/bitrise-ci/configure-builds/environment-variables#availability-order-of-environment-variables) ### Availability order of Environment Variables Environment Variables (Env Var) are available after the Env Var is processed. There are Env Vars exposed by the Bitrise CLI. These are available from the start: for example, `BITRISE_SOURCE_DIR` and `BITRISE_TRIGGERED_WORKFLOW_ID`. All other Env Vars are processed and made available as the build progresses. The processing order is the following: 1. Env Vars exposed by the Bitrise CLI. 1. [Secrets](/bitrise-ci/configure-builds/secrets): they are processed before a Workflow starts. 1. One-off Environment Variables specified for the build through our API. 1. App Environment Variables. 1. Workflow Environment Variables: when the processing of the specified Workflow starts, the Env Vars specified for that Workflow are made available. If the Workflow has Workflows [chained before or after it](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows), the Environment Variables of the chained workflows are processed and made available right before the first Step of the Workflow would run. 1. Step inputs: they are exposed for each Step, right before the Step would start. 1. Step outputs: they are exposed by the specific Step, so those are available for subsequent Steps after the Step finishes. ### Setting an Env Var in the Workflow Editor :::note[Every Env Var value is a string] The value of an Environment Variable or Secret can only be a string. Even if you set a number (for example, 7), it will be passed on as a string. ::: :::important[Using the $ character] You can use the `$` character in the value of an Env Var or Secret (for example, in a password) but in that case always leave the **Replace variables in inputs** option unchecked. If you replace the variable's key with its value in inputs, the Bitrise CLI will treat the value as another Env Var because of the `$` character. ::: You can set Env Vars at two levels: **Project** (available to every Workflow) or **Workflows** (scoped to a specific Workflow). For details on how these interact, see [Availability order of Environment Variables](/bitrise-ci/configure-builds/environment-variables#availability-order-of-environment-variables). **Project** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Env Vars** from the navigation menu. 1. Select the **Project** tab. ![Project Environment Variables tab in the Workflow Editor](/img/configure-builds/2026-07-08-env-vars-project-tab.png) 1. Click **Add new**. 1. Add a key and a value. 1. Click **Save changes** in the top right corner. **Workflows** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Env Vars** from the navigation menu. 1. Select the **Workflows** tab. ![Workflows Environment Variables tab in the Workflow Editor](/img/configure-builds/2026-07-08-env-vars-workflows-tab.png) 1. Choose the Workflow you want to add the Env Var to. 1. Click **Add new**. 1. Add a key and a value. 1. Click **Save changes** in the top right corner. That's it. Your new Env Var is saved and ready to be used. ### Replacing variables in inputs Replacing variables in inputs ensures that the value of the Env Var will be passed to the build instead of the key. For details, check [Replacing variables in inputs](/bitrise-ci/configure-builds/environment-variables#replacing-variables-in-inputs). Toggling on this option ensures that instead of the key of the Env Var, the value of the Env Var will be passed to the build. Normally, this is not necessary. Please note that if you add a new Environment Variable directly in the `bitrise.yml` file and do NOT set the `is_expand` property, the default value will be `true`. We recommend explicitly setting `is_expand` in this case: ```yaml envs: - opts: is_expand: false KEY: VALUE ``` ### Setting a custom Env Var when starting a build When scheduling a new build or starting a new build manually, you have the option to set up custom Environment Variables (Env Var). These variables are only available for the build you started or scheduled. :::caution[Don't use the same key as an App Env Var] App Environment Variables have precedence over custom Environment Variables! This means that if you define a custom Env Var with the same key as an App Env Var, the build will use the value of the App Env Var. ::: 1. On the **Bitrise CI** page of your app, find the **Start build** button and click the button with the clock icon next to it. ![scheduling-builds.png](/img/_paligo/uuid-ea158f34-25dc-4585-c7a3-0961c5ef5472.png) 1. In the **Build configuration** pop-up window, select the **Advanced** tab. 1. Find the **Custom Environment Variables** section. 1. Enter a key and a value. :::important[Replacing variables in inputs] Replacing variables in inputs ensures that the value of the Env Var will be passed to the build instead of the key. For details, check [Replacing variables in inputs](/bitrise-ci/configure-builds/environment-variables#replacing-variables-in-inputs). ::: 1. Press the **+ Add Environment Variable** button. 1. Finish starting or scheduling the build. ### Using an Env Var in a Step input Many [Step inputs](/bitrise-ci/workflows-and-pipelines/steps/step-versions) accept Environment Variables (Env Var) and [Secrets](/bitrise-ci/configure-builds/secrets) as input values. :::important[Sensitive inputs] Input fields marked as **SENSITIVE** only accept Secrets as their input. Generally, we do not recommend changing the value of these inputs. ::: To use an Env Var or a Secret as a Step input value: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Select **Env Vars** from the navigation menu on the left. 1. Select a Step from the Workflow. For example, the **Git Clone Repository** Step. 1. Choose a Step input. For example, the **Clone destination (local) directory path** input of the **Git Clone Repository** Step. 1. Next to the name of the input, click **Insert variable**. 1. Find the Env Var in the list, and select it. You can search for the Env Var by typing its key (or a part of it) into the **Filter by key or source** search field. :::note[Env Vars generated by Steps] The interactive list of Env Vars will show the Env Vars that are generated by previous Steps of the Workflow. For example, if you want to insert an Env Var into one of the inputs of the third Step in the Workflow, you can choose from the Env Vars generated by the first and second Steps. ::: That's it. The next time you run a build of that Workflow, the Step input will use the value of the inserted Env Var as the Step input value. ### Using Env Vars in the value of an Env Var Environment Variables (Env Var) normally contain a simple string value. However, it is possible to set up an Env Var that includes other Env Vars as values. :::note[Secrets as variable values] The methods described here also apply to [Secrets](/bitrise-ci/configure-builds/secrets). You can also embed a Secret within an Env Var. ::: You can, at any time, use another Environment Variable in the value of an Env Var - embedding the Env Var, so to speak. For example, let's say we want to set the value of the $BITRISE_AUTH Env Var to $PERSONAL_ACCESS_TOKEN which is another Env Var. To do this, you need to make sure that the key of $BITRISE_AUTH is replaced with its value so that its the embedded Env Var that is passed on to the Workflows and Steps. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Env Vars** from the navigation menu. 1. Under the key of the Env Var you need, toggle the **Replace variables in inputs** toggle to active. ### Setting and managing Env Vars during a build You can set Env Vars during a build by defining them in a Step, typically a **Script** Step. To accomplish this, you can use the [envman](https://github.com/bitrise-io/envman/) tool. :::important[New Env Vars take effect from the next Step] Any Environment Variable you create with the `envman` tool takes effect only from the subsequent Step in the Workflow. In other words, you can't use a newly created Environment Variable in the same Step in which it was created. ::: Here is a simple example where we're using `envman` to add a new Env Var with the key MY_RELEASE_NOTE: ```bash envman add --key MY_RELEASE_NOTE --value "This is the release note" ``` You can call `envman` in any Step, including a **Script** Step, or even in your own script (stored in your repository) if you call it from a `bitrise` build. You can specify the value as the `--value` parameter, or by using pipe: ```bash echo 'hi' | envman add --key MY_RELEASE_NOTE ``` You can also read the value from a file: ```bash envman add --key MY_RELEASE_NOTE --valuefile ./some/file/path ``` Once the Env Var is exposed, you can use it like any other Env Var. You can use these exposed Env Vars in the inputs of other Steps as well. Here is an example where we’re exposing the release note Env Var and then using it in another **Script** Step and in a **Send a Slack message** Step: ```yaml workflows: example: steps: - script: inputs: - content: | #!/bin/bash envman add --key MY_RELEASE_NOTE --value "This is the release note" - script: inputs: - content: | #!/bin/bash echo "My Release Note: $MY_RELEASE_NOTE" - slack: inputs: - channel: ... - webhook_url: ... - message: "Release Note: $MY_RELEASE_NOTE" ``` If you want to expose the value of an Env Var to be accessible through the key of another Env Var, you can do so. For example, to expose the value of `BITRISE_BUILD_NUMBER` under the key `MY_BUILD_NUMBER`: ```bash envman add --key MY_BUILD_NUMBER --value "${BITRISE_BUILD_NUMBER}" ``` After this, subsequent Steps can get the value of `BITRISE_BUILD_NUMBER` from the `MY_BUILD_NUMBER` Env Var. If you change the value of `BITRISE_BUILD_NUMBER` after this, the value of `MY_BUILD_NUMBER` won’t be modified, it will still hold the original value! If you need to know if a custom Env Var has been defined, you can easily check it, and even overwrite its value: ```bash #!/bin/bash set -ex if [ ! -z "$API_PROJECT_SCHEME" ] ; then envman add --key PROJECT_SCHEME --value "$API_PROJECT_SCHEME" fi ``` This script checks whether the `API_PROJECT_SCHEME` Env Var is defined, and if it is, its value will be assigned to the `PROJECT_SCHEME` Environment Variable, overwriting the original value of `PROJECT_SCHEME`. ### Setting Env Vars in the configuration YAML You can set Env Vars directly in the YAML configuration file for your app. You can set both app level and Workflow level Env Vars in your app's config file. In this example, we have a configuration with an app-level Env Var called TEST_KEY: ```yaml app: envs: - opts: is_expand: false TEST_KEY: test value ``` :::important[Replacing variables in inputs] Replacing variables in inputs ensures that the value of the Env Var will be passed to the build instead of the key. For details, check [Replacing variables in inputs](/bitrise-ci/configure-builds/environment-variables#replacing-variables-in-inputs). ::: In this example, the `deploy-alpha` Workflow defines an Env Var called ENV_TYPE, and then runs another Workflow that can use that Env Var: ```yaml workflows: deploy-alpha: envs: - ENV_TYPE: alpha after_run: - _deploy _deploy: steps: - script: inputs: - content: | #!/bin/bash echo "ENV_TYPE: $ENV_TYPE" ``` If you run the `deploy-alpha` Workflow, that will set the `ENV_TYPE` Env Var to `alpha`, then it will run the `deploy` Workflow, which can use that Env Var. In this example, it will simply print its value (the printed text will be: `ENV_TYPE: alpha`). --- ## Secrets Secrets are a specific type of Environment Variable: they hide their information in an encrypted format and their value is not exposed in the build logs. They aren't shown in the `bitrise.yml` configuration either. You can store confidential information, such as passwords or API keys as Secrets. Just like Environment Variables, Secrets can be used as the value of a Step input: [Using an Env Var as a Step input](/bitrise-ci/configure-builds/environment-variables#using-an-env-var-in-a-step-input) ### Setting a Secret :::note[Every Env Var value is a string] The value of an Environment Variable or Secret can only be a string. Even if you set a number (for example, 7), it will be passed on as a string. ::: You can create a Secret either on the **Secrets** page in the Workflow Editor or when modifying Step inputs. **Secrets page** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Secrets**. 1. Under **Project level Secrets**, click the **Add new** button. ![secrets-screenshot.png](/img/_paligo/uuid-b269a597-65ef-34a5-1828-ad1ab954437d.png) 1. Add a key and a value. :::important[Using the $ character] You can use the `$` character in the value of an Env Var or Secret (for example, in a password) but in that case always leave the **Replace variables in inputs** option unchecked. If you replace the variable's key with its value in inputs, the Bitrise CLI will treat the value as another Env Var because of the `$` character. ::: 1. Optionally, you can [replace the key of your Secret with its value in inputs](/bitrise-ci/configure-builds/environment-variables#replacing-variables-in-inputs): check the **Replace variables in inputs** option. 1. Optionally, you can expose your Secret to pull requests by selecting the option. In most cases, we strongly recommend [not to expose Secrets](/bitrise-ci/configure-builds/secrets#exposing-a-secret-to-pull-requests). 1. Click **Save**. **Step inputs** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Select a Workflow and find the Step you want to configure. 1. Find the sensitive input you wish to modify. 1. Click the **$** sign and then click **Create** in the dialog. 1. In the **Create secret** dialog, specify a key and a value for your new Secret. ![create-variable.png](/img/_paligo/uuid-2a0854ff-b62a-6215-5c2e-09cf6b244786.png) 1. Optionally, you can [replace the key of your Secret with its value in inputs](/bitrise-ci/configure-builds/environment-variables#replacing-variables-in-inputs) by checking the option. 1. Click **Create**. ### Editing an existing Secret Once you’ve added a new secret Env Var in the **Secrets** tab, you come back to it any time, modify its content or make it protected from curious eyes! 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Secrets**. 1. Click **Edit** next to the value of your Secret. 1. Modify its content as needed. 1. Click **Save**. ### Protecting the value of a Secret Normally, you can **show** and **hide** the value of a Secret by clicking the **eye** icon. This feature is useful if you have a long list of secret env vars in **Secrets** and you wish to check the value of only one Secret while leaving the other values hidden. If a value is hidden, it’s represented with the **crossed out eye** icon. However, you can hide the value of a Secret permanently by making it protected. If you do so, no one, including yourself, will be able to change or even view the value again. :::warning[A Secret's protection can't be undone] Making a Secret protected is irreversible. If you ever need to change the value, you will have to delete the Secret and create a new one. ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Secrets**. 1. Click **Edit** next to the value of your Secret. ![edit-button-secrets.png](/img/_paligo/uuid-2de8b6b8-3fc0-5da9-9f45-1b22546e1bb2.png) 1. Check **Protected**. 1. The dialog will warn that the process is irreversible. Click **Save and protect**. That's it. You can no longer view the value of the Secret. ### Exposing a Secret to pull requests By default, pull requests do not have access to the values of Secrets. This means that if a pull request opened from a fork of a repository triggers a build, that build can't use the app's Secrets. If you need to grant pull request builds access to a particular Secret, you can expose that Secret to pull requests. However, even when exposed, its value won't be visible in the logs: it will be displayed as [REDACTED]. :::important[Protected Secrets can't be exposed] Once a Secret has been [made protected](/bitrise-ci/configure-builds/secrets#protecting-the-value-of-a-secret), you can't expose it to pull request builds. ::: :::important[Public apps] If your app is a public app, you can't expose the app's Secrets to pull requests builds. ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Secrets**. 1. Click **Edit** next to the value of your Secret. 1. Toggle the **Expose for Pull Requests?** toggle. Once the Secret is exposed, pull request builds can access it. ### Managing Secrets across multiple apps By default, all Secrets are handled on the app level. You can reuse Secret keys across multiple Bitrise apps, even if their corresponding values are different for each app. However, it is possible to set up a Secret that holds the same value for all your apps, and manage that Secret from one location. For example, if all your apps need access to the same API, it makes sense to store the Secret containing the API key in a central location. If the API key ever changes, you only need to change it in that single location and the change applies to all your Bitrise apps. There are two ways to achieve this: - [Managing your Secrets from a Workspace](#managing-secrets-on-a-workspace-level). This is only available on Enterprise plans. - [Managing secrets from a central location](#managing-secrets-from-a-central-vault-or-database) such as a vault or database and pulling it with a Step. #### Managing Secrets on a Workspace level On Enterprise plans, you can store Secrets on a Workspace level. This means that the same Secret is accessible to all apps owned by that Workspace. This means increased security: only Workspace Owners and Managers can access these Secrets. :::note[Downgrading] If you downgrade from an Enterprise plan, Workspace Secrets will be converted to app level Secrets. ::: When passing Secrets to your build, app level Secrets take precedence over Workspace level Secrets in the [availability order](/bitrise-ci/configure-builds/environment-variables#availability-order-of-environment-variables). This also means that if you have two Secrets with the same key, the app level Secret will be used during the build. To add a new secret: 1. On the Bitrise main page, select **Settings** on the navigation menu on the left. It takes you to the **Workspace settings** page. 1. On the **Workspace settings** page, select **Shared resources**. ![shared-res.png](/img/_paligo/uuid-8b262205-594a-d6ae-9985-3c47a3df5175.png) 1. Click the **Add new** button. 1. Add a key and a value. ![ws-secrets.png](/img/_paligo/uuid-0d1616e8-82d6-9de7-f192-1aab7058880b.png) 1. Configure the usage details of the Secret: - **Replace variables in inputs**: This passes the value of the Secret as a string to the build. Use this for embedded Secrets or Environment Variables: when the value of your Secret is the key of another Secret or Environment Variable. For most use cases, you don't need this checked. - **Expose for pull requests**: Exposing a Secret to a PR means that the Secret is available to use in pull request builds. Depending on your repository's privacy settings, this is a potential security risk! - **Protected**: The value cannot be changed or viewed again. This setting is irreversible once saved. 1. When you're ready, click **Done**. #### Managing Secrets from a central vault or database Setting up Secrets in a central location requires two things: - A central vault or database - such as HashiCorp or Doppler - to store the Secrets. It must be accessible via a CLI. - A **Script** Step to access the central vault/database, pull the Secret and set it to sensitive on Bitrise. To create a new Secret and store it in a central location during a build: 1. Add the Secrets as a key-value pair to your vault or database where you want to store them. 1. Add a **Script** Step to ALL Workflows where you want to use the Secrets. 1. Add the necessary commands to access your vault and pull the Secrets. The exact commands depend on the service you’re using. 1. Use the `envman` tool to mark the Secrets as sensitive. The envman tool has the following syntax: `envman add --key KEY --value value --sensitive` . 1. Make sure the Step doesn’t display the value of the Secret in the build log. To do so, remove `set -x` from the Step’s `content`. :::warning[Secret redaction] Please note that if you have Secret redaction turned off, your Secrets will not be redacted and thus their value can still be visible in logs. ::: **Storing your Secrets in a HashiCorp Vault** Let’s say you have a [HashiCorp Vault](https://www.vaultproject.io/) instance called `secret/hello`. You have two Secrets in this vault instance: `foo` with the value `world` and `foo2` with the value `world2`. To use these Secrets in a Bitrise build, you need to: - Export them from the Vault instance. - Iterate over them and mark both of them as sensitive. You can use this Script to achieve both: ```bash # Exporting the Secrets vault kv get --format=json secret/hello | jq -r '.data.data | to_entries[] | [.key, .value] | @tsv' | # Iterating over the Secrets and marking them as sensitive while IFS=$'\t' read -r key value; do envman add --key "$key" --value "$value" --sensitive done ``` ### Redacting Secrets The Bitrise CLI automatically redacts your Secret Env Vars and prints `[REDACTED]` with newlines after the key so that the Secret Env Vars are NOT VISIBLE in the build log. This applies to both private and public apps. You can turn this off at any time though if you need to have your Secrets visible in logs. :::warning This is a potential security risk. We strongly recommend not to turn off Secret redaction. ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Secrets**. 1. Click **Add new** to register the `BITRISE_SECRET_FILTERING` secret Environment Variable with false value. 1. Click **Save changes** in the top right corner. ### Secrets in self-hosted environments You can run Bitrise builds on self-hosted infrastructure: hardware or virtualized environments that you control. If your security policy doesn't allow you to use Bitrise Secrets hosted on bitrise.io, this guide offers a different way of accessing Secrets and using them in your builds. In a self-hosted build, your host machine is behind your virtual private cloud. As such, you can access the secret service of your choice without exposing the Secrets to the Bitrise control plane and the website. Get the Secret from your service and then add it to the Bitrise build using `envman`: 1. Optionally, create a placeholder Secret on Bitrise with any value: [Setting a Secret](/bitrise-ci/configure-builds/secrets#setting-a-secret). This is necessary only if you wish to use the Secret in a sensitive Step input on the GUI of the Workflow Editor. Sensitive inputs only accept Secrets and in the Workflow Editor you can only add existing Secrets as the value of a sensitive input. If you edit your Bitrise configuration in YAML, you don't need a placeholder as you can set any value to your input. 1. Use a **Script** Step to get your Secret from the service you use. 1. In the script, turn off debugging by setting `set +x`: This is very important: in debug mode, the value of the Secret might be visible in the build log! ```bash #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set +x ``` 1. Fetch the Secret value from the service you use and then add it to `envman`. ```bash set +x GIT_PASSWORD_SECRET=TODO Your call to fetch the secret value envman add --key GIT_HTTP_PASSWORD --value $GIT_PASSWORD_SECRET ``` The actual commands depend on the service you use. For example, if you use Bitrise on AWS and your EC2 machine can access the AWS Secrets Manager, you could get the secret with a command similar to this: ```bash set +x USERNAME=aws secretsmanager get-secret-value --secret-id BitriseDemoGitUsername --region eu-central-1 | jq -r '.SecretString' envman add --key GIT_HTTP_USERNAME --value $USERNAME PASS=aws secretsmanager get-secret-value --secret-id BitriseDemoGitPassword --region eu-central-1 | jq -r '.SecretString' envman add --key GIT_HTTP_PASSWORD --value $PASS ``` --- ## Android dependencies The Gradle build system handles dependencies for Android apps. If you have your dependencies defined in your `build.gradle` file, the dedicated Android Steps on Bitrise can handle installing and even caching them. ### Installing dependencies for Android apps Building an Android app with Gradle dependencies is straighforward on Bitrise. When you first [add the app](/bitrise-ci/getting-started/adding-a-new-project), our project scanner determines that it's an Android app by locating the `build.gradle` file. Our official Android Steps can handle installing dependencies during the build process, and can build different modules and variants easily. To make sure all your dependencies will be installed during the build: 1. [Define dependencies](https://developer.android.com/build/dependencies) in your Android project. 1. Use one of our Android Steps to build your app. The following Steps can install dependencies and build the app: - [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build) - [**Android Build for UI Testing**](https://github.com/bitrise-steplib/bitrise-step-android-build-for-ui-testing) - [**Gradle Runner**](https://github.com/bitrise-io/steps-gradle-runner) Each of these Steps run a Gradle task the same way you would run it on your own device. They can build specific modules and install the relevant dependencies for those modules in the process. ### Installing missing Android SDK components Our build machines come with all the most commonly used Android tools pre-installed. However, if you need additional components of the Android SDK installed, we have a dedicated Step that handles the job for you. This Step requires you to have [the Gradle Wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) in your project, as it looks for the ``gradlew` file. It runs the `gradlew dependencies --stacktrace` command to list and install the missing dependencies. To install missing Android SDK components in a Bitrise build: 1. Define the Android SDK components you need in the top level `build.gradle` file of your project. 1. Make sure you have a `gradlew` file in your project's repository. 1. On Bitrise, add the [**Install missing Android SDK components**](https://github.com/bitrise-steplib/steps-install-missing-android-tools) Step to your Workflow. It should be before any Step that requires Android SDK components. 1. In the **gradlew file path** input, set the path to your `gradlew` file, relative to the root of the repository. ![install-sdk.png](/img/_paligo/uuid-3138c36f-fad8-3630-46b8-dfd9910807cc.png) 1. If you use the Native Development Kit in your project, set the required version in the **NDK version** input. If you don't use NDK, leave the input empty. 1. In the **Additional options for the gradlew dependencies command** input, you can set flags in addition to the default command call. ### Caching Gradle dependencies With key-based caching, you only need the [**Restore Gradle cache**](https://github.com/bitrise-steplib/bitrise-step-restore-gradle-cache) and the [**Save Gradle cache**](https://github.com/bitrise-steplib/bitrise-step-save-gradle-cache) Steps to cache your Gradle dependencies. These Steps require no configuration as they automatically set up the cache keys needed for your dependencies. 1. Add the [**Restore Gradle cache**](https://github.com/bitrise-steplib/bitrise-step-restore-gradle-cache) Step to your Workflow ![restore-gradle.png](/img/_paligo/uuid-527aa0a4-a647-f9e9-7a56-ea38c1366f33.png) It should come before any Step that handles dependencies in any way, such as [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build). 1. Add the [**Save Gradle Cache**](https://github.com/bitrise-steplib/bitrise-step-save-gradle-cache) Step to the end of your Workflow. --- ## Dependencies and caching overview Handling platform and application dependencies is a vital part of development. On Bitrise, we offer several dedicated Steps to make sure you can install your dependencies regardless of project type. Dependencies, and just about any other build files, can be cached, too. Bitrise offers several dedicated Steps to make caching as convenient as possible. ### iOS dependencies Install iOS dependencies via our official Xcode Steps which offer built-in dependency management, or use our Steps for the most commonly used third-party dependency managers: [iOS dependencies](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-carthage) - Use the official Xcode Steps to handle Swift Package Manager dependencies without having to worry about configuring anything outside Xcode: [Managing dependencies with SPM](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-spm). - If you use CocoaPods, and have your `Podfile` configured, you can use our [**Run CocoaPods install**](https://github.com/bitrise-io/steps-cocoapods-install) Step to install your pods: [Managing dependencies with CocoaPods](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-cocoapods). - If you use Carthage in your project, you can use our [**Carthage**](https://github.com/bitrise-steplib/steps-carthage) Step to install your dependencies: [Managing dependencies with Carthage](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-carthage). ### Android dependencies Our official Android Steps run your Gradle tasks for you in a CI environment. As such, if your dependencies are appropriately configured within your project, they will handle installing them for you: [Android dependencies](/bitrise-ci/dependencies-and-caching/android-dependencies). ### Flutter dependencies For Flutter, our [**Flutter Build**](https://github.com/bitrise-steplib/bitrise-step-flutter-build) Step can handle both packages and plugins so you don't need to add any additional Step to install your dependencies: [Flutter dependencies](/bitrise-ci/dependencies-and-caching/flutter-dependencies). ### React Native dependencies For React Native, you can install npm packages via either npm or Yarn, as we have official Steps for both package managers. You can also install your native dependencies separately: [React Native dependencies](/bitrise-ci/dependencies-and-caching/react-native-dependencies) ### Caching Our caching solution allows you to cache just about any build file you want. You can cache all of your dependencies with barely any configuration as several Steps can automatically collect and cache dependency content. For other build files, the main caching Steps are fully configurable to fit your needs. #### Key-based caching Key-based caching relies on using key-value pairs to identify cache archives. The keys can be dynamically generated so you can ensure, for example, that the archive is only updated if certain files change. You have full control over assigning keys to your cache archives: [Key-based caching](/bitrise-ci/dependencies-and-caching/key-based-caching/accessing-key-based-cache-archives). #### Caching dependencies We have dedicated Steps for all the most frequently used dependency managers. - [Managing dependencies with SPM](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-spm) - [Managing dependencies with CocoaPods](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-cocoapods) - [Managing dependencies with Carthage](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-carthage) - [Android dependencies](/bitrise-ci/dependencies-and-caching/android-dependencies) - [Flutter dependencies](/bitrise-ci/dependencies-and-caching/flutter-dependencies) - [React Native dependencies](/bitrise-ci/dependencies-and-caching/react-native-dependencies) ### Bitrise Build Cache The Bitrise Build Cache is a custom, hosted implementation for remote caching of certain build systems. You can use the remote cache both locally and in the Bitrise CI environment: in this way your builds will work consistently regardless of the environment and you can save a significant amount of build time. Bitrise supports the Bitrise Build Cache for the following build systems: - [Build Cache for Gradle](/bitrise-build-cache/build-cache-for-gradle/configuring-the-build-cache-for-gradle-in-the-bitrise-ci-environment) - [Build Cache for Bazel](/bitrise-build-cache/build-cache-for-bazel/configuring-the-build-cache-for-bazel-in-the-bitrise-ci-environment) - [Build Cache for Xcode](/bitrise-build-cache/build-cache-for-xcode/configuring-the-build-cache-for-xcode-in-the-bitrise-ci-environment) - [Build Cache for React Native](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-the-bitrise-ci-environment) --- ## Flutter dependencies Flutter supports using shared packages as app dependencies. The packages you can use in your app can be divided into two broad types: - Dart packages use only Dart code and can contain dependencies, apps, resources, or tests. - Plugins are a special type of package, containing both native Android or iOS code, as well as Dart code. They make platform functionality available to your Flutter apps. Bitrise Steps can handle both types, and we have efficient caching solutions for all Flutter dependencies. ### Installing dependencies for Flutter apps Our [**Flutter Build**](https://github.com/bitrise-steplib/bitrise-step-flutter-build) Step can build both the iOS and Android apps of a Flutter project. The Step runs the `flutter pub get` command to install all dependencies found in your project's `pubspec.yaml` file, including plugin packages. As such, it's really simple to add dependencies to a Flutter app on Bitrise. :::tip[Package interdependencies] If your app's dependencies include plugin packages that require access to platform-specific APIs, you need to add the appropriate dependency declarations to the platform-specific build files. For example, you might need to declare a Gradle dependency in the `pubspec.yaml` file and in your project's `build.gradle` file as well. For more information, check out the official Flutter documentation: [Handling package interdependencies](https://docs.flutter.dev/development/packages-and-plugins/developing-packages#dependencies). ::: **Workflow Editor** 1. [Add dependencies](https://docs.flutter.dev/development/packages-and-plugins/using-packages#adding-a-package-dependency-to-an-app) to your Flutter project's `pubspec.yaml` file. 1. On Bitrise, add the [**Flutter Install**](https://github.com/bitrise-steplib/bitrise-step-flutter-installer) Step to your Workflow to install the Flutter SDK. In the **Flutter SDK version or bundle URL** input, set a channel name (such as `stable`) to always install the latest release in that channel, or set an exact version tag to pin the installed version. 1. Add the [**Flutter Build**](https://github.com/bitrise-steplib/bitrise-step-flutter-build) Step to your Workflow. ![flutter-build-step.png](/img/_paligo/uuid-98bd1fcb-463a-c828-a627-5d3adaf78d32.png) The Step can build both the iOS and Android apps of a Flutter project. If your app's repository contains the necessary build files, it will download and install all required dependencies. **Configuration YAML** 1. [Add dependencies](https://docs.flutter.dev/development/packages-and-plugins/using-packages#adding-a-package-dependency-to-an-app) to your Flutter project's `pubspec.yaml` file. 1. On Bitrise, add the `flutter-installer` Step to your Workflow to install the Flutter SDK. In the **Flutter SDK version or bundle URL** (`version`) input, set a channel name (such as `stable`) to always install the latest release in that channel: ```yaml your-workflow: steps: - git-clone: {} - flutter-installer: inputs: - version: stable ``` Or set an exact version tag to pin the installed version: ```yaml your-workflow: steps: - git-clone: {} - flutter-installer: inputs: - version: 3.32.5 ``` 1. Add the `flutter-build` Step to your Workflow. ```yaml your-workflow: steps: - git-clone: {} - flutter-installer: inputs: - version: stable - flutter-build: {} ``` The Step can build both the iOS and Android apps of a Flutter project. If your app's repository contains the necessary build files, it will download and install all required dependencies. ### Caching dependencies for Flutter apps With key-based caching, you only need the [**Restore Dart cache**](https://github.com/bitrise-steplib/bitrise-step-restore-dart-cache) and the [**Save Dart cache**](https://github.com/bitrise-steplib/bitrise-step-save-dart-cache) Steps to cache your Dart dependencies. These Steps require no configuration as they automatically set up the cache keys needed for your dependencies. 1. Add the [**Restore Dart cache**](https://github.com/bitrise-steplib/bitrise-step-restore-dart-cache) Step before the [**Flutter Build**](https://github.com/bitrise-steplib/bitrise-step-flutter-build) Step. We also recommend placing it after the [**Flutter Install**](https://github.com/bitrise-steplib/bitrise-step-flutter-installer) Step. ![restore-dart-cache.png](/img/_paligo/uuid-48b2ff90-e029-0d70-f0d7-f0b05e989540.png) 1. Add the [**Save Dart cache**](https://github.com/bitrise-steplib/bitrise-step-save-dart-cache) Step to the end of your Workflow. --- ## Managing dependencies with Carthage [Carthage](https://github.com/Carthage/Carthage) is a dependency manager for iOS and macOS. It's a decentralized dependency manager that doesn't alter your Xcode project in any way. You can use it on Bitrise, too, to handle dependencies for your iOS apps. ### Installing Carthage dependencies To install your dependencies with Carthage: **Workflow Editor** 1. Make sure you have a [Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile) included in your project. 1. Add the **Carthage** Step to your Workflow. It should come after any Step that pulls from the cache. If you don't have any caching Steps, add the Step right after the [**Git Clone Repository**](https://github.com/bitrise-steplib/steps-git-clone) Step. 1. In the **Carthage command to run** input, select the command you wish to run. ![carthage-command.png](/img/_paligo/uuid-71148b6a-fbf8-6a5f-5423-a5ac2817e866.png) The default value is `bootstrap`. For a list of available commands, run `carthage help` on a device with Carthage installed. 1. You can add options to the Carthage call in the **Additional options for carthage command** input. For example, the `--platform ios` flag ensures that only the iOS version of frameworks will be installed. **Configuration YAML** 1. Make sure you have a [Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile) included in your project. 1. Add the `carthage` Step to your Workflow. It should come after any Step that pulls from the cache. If you don't have any caching Steps, add the Step right after the `git-clone` Step. ```yml my-workflow: steps: - activate-ssh-key: {} - git-clone: {} - restore-carthage-cache: {} - carthage: - save-carthage-cache: {} ``` 1. In the `carthage_command` input, select the command you wish to run. The default value is `bootstrap`. For a list of available commands, run `carthage help` on a device with Carthage installed. ```yml my-workflow: steps: - activate-ssh-key: {} - git-clone: {} - restore-carthage-cache: {} - carthage: inputs: - carthage_command: bootstrap - save-carthage-cache: {} ``` 1. You can add options to the Carthage call in the `carthage_options` input. For example, the `--platform ios` flag ensures that only the iOS version of frameworks will be installed. ```yml my-workflow: steps: - activate-ssh-key: {} - git-clone: {} - restore-carthage-cache: {} - carthage: inputs: - carthage_command: bootstrap - carthage_options: "--platform ios" - save-carthage-cache: {} ``` ### Caching Carthage dependencies With key-based caching, you only need the [**Restore Carthage cache**](https://github.com/bitrise-steplib/bitrise-step-restore-carthage-cache) and the [**Save Carthage cache**](https://github.com/bitrise-steplib/bitrise-step-save-carthage-cache) Steps to cache your dependencies. These Steps require no configuration as they automatically set up the cache keys and cache paths. 1. Add the [**Restore Carthage cache**](https://github.com/bitrise-steplib/bitrise-step-restore-carthage-cache) Step to your Workflow ![carthage-command.png](/img/_paligo/uuid-71148b6a-fbf8-6a5f-5423-a5ac2817e866.png) It should come before the [**Carthage**](https://github.com/bitrise-steplib/steps-carthage) Step or any Step that needs dependencies to build your app, such as [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive). 1. Add the [**Save Carthage cache**](https://github.com/bitrise-steplib/bitrise-step-save-carthage-cache) Step to the end of your Workflow. --- ## Managing dependencies with CocoaPods [CocoaPods](https://cocoapods.org/) is a dependency manager for Swift and Objective-C Cocoa projects. An iOS app with CocoaPods dependencies needs to have a `Podfile` with a number of pods listed in it: these pods are installed during the process of building the app. You can, of course, easily install CocoaPods dependencies during a Bitrise build. You just need our dedicated Step: **[Run CocoaPods Install](https://github.com/bitrise-io/steps-cocoapods-install)**. The Step can run both `pod install` and `pod update` commands. ### Installing CocoaPods dependencies To install your dependencies with CocoaPods: **Workflow Editor** 1. If you need a specific version of CocoaPods, make sure you define it either in the `Gemfile.lock` or the `Podfile.lock` file. The Step first looks for the `cocoapods` gem in the `Gemfile.lock` file. If there's no `cocoapods` gem there, the Step uses the CocoaPods version defined in the `Podfile.lock` file. If the version is not defined in either file, the preinstalled system version will be used which you can check in the [system reports](https://github.com/bitrise-io/bitrise.io/tree/master/system_reports/MACOS). 1. Make sure that the Xcode Step building your app uses your `.xcworkspace` file: the **Project path** input of the Step should point to the path of `.xcworkspace`. 1. Add the [**Run CocoaPods Install**](https://github.com/bitrise-io/steps-cocoapods-install) Step to your Workflow. It should come after any Step that pulls [from the build cache](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache). If you don't have any caching Steps, add the Step right after the [**Git Clone Repository**](https://github.com/bitrise-steplib/steps-git-clone) Step. 1. In the **CocoaPods command** input, select the command you wish to run. **install**: Installs the version specified in the `Podfile` for each pod. **update**: Installs the latest version for each pod listed in the `Podfile`. ![pod-install.png](/img/_paligo/uuid-92405804-e42c-f788-4026-7339492f1113.png) 1. Optionally, you can specify a path to your `Podfile` in the **Podfile path** input. This is not mandatory: if you leave the input empty, the Step performs a recursive search in the root directory of your app, and uses the first `Podfile` it finds. **Configuration YAML** 1. If you need a specific version of CocoaPods, make sure you define it either in the `Gemfile.lock` or the `Podfile.lock` file. The Step first looks for the `cocoapods` gem in the `Gemfile.lock` file. If there's no `cocoapods` gem there, the Step uses the CocoaPods version defined in the `Podfile.lock` file. If the version is not defined in either file, the preinstalled system version will be used which you can check in the [stack reports](https://stacks.bitrise.io/stack_reports/). 1. Make sure that the Xcode Step building your app uses your `.xcworkspace` file: the `project_path` input of the Step should point to the path of `.xcworkspace`. 1. Add the `cocoapods-install` Step to your Workflow. It should come after any Step that pulls [from the build cache](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache). If you don't have any caching Steps, add the Step right after the `git-clone` Step. ```yml my-workflow: steps: - activate-ssh-key: {} - git-clone: {} - restore-cocoapods-cache: {} - cocoapods-install: is_always_run: true - save-cocoapods-cache: {} ``` 1. In the `command` input, select the command you wish to run. **install**: Installs the version specified in the `Podfile` for each pod. **update**: Installs the latest version for each pod listed in the `Podfile`. ```yml my-workflow: steps: - activate-ssh-key: {} - git-clone: {} - restore-cocoapods-cache: {} - cocoapods-install: is_always_run: true inputs: - command: update - save-cocoapods-cache: {} ``` 1. Optionally, you can specify a path to your `Podfile` in the `podfile_path` input. ```yml my-workflow: steps: - activate-ssh-key: {} - git-clone: {} - restore-cocoapods-cache: {} - cocoapods-install: is_always_run: true inputs: - command: update - podfile_path: ./path/to/podfile/ - save-cocoapods-cache: {} ``` This is not mandatory: if you leave the input empty, the Step performs a recursive search in the root directory of your app, and uses the first `Podfile` it finds. ### Caching CocoaPods dependencies With key-based caching, you only need the [**Restore CocoaPods cache**](https://github.com/bitrise-steplib/bitrise-step-restore-cocoapods-cache) and the [**Save CocoaPods cache**](https://github.com/bitrise-steplib/bitrise-step-save-cocoapods-cache) Steps to cache your pods. These Steps require no configuration as they automatically set up the cache keys needed for your dependencies. 1. Add the [**Restore CocoaPods cache**](https://github.com/bitrise-steplib/bitrise-step-restore-cocoapods-cache) Step to your Workflow It should come before the [**Run CocoaPods install**](https://github.com/bitrise-io/steps-cocoapods-install) Step or any Step that needs dependencies to build your app, such as [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive). ![restore-pods.png](/img/_paligo/uuid-3305dee6-a952-5073-e44b-02fd8c3925c1.png) 1. Add the [**Save CocoaPods cache**](https://github.com/bitrise-steplib/bitrise-step-save-cocoapods-cache) Step to the end of your Workflow. --- ## Managing dependencies with SPM Swift packages are reusable components of Swift, Objective-C, Objective-C++, C, or C++ code that developers can use in their projects. Xcode uses the built-in Swift Package Manager (SPM) to support creating and publishing Swift packages and managing package dependencies. On Bitrise, every Xcode Step can handle Swift package dependencies without any extra configuration. For example, if you wish to build an iOS app to deploy it to the App Store, the [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive) Step will handle installing Swift dependencies to your app. ### Installing Swift packages You can easily install Swift packages for your iOS apps during a Bitrise build: 1. Make sure you have correctly configured your Swift packages in Xcode. 1. Add one of our official Xcode Steps to your Workflow. The available Steps are: - [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive) - [**Xcode Test for iOS**](https://github.com/bitrise-steplib/steps-xcode-test) - [**Xcode Build for testing for iOS**](https://github.com/bitrise-steplib/steps-xcode-build-for-test) - [**Xcode Build for Simulator**](https://github.com/bitrise-steplib/steps-xcode-build-for-simulator) Any of these Steps can handle the Swift package dependencies. ### Caching Swift packages With key-based caching, you only need the [**Restore SPM cache**](https://github.com/bitrise-steplib/bitrise-step-restore-spm-cache) and the [**Save SPM cache**](https://github.com/bitrise-steplib/bitrise-step-save-spm-cache) Steps to cache your Swift packages. These Steps require no configuration as they automatically set up the cache keys needed for your dependencies. 1. Add the [**Restore SPM cache**](https://github.com/bitrise-steplib/bitrise-step-restore-spm-cache) Step to your Workflow ![restore_spm-cache.png](/img/_paligo/uuid-e51ea807-fef9-bfc9-8666-2092740c7a52.png) It should come before any Step that handles SPM packages in any way, such as [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive). 1. Add the [**Save SPM cache**](https://github.com/bitrise-steplib/bitrise-step-save-spm-cache) Step to the end of your Workflow. --- ## Accessing key-based cache archives You can access your cache archives separately, without running a build. This allows you to keep track of several things: - What cache keys are associated with different cache archives. - How much storage space is taken up by your cache archives. - When each cache archive is due to expire. In addition, you can download any cache archive - if it hasn't expired yet -, you can copy the cache keys, and you can delete archives. To access your archives: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left side, select **Dependency cache**. 1. Click the actions menu next to a cache archive, then select one of the following: - **Copy key** to copy the cache key. - **Download** to download the cache archive. - **Delete** to delete the cache archive. :::note Cache archives are compressed with [Zstandard](https://github.com/facebook/zstd). To decompress a downloaded archive, install `zstd`, then run `zstd -d cache.tzst`. ::: --- ## Dedicated caching Steps for dependency managers Key-based caching is powerful and flexible: you can use the [**Save cache**](https://github.com/bitrise-steplib/bitrise-step-save-cache) and [**Restore cache**](https://github.com/bitrise-steplib/bitrise-step-restore-cache) Steps with any project, regardless of platform or the type of data you want to cache. However, these Steps require careful configuration and it is possible to make mistakes. If you are looking for a simple solution to cache dependencies of the most frequently used dependency managers, we offer dedicated Steps that require no configuration whatsoever. The dedicated caching Steps store their archives in the same storage space as the [**Save cache**](https://github.com/bitrise-steplib/bitrise-step-save-cache) and [**Restore cache**](https://github.com/bitrise-steplib/bitrise-step-restore-cache) Steps but unlike those two, they automatically set up the appropriate cache paths and cache keys. The following dedicated Steps are available: - [**Save Cocoapods Cache**](https://github.com/bitrise-steplib/bitrise-step-save-cocoapods-cache) and [**Restore Cocoapods Cache**](https://github.com/bitrise-steplib/bitrise-step-restore-cocoapods-cache): [Managing dependencies with CocoaPods](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-cocoapods). - [**Save SPM Cache**](https://github.com/bitrise-steplib/bitrise-step-save-spm-cache) and [**Restore SPM Cache**](https://github.com/bitrise-steplib/bitrise-step-restore-spm-cache): [Managing dependencies with SPM](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-spm). - [**Save NPM Cache**](https://github.com/bitrise-steplib/bitrise-step-save-npm-cache) and [**Restore NPM Cache**](https://github.com/bitrise-steplib/bitrise-step-restore-npm-cache): [React Native dependencies](/bitrise-ci/dependencies-and-caching/react-native-dependencies). - [**Save Gradle Cache**](https://github.com/bitrise-steplib/bitrise-step-save-gradle-cache) and [**Restore Gradle Cache**](https://github.com/bitrise-steplib/bitrise-step-restore-gradle-cache): [Android dependencies](/bitrise-ci/dependencies-and-caching/android-dependencies). - [**Save Carthage Cache**](https://github.com/bitrise-steplib/bitrise-step-save-carthage-cache) and [**Restore Carthage Cache**](https://github.com/bitrise-steplib/bitrise-step-restore-carthage-cache): [Managing dependencies with Carthage](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-carthage). - [**Save Dart Cache**](https://github.com/bitrise-steplib/bitrise-step-save-dart-cache) and [**Restore Dart Cache**](https://github.com/bitrise-steplib/bitrise-step-restore-dart-cache): [Flutter dependencies](/bitrise-ci/dependencies-and-caching/flutter-dependencies). To use these Steps, simply add the Restore version to the start of your Workflow and the Save version to the end of your Workflow. No other configuration is needed. --- ## Using key-based caching Key-based caching requires two Steps that must be used together: - [**Save Cache**](https://github.com/bitrise-steplib/bitrise-step-save-cache): saves the build files into a cache archive, identified by a key. - [**Restore Cache**](https://github.com/bitrise-steplib/bitrise-step-restore-cache): restores build files into a cache archive, identified by a key. :::note[Dedicated key-based caching Steps] You can use dedicated key-based caching Steps, such as the [Save NPM Cache](https://github.com/bitrise-steplib/bitrise-step-save-npm-cache), to cache npm or yarn dependencies. For a full list of dedicated key-based caching Steps, check out [Dedicated caching Steps for dependency managers](/bitrise-ci/dependencies-and-caching/key-based-caching/dedicated-caching-steps-for-dependency-managers). ::: Both Steps access cache archives via key strings. These keys need to be specified as the values of the **Cache keys** [Step input](/bitrise-ci/workflows-and-pipelines/steps/step-inputs); each key identifies a separate cache archive. ### Cache retention and eviction policy Your cache entries are retained for seven days since the last use. If they're not used in your workflows for a continuous period of seven days, they will be automatically removed. If you run out of your cache storage allowance, the Least Recently Used (LRU) cache entries on your app will be replaced with any new ones produced. LRU is a cache replacement algorithm that removes the least recently used data in order to make room for new data. This might mean that your cache hit rate could reduce if the replaced cache entries are needed by any Workflows. We recommend upgrading to [a higher plan](http://www.bitrise.io/pricing) to get more storage so that you don't lose any cache entries that might be needed by your Workflows. ### Creating a new cache archive 1. Add the [**Save Cache**](https://github.com/bitrise-steplib/bitrise-step-save-cache) Step at the end of your Workflow. 1. In the **Cache key** input, define a cache key. This key will be used to identify the cache archive. :::important[Key limitations] The maximum length of a cache key is 512 characters (longer keys get truncated). Commas (,) are not allowed in keys. ::: You can use [templates and functions](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching#key-based-caching-templates-and-functions) to create dynamic keys that change depending on the build environment or other factors. :::tip[Conditional caching with dynamic keys] You can configure the Step in a way that allows it to automatically skip archiving and uploading the cache if its content has not changed during the build: [Conditional caching](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching#using-conditional-caching-with-dynamic-keys). ::: **Creating a new cache archive with a key referring to the OS** In this example, we're creating a cache archive with a key that refers to the type of the operating system of the build machine. ```yaml - save-cache@1: inputs: - key: |- npm-cache-{{ .OS }} ``` 1. In the **Paths to cache** input, define the files and folders that you want to cache. The input allows for wildcards: `*` and `**`. The input value is evaluated at runtime. :::caution[Archive size limit] The size of a single cache archive cannot exceed 15 GB. ::: **Caching all files and folders recursively in the node_modules folder** ```yaml - save-cache@1: inputs: - key: |- npm-cache-{{ .OS }} - paths: node_modules/ ``` Once a cache archive has been created, you can access it on the **App Settings** page: [Accessing key-based cache archives](/bitrise-ci/dependencies-and-caching/key-based-caching/accessing-key-based-cache-archives). ### Restoring an existing cache archive 1. Add the [**Restore Cache**](https://github.com/bitrise-steplib/bitrise-step-restore-cache) Step at the start of your Workflow. 1. In the **Cache key** input, type the key of the cache that you want to restore. You can use [templates and functions](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching#key-based-caching-templates-and-functions) to create dynamic keys that change depending on the build environment or other factors. You can specify multiple keys; the Step will evaluate them in order and select the first matching one. Read more: [Key matching for cache archives](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching#key-matching-for-cache-archives). **Restoring a cache archive from one of two keys** In this example, we're restoring one of two keys: - First, we'll look for a cache archive with a key that includes the name of the current Workflow. For example, if the current Workflow's name is `primary`, the Step will look for an archive with the key `npm-cache-primary`. - Second, we'll look for an archive with a key that includes the name of the current branch. For example, if the current branch's name is `main`, the Step will look for an archive with the key `npm-cache-main`. ```yaml - restore-cache@1: inputs: - key: |- npm-cache-{{ .Workflow }} npm-cache-{{ .Branch }} ``` ### Key-based caching templates and functions Both key-based caching Steps support using template elements in their Step inputs. The Steps evaluate the key template at runtime and the final cache key to be used can change depending on the build environment or on certain files in the repository. #### Available caching templates | Template expression | Definition | Possible values | | --- | --- | --- | | `cache-key-{{ .Branch }}` | Current git branch the build runs on. | The exact name of any existing branch of the app. | | `cache-key-{{ .CommitHash }}` | SHA-256 hash of the git commit the build runs on. | Any existing commit hash. | | `cache-key-{{ .Workflow }}` | Current Bitrise workflow name (for example, `primary`). | The exact name of any existing Workflow of the app. | | `{{ .OS }}-cache-key` | Current operating system of the build stack (`linux` or `darwin`). | - `linux`: For Linux-based stacks. - `darwin`: For macOS-based stacks. | #### Using functions in caching templates The key-based caching templates support the use of two different functions: - `checksum`: This function computes the SHA-256 checksum of the contents of one or more files. This is useful for creating unique cache keys based on files that describe content to cache. See the examples below. - `getenv`: This function returns the value of an [Environment Variable](/bitrise-ci/configure-builds/environment-variables) (Env Var) or an empty string if the variable is not defined. See the examples below. **Using the checksum function** Use the `checksum` function to create a key that computes the checksum of the `package-lock.json` file: ```yaml - save-cache@1: inputs: - key: npm-cache-{{ checksum "package-lock.json" }} - paths: node_modules ``` Use the `checksum` function to create a key that computes a checksum for any `.gradle` file and the `gradle.properties` file: ```yaml - save-cache@1: inputs: - key: gradle-cache-{{ checksum "**/*.gradle*" "gradle.properties" }} - paths: AndroidApp ``` **Using the getenv function** Use the `getenv` function to create a key that contains the value of the BITRISE_BUILD_NUMBER Env Var. ```yaml - save-cache@1: inputs: - key: npm-cache-{{ getenv "BITRISE_BUILD_NUMBER" }} - paths: node_modules ``` ### Key matching for cache archives It's possible to define more than one key in the **Cache keys** input of the key-based caching Steps. You can specify additional keys by listing one key per line. The list is in priority order, so the Step will first try to find a match for the first key you provided, and if there is no cache stored for the key, it will move on to find a match for the second key (and so on). ```yaml inputs: key: | key-1 key-2 key-3 ``` In addition to listing multiple keys, each key can be a prefix of a saved cache key and still get a matching cache archive. For example, the key `my-cache-` can match an existing archive saved with the key `my-cache-a6a102ff`. We recommend configuring the keys in a way that the first key is an exact match to a checksum key, and to use a more generic prefix key as a fallback: ```yaml inputs: key: | npm-cache-{{ checksum "package-lock.json" }} npm-cache- ``` ### Using conditional caching with dynamic keys You might not want to update a cache archive every time you run a build. By skipping caching, you can: - Avoid saving potentially incorrect build data in the cache. - Make the PR validation workflow faster. - Limit the amount of data stored and transferred. If the cached content did not change during your build at all, the **Save cache** Step can automatically skip compressing and uploading the cache. To make this work, you need to make sure your cache archive has a unique cache key that changes whenever the contents of the cache change: in practice, this requires [a dynamic key with a checksum](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching#key-based-caching-templates-and-functions) and a file that describes the cached content. The checksum will be calculated based on the contents of the file; if the file remains unchanged, so does the checksum. We strongly recommend configuring the Step in a way to take advantage of this feature. Follow the steps below, or skip ahead to the YAML example at the end of this section. :::tip[Skipping the Save cache Step entirely] If you don't wish to update the cache archive even if the content that would be cached has changed, you can either remove the **Save cache** Step from your Workflow or you can set conditions for the Step: [Enabling or disabling a Step conditionally](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally). ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Open your Workflow and select the **Save cache** Step. 1. Set the **Unique cache key** input to `true`. If the input is set to `false`, the Step can still skip uploading the cache but it will need to create the cache archive first to calculate its checksum. This takes time. 1. In the **Cache key** input, create a key with a checksum for a file that describes the cached content. For example, `npm-cache-{{ checksum "package-lock.json" }}` is a dynamic key that remains unchanged as long as the `package-lock.json` file does not change. 1. Add the same dynamic key to the **Cache keys** input of the **Restore cache** Step. If everything is configured correctly, if the keys in the two caching Steps match, the cache archive will not be updated. **YAML example for using a dynamic key with checksum** In this example, the cache key calculates the sum for any `.gradle` file and the `gradle.properties` file. Both the **Restore cache** and the **Save cache** Step looks for the same cache key: ```yaml workflows: caching: steps: - restore-cache@1: inputs: - key: gradle-cache-{{ checksum "**/*.gradle*" "gradle.properties" }} - save-cache@1: inputs: - key: gradle-cache-{{ checksum "**/*.gradle*" "gradle.properties" }} - is_key_unique: 'true' ``` --- ## Migrating from branch-based caching to key-based caching Branch-based caching is a legacy technology that Bitrise has deprecated. Use the more efficient and flexible Key-based caching. If your builds are using smaller cache archives than 15 GB then the branch-based caching Steps will keep working but we still recommend migrating the key-based caching as it results in better caching performance in almost all cases. This guide will help you transition your projects to the key-based caching infrastructure. ### Differences between caching systems Key-based caching is generally more efficient and far more powerful than branch-based caching. In the table, we compare the two caching methods based on their feature set. | Features | Branch-based caching | Key-based caching | | --- | --- | --- | | **Cache scope** | One cache per branch | Multiple caches identified by keys | | **Cache sharing across builds** | Limited to same branch and stack | Can be shared across Workflows, branches, and stacks | | **Steps used** | [Cache:Pull](https://bitrise.io/integrations/steps/cache-pull) and [Cache:Push](https://bitrise.io/integrations/steps/cache-push) | - The generic [Restore Cache](https://bitrise.io/integrations/steps/restore-cache) and [Save Cache](https://bitrise.io/integrations/steps/save-cache) Steps - [Dedicated caching steps for six dependency managers](/bitrise-ci/dependencies-and-caching/key-based-caching/dedicated-caching-steps-for-dependency-managers) | | **Expiration** | Seven days without new build on branch | Seven days since last use | | **Fallback mechanism** | Default branch cache used as fallback | Multiple fallback keys can be configured | | **Maximum cache archive size** | No limit (until migration stated) | 15 GB | | **Adding files/paths to the cache archive** | Configured manually or by other Bitrise steps supporting caching | Configured manually or via the dedicated caching Steps | | **Ignoring files** | `Ignore paths` parameter | No separate ignore list | | **Performance/speed** | Slower (larger gzip archives and slower storage backend) | Faster (state-of-the art [zstd](https://github.com/facebook/zstd) compression and faster storage backend) | | **Dedicated caching Steps for dependency managers** | Not available | Available for [most dependency managers](/bitrise-ci/dependencies-and-caching/key-based-caching/dedicated-caching-steps-for-dependency-managers) | ### Replacing branch-based caching Steps There are two ways to use key-based caching: either via the generic **Restore Cache** and **Save Cache** Steps or via the dedicated caching Steps for specific dependency managers. We strongly recommend using the dedicated Steps, unless your dependency manager is not supported or you need some special configuration. #### Using the dedicated caching Steps Dedicated caching Steps cache dependencies for a specific dependency manager. For example, if you run Gradle in your build, you can cache Gradle dependencies with the dedicated Steps. The dedicated Steps usually don't need any further configuration: you just add them to your Workflow: :::tip[Full list of dedicated Steps] The procedure below is only an example for using dedicated key-based caching Steps. The example uses Gradle but we have several dedicated Steps. For the detailed list of Steps, see: [Dedicated caching Steps for dependency managers](/bitrise-ci/dependencies-and-caching/key-based-caching/dedicated-caching-steps-for-dependency-managers). ::: 1. Replace the **Cache:Pull** Step with the **Restore Gradle Cache** Step in your Workflow. This Step will download your Gradle cache. 1. Replace the **Cache:Push** Step with the **Save Gradle Cache** Step. This Step updates the Gradle cache. All key-based caching Steps follow a similar naming convention: the Restore Steps download the cache while the Save Steps update it. After you ran at least two builds with a key-based setup, you can find and download the cache archive from the **Project settings** page: [Accessing key-based cache archives](/bitrise-ci/dependencies-and-caching/key-based-caching/accessing-key-based-cache-archives). #### Using the generic key-based caching Steps If the dedicated caching Steps don't produce the desired results, consider using the generic **Restore Cache** and **Save Cache** Steps. You can configure these Steps to perfectly fit your needs. You can: - [Use key-based caching templates and functions](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching#key-based-caching-templates-and-functions). - [Define multiple keys to match your cache archives](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching#key-matching-for-cache-archives). - [Use conditional caching with dynamic keys](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching#using-conditional-caching-with-dynamic-keys). :::tip[Cache recipes with the generic Steps] Check out our key-based cache recipes utilising the generic Steps: [Advanced key-based cache recipes](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/key-cache-advanced.md). ::: --- ## React Native dependencies [npm](https://docs.npmjs.com/) and [Yarn](https://yarnpkg.com/) are both package managers for Node.js. They can manage the dependencies of a project, or globally installed Javascript tools. For mobile development, they are frequently used as package managers for React Native projects. If you have a React Native app on Bitrise, you can use our dedicated npm or Yarn Steps to install and cache your dependencies. You can also install native dependencies by using the dedicated Steps: [Installing native dependencies for a React Native app](#installing-native-dependencies-for-a-react-native-app). ### Installing dependencies with npm and Yarn **npm** 1. Make sure your project has [a package.json file](https://docs.npmjs.com/creating-a-package-json-file) defined in it. 1. Add the [**Run npm command**](https://github.com/bitrise-steplib/steps-npm) Step to your Workflow. 1. Set the **The npm command with arguments to run** to `install`. You can add additional options to the `install` command. For example, if you need to [link a library with native dependencies to your React Native project](https://docs.flutter.dev/development/packages-and-plugins/developing-packages#dependencies), use the `--save` or `--save-dev` flag. For the available options, see the [npm documentation](https://docs.npmjs.com/cli/v9/commands/npm-install). ![run-npm-command.png](/img/_paligo/uuid-676b848d-85db-ff48-883e-6ca489d799d3.png) 1. Optionally, you can set [the npm version](https://www.npmjs.com/package/npm?activeTab=versions) that will run the `npm install` command in the **Version of npm to use** input. **Yarn** 1. Make sure your project has [a package.json file](https://docs.npmjs.com/creating-a-package-json-file) defined in it. 1. Add the [**Run yarn command**](https://github.com/bitrise-community/steps-yarn) Step to your Workflow. 1. Set the **Yarn command to run** to `install`. 1. Optionally, add arguments to the yarn command in the **Arguments for running yarn commands**. You can specify multiple arguments, separated by a space. ### Caching npm and Yarn dependencies With key-based caching, you only need the [**Restore NPM cache**](https://github.com/bitrise-steplib/bitrise-step-restore-npm-cache) and the [**Save NPM cache**](https://github.com/bitrise-steplib/bitrise-step-save-npm-cache) Steps to cache your node modules. These Steps require no configuration as they automatically set up the cache keys needed for your dependencies. 1. Add the [**Restore NPM cache**](https://github.com/bitrise-steplib/bitrise-step-restore-npm-cache) Step to the start of your Workflow. ![restore-npm-cache.png](/img/_paligo/uuid-68fb84b2-a10a-f7b9-f1e3-7ab0accbae3a.png) 1. Add the [**Save NPM cache**](https://github.com/bitrise-steplib/bitrise-step-save-npm-cache) Step to the end of your Workflow. ### Installing native dependencies for a React Native app You might need to install native dependencies that are declared in the `ios` and `android` folders. For example, CocoaPods dependencies defined in a `Podfile`. You can do this quite easily on Bitrise, too: once you bundle your React Native app to be ready to build the Android and iOS binaries, you can simply use the dependency manager Steps for Android and iOS apps. :::tip[Demo app] Check out our React Native demo app for a working example. If you add the app to Bitrise, you can see that the **deploy-ios-release** Workflow, for example, contains both the [**Run npm command**](https://github.com/bitrise-steplib/steps-npm) and the [**Run CocoaPods install**](https://github.com/bitrise-io/steps-cocoapods-install) Steps, to install both npm packages and pods: [React Native demo app](https://github.com/bitrise-io/react-native-demo-app). ::: 1. Make sure your Workflow installs your npm packages: [Installing dependencies with npm and Yarn](#installing-dependencies-with-npm-and-yarn). You can have a separate Workflow that is only responsible for installing npm packages, and it's inserted to run before your main Workflow: [Chaining Workflows together](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#chaining-workflows-together). It can be a [utility Workflow](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#utility-workflows). 1. Add the [**React Native Bundle**](https://github.com/bitrise-steplib/steps-react-native-bundle) Step to your Workflow. It must come after the npm packages are installed. 1. Add the required dependency manager Steps or build Steps to the Workflow. The exact Steps you need depend on the project type and the dependency manager you use: - [Android dependencies](/bitrise-ci/dependencies-and-caching/android-dependencies) - [Managing dependencies with SPM](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-spm) - [Managing dependencies with CocoaPods](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-cocoapods) - [Managing dependencies with Carthage](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-carthage) --- ## Deploying Android apps to Bitrise and Google Play This guide describes how you can add your Android project to [bitrise.io](https://www.bitrise.io) and deploy the APK or AAB built from your project to [Google Play Store](https://play.google.com/store). You need a new service account created in the Google Play Console so that Bitrise can authenticate with [Google Play Deploy](https://github.com/bitrise-io/steps-google-play-deploy) during your build. The new service account has to be invited to Google Play Console as a user with the appropriate permission. To set up your project for the first time: 1. Register a [Google Play Developer Account](https://developer.android.com/distribute/console/). If you already have a Google Play Developer account, and have already deployed your app to Google Play Store, skip to [Setting up Google Play API access](#setting-up-google-play-api-access). 1. Go through [Setting up Google Play deployment for the first time](#setting-up-google-play-deployment-for-the-first-time). ### Setting up Google Play API access Grant the Google Play API access to your project by creating a service account and granting the necessary user permissions to the service account. 1. Turn on the Google Play Developer API for your project: [Enable the API](https://developers.google.com/android-publisher/getting_started#enable). 1. Create a service account on Google Cloud Platform: [Create service accounts](https://developers.google.com/android-publisher/getting_started#service-account). 1. Create a new JSON key for the service account: [Create and delete service account keys](https://cloud.google.com/iam/docs/keys-create-delete). :::note[Instant download] When you click **Create** at the end of the process, the service account JSON key is automatically downloaded. Make sure to save it as you cannot access or download it again! ::: 1. Invite your service account user on the **Users & Permissions** page in Google Play Console and grant the necessary permissions to be able to access and release apps on Google Play: [Use a service account](https://developers.google.com/android-publisher/getting_started#service-account). Check out the [Google Play Developer API](https://developers.google.com/android-publisher/getting_started) guide if you need more information on the process. You have successfully prepared your Google Play Console project. A services credential account has been created which is authorized to manage your releases. ### Setting up Google Play deployment for the first time Deploying to Google play publishes your app to Google's online store. When you do it for the first time, this requires a bit more work than simply deploying to [bitrise.io](https://www.bitrise.io/). Once the necessary configurations are in place, it becomes very simple. When configuring Google Play deployment for the first time, you need to link your Google Play Developer account to an API project, set up API access, and upload the service account JSON key to Bitrise. 1. Upload the first AAB or APK manually to Google Play [using the Google Play Console](https://support.google.com/googleplay/android-developer/answer/113469?hl=en). 1. [Link](https://developers.google.com/android-publisher/getting_started) your Google Play Developer Console to an API project. 1. [Set up API Access Clients using a service account](https://developers.google.com/android-publisher/getting_started): Please note when you create your service account on the Google Developer Console, you have to choose `json` as **Key Type**. 1. Grant the necessary rights to the service account with your [Google Play Console](https://play.google.com/apps/publish). Go to **Settings**, then **Users & permissions**, then **Invite new user**. Due to the way the Google Play Publisher API works, you have to grant at least the following permissions to the service account: - Access level: View app information. - Release management: Manage production releases, manage testing track releases. - Store presence: Edit store listing, pricing & distribution. 1. As an optional step, you can add translations to your Store Listing: [Translate & localize your app](https://support.google.com/googleplay/android-developer/answer/3125566?hl=en). 1. [Connect your Google service account to Bitrise](/bitrise-platform/integrations/connecting-a-google-service-account-to-bitrise). ### Deploying an Android app to bitrise.io In this section, we'll go through how to deploy your Android project to [bitrise.io](https://www.bitrise.io/). Deploying to [bitrise.io](https://www.bitrise.io) means that the build artifacts generated during the build will be available for download once the build is finished. You can use this to test your Android app on your own test devices, for example. To deploy your app to [bitrise.io](https://www.bitrise.io/): **Workflow Editor** 1. Make sure your Workflow contains the **[Android Build](https://www.bitrise.io/integrations/steps/android-build)** Step to build your app. Optionally, you can build your app with the **[Gradle Runner](https://www.bitrise.io/integrations/steps/gradle-runner)** Step. This requires a bit more configuration from you but allows for more extensive customization. 1. Add the **[Deploy to Bitrise.io](https://www.bitrise.io/integrations/steps/deploy-to-bitrise-io)** Step to your Workflow. :::tip[Notifying other users] You can use the **Notify: User Roles** and the **Notify: Emails** inputs of the Step to set up notifications about your deploy. Click the input names to reveal more information about how to configure them. ::: 1. Optionally, set the **Enable public page for the App?** input of the Step to **true** so the Step [enables the public install page](/bitrise-ci/deploying/bitrise-ota-app-deployment#deploying-with-the-deploy-to-bitriseio-step) for your app. 1. Run a build. **Configuration YAML** 1. Open the `bitrise.yml` file of your app. 1. Make sure your Workflow contains the `android-build` Step to build your app. ```yaml workflows: example-workflow: steps: - android-build@1: ``` Optionally, you can build your app with the `gradle-runner` Step. This requires a bit more configuration from you but allows for more extensive customization. 1. Set the `module` and/or `variant` input to tell the Step what to build. In this example, we're building a debug variant of the Android project. ```yaml workflows: example-workflow: steps: - android-build@1: inputs: - variant: debug - deploy-to-bitrise-io: {} ``` 1. Add the `deploy-to-bitrise-io` Step to your Workflow. ```yaml workflows: example-workflow: steps: - android-build@1: inputs: - variant: debug - deploy-to-bitrise-io: {} ``` :::tip[Notifying other users] You can use the `notify_user_groups` and the `notify_email_list` inputs of the Step to set up notifications about your deploy: - The `notify_user_groups` input allows you to send notifications based on the [access roles](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) granted to users. For example, you can set the input to notify everyone with an **Admin** and a **Developer** role. Set multiple roles separated by a comma: `- notify_user_groups: admins, testers`. - The `notify_email_list` input only accepts Secrets, and the Secret should contain comma-separated lists of email addresses. ::: 1. Optionally, set the **Enable public page for the App?** input of the Step to **true** so the Step [enables the public install page](/bitrise-ci/deploying/bitrise-ota-app-deployment#deploying-with-the-deploy-to-bitriseio-step) for your app. 1. Run a build. The **Deploy to Bitrise.io** Step will deploy the app. You can share the generated binary with your team members using the build’s URL. **A bitrise.yml for deploying an Android app to Bitrise** In this example, we're building the `debug` variant of an Android app, and deploy it to bitrise.io, as. ### Deploying to Google Play Deploying to Google Play requires [a signed APK or AAB file](/bitrise-ci/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step) and the **[Google Play Deploy](https://www.bitrise.io/integrations/steps/google-play-deploy)** Step. **Workflow Editor** 1. [Upload your service account JSON key to the **Files** section](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds). 1. In the **Files** section, copy the **Download URL** of your service account file. For example, `BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL`. 1. Open the Workflow Editor and select **Secrets**. 1. Create a Secret with the copied download URL as the value. If you uploaded the JSON key file to Bitrise, the download URL is an Environment Variable so check the **Replace variables in inputs** checkbox. :::note[Direct link] If you use a direct link to your keystore file without uploading it to Bitrise, you don't need to check the **Replace the variables in inputs** option. ::: 1. Add the **Google Play Deploy** Step to your Workflow. 1. In the **Service Account JSON key file path** input, paste the Secret you created. 1. In the **Package name** input, add the package name of your app. 1. In the **Track** input, add the track where you want to deploy your APK (for example, alpha/beta/rollout/production or any custom track you set). **Configuration YAML** 1. [Upload your service account JSON key to the **Files** section](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds). :::note[Uploading the service account JSON key file] We recommend uploading the service account JSON key to Bitrise but it is not mandatory: you can store it elsewhere and provide a direct link to it. ::: 1. Open your app's Configuration YAML file and add the `google-play-deploy` Step to it. ```yaml deploy-workflow: steps: - google-play-deploy: inputs: ``` 1. In the `service_account_json_key_path` input, you need to provide the path to the service account JSON key file. [Create a Secret](/bitrise-ci/configure-builds/secrets) to the path and reference that here. ```yaml deploy-workflow: steps: - google-play-deploy: inputs: - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL" ``` 1. In the `package` input, add [the package name](https://support.google.com/admob/answer/9972781?hl=en#:~:text=The%20package%20name%20of%20an,supported%20third%2Dparty%20Android%20stores.) of your app. ```yaml deploy-workflow: steps: - google-play-deploy: inputs: - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL" - package_name: myApp ``` 1. In the `track` input, add the track where you want to deploy your app binary (for example, alpha/beta/rollout/production or any custom track you set). ```yaml deploy-workflow: steps: - google-play-deploy: inputs: - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL" - package_name: myApp - track: alpha ``` That’s all! Start or schedule a build and share the URL with external testers or distribute your app on an app store of your choice! --- ## Deploying apps to Huawei AppGallery You can deploy your Android apps to [Huawei AppGallery](https://appgallery.huawei.com/) via a verified Bitrise Step called [**Deploy to Huawei App Gallery**](https://github.com/FutureMind/bitrise-step-huawei-app-gallery-apk-distribution). The Step can be used to deploy any APK file that you build on Bitrise. The Step will need: - The App ID of the app. - The Client ID of the API client. - The Key generated for the API client. To successfully deploy your app to Huawei AppGallery, you need a Workflow that: - Builds and signs an APK or AAB file. - Includes the [**Deploy to Huawei App Gallery**](https://github.com/FutureMind/bitrise-step-huawei-app-gallery-apk-distribution) Step to deploy the app. To configure deploying with the **Deploy to Huawei App Gallery Step**: 1. [Manually upload the first APK of the app to Huawei AppGallery using the website interface on AppGallery Connect.](https://developer.huawei.com/consumer/en/doc/distribution/app/agc-create_app) 1. [Create a team-level API client on AppGallery Connect](https://developer.huawei.com/consumer/en/doc/distribution/app/appgallerykit-createapiclient). ![huawei_api.png](/img/_paligo/uuid-e444bc09-0aed-9c9d-6ebb-8531a391fb75.png) 1. Open the Workflow Editor on Bitrise. 1. Go to the Workflow that you want to use for deploying the app. 1. Add the [**Deploy to Huawei App Gallery**](https://github.com/FutureMind/bitrise-step-huawei-app-gallery-apk-distribution) Step after the Steps that build and sign your APK. ![huawei_step.png](/img/_paligo/uuid-f1bdccd2-c501-e9ae-ace8-61c3c7e82a9b.png) 1. Open the **Config** input group. 1. Fill in the required inputs. - **File path**: If you used a Step that automatically exports the `BITRISE_APK_PATH` Environment Variable after building your APK, leave this unchanged. The [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build) Step is such a Step, for example. - **File name**: The unique name of the APK file. This name will be used when uploading to the AppGallery Connect. - **App ID**: The identified can be found in the **App information** section on AppGallery Connect. - **Client ID**: The API client ID generated on AppGallery Connect. - **Key**: The key generated with the API client on AppGallery connect. Take a look at the following bitrise.yml file to see an example configuration that uses the [**Deploy to Huawei App Gallery**](https://github.com/ferPrieto/steps-app-gallery-deploy) Step to deploy an app. ```yaml workflows: deploy: steps: - activate-ssh-key@4: run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' - git-clone@4: {} - cache-pull@2: {} - install-missing-android-tools@2: inputs: - gradlew_path: "$PROJECT_LOCATION/gradlew" - gradle-runner@1.9: inputs: - gradle_file: "$GRADLE_BUILD_FILE_PATH" - gradle_task: assembleRelease - gradlew_path: "$GRADLEW_PATH" - sign-apk@1.7: {} - deploy-to-bitrise-io@1: {} - cache-push@2: {} - appgallery-deploy@0: inputs: - huawei_client_id: 'XXX' - huawei_client_secret: "$CLIENT_SECRET" - huawei_app_id: 'YYY' ``` Run a build! If all goes well, you should see your app on Huawei AppGallery. --- ## Exporting a universal APK from an AAB You can test an Android app on a test device even if the generated artifact is an App Bundle (`.aab`). With the [**Export Universal APK**](https://github.com/bitrise-steplib/bitrise-step-export-universal-apk) Step you can export a universal APK from the App Bundle, sign it with a keystore (or debug keystore), and deploy the APK to your test device before releasing the app to the Google Play Store. To configure this Step: **Workflow Editor** 1. Insert the [**Export Universal APK**](https://github.com/bitrise-steplib/bitrise-step-export-universal-apk) Step after the [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build) Step in your Workflow. 1. Make sure the **Android App Bundle path** input's value is the output variable (BITRISE_AAB_PATH) of the previous build Step. :::note[Using a different build Step] If you don't use the [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build) Step to build an AAB file, make sure that the input points to the AAB output of the Step you used. You can use an [Environment Variable](/bitrise-ci/configure-builds/environment-variables), or a direct local path or URL. ::: 1. Make sure the **Keystore URL** input points to your Android keystore file. We recommend uploading the file to Bitrise and using the default Env Var: $BITRISEIO_ANDROID_KEYSTORE_URL. You can, however, use a local path or a URL as input value here. 1. Provide your credentials in the **Keystore alias** and the **Keystore password** inputs. If you uploaded a keystore file to Bitrise, the default value of the inputs should not need to be changed. 1. In the **Bundletool version** input, you can override the default Bundletool version if you need a specific one but make sure you use the [correct version](https://github.com/google/bundletool/releases). 1. Run your Workflow. **Configuration YAML** 1. In your app's Configuration YAML file, insert the `bitrise-step-export-universal-apk` Step after the `android-build` Step. ```yaml my-workflow: steps: - android-build: {} - bitrise-step-export-universal-apk: inputs: ``` 1. Make sure the `aab_path` input's value is the output variable ($BITRISE_AAB_PATH) of the previous build Step. :::note[Using a different build Step] If you don't use the `android-build` Step to build an AAB file, make sure that the input points to the AAB output of the Step you used. You can use an Environment Variable, or a direct local path or URL. ::: ```yaml my-workflow: steps: - android-build: {} - bitrise-step-export-universal-apk: inputs: - aab_path: "$BITRISE_AAB_PATH" ``` 1. Make sure the `keystore_url` input points to your Android keystore file. We recommend uploading the file to Bitrise and using the default Env Var: $BITRISEIO_ANDROID_KEYSTORE_URL. You can, however, use a local path or a URL as input value here. ```yaml my-workflow: steps: - android-build: {} - bitrise-step-export-universal-apk: inputs: - aab_path: "$BITRISE_AAB_PATH" - keystore_url: "$BITRISEIO_ANDROID_KEYSTORE_URL" ``` 1. Provide your credentials in the `keystore_alias` and the `keystore_password` inputs. If you uploaded a keystore file to Bitrise, the default value of the inputs should not need to be changed. Otherwise store your credentials in a [Secret](/bitrise-ci/configure-builds/secrets) and use the Secrets as the input values. ```yaml my-workflow: steps: - android-build: {} - bitrise-step-export-universal-apk: inputs: - aab_path: "$BITRISE_AAB_PATH" - keystore_url: "$BITRISEIO_ANDROID_KEYSTORE_URL" - keystore_password: "$BITRISEIO_ANDROID_KEYSTORE_PASSWORD" - keystore_alias: "$BITRISEIO_ANDROID_KEYSTORE_ALIAS" ``` 1. In the `bundletool_version` input, you can override the default Bundletool version if you need a specific one but make sure you use the [correct version](https://github.com/google/bundletool/releases). ```yaml my-workflow: steps: - android-build: {} - bitrise-step-export-universal-apk: inputs: - aab_path: "$BITRISE_AAB_PATH" - keystore_url: "$BITRISEIO_ANDROID_KEYSTORE_URL" - keystore_password: "$BITRISEIO_ANDROID_KEYSTORE_PASSWORD" - keystore_alias: "$BITRISEIO_ANDROID_KEYSTORE_ALIAS" - bundletool_version: 1.8.1 ``` 1. Run your Workflow. The [**Export Universal APK**](https://github.com/bitrise-steplib/bitrise-step-export-universal-apk) Step exports the APK to the `$BITRISE_APK_PATH` Environment Variable which the next Steps can pick up. If the [**Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step is included in your Workflow, [Release Management](/release-management) can deploy the APK for you. --- ## Generate and deploy multiple flavor APKs in a single workflow You can generate, code sign and deploy multiple flavor (multi-flavor) APKs/AABs in one Workflow using our [**Gradle Runner**](https://github.com/bitrise-io/steps-gradle-runner) Step. Flavor means enhancing an app’s core code with features resulting in different versions of the same app (just to mention the most common examples: free/paid, demo/full). Check out the official Android Studio guide on [build types, flavors and build variants](https://developer.android.com/studio/build/build-variants) for more info! In this tutorial, you will need to do some settings to [**Android Sign**](https://github.com/bitrise-steplib/steps-sign-apk) and [**Google Play Deploy**](https://github.com/bitrise-io/steps-google-play-deploy) Steps - so keep your eyes peeled! ### Generating multi-flavor APKs To generate APK files for several different flavors: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Insert **Gradle Runner** Step after the Android testing Steps. The **Android Build** Step also supports multiple variants via its **Variant** input (list them separated by a line break), but this tutorial continues with **Gradle Runner**. 1. Click the **Config** section of the Step. 1. Specify **assemble** Gradle tasks by adding your build variants’ task names in the **Gradle task to run** Step input field - as many task names as many build variants you want to build in one workflow. Each task name must be exactly the same build variant name what you have listed in the **Build Variant** window of Android Studio! Make sure you separate them only with a space, no need for a comma! For example, with two build variants: `assembleDemo` and `assembleFull` (for APKs) or `bundleDemo` and `bundleFull` (for AABs) 1. **Gradle Runner** generates a `$BITRISE_APK_PATH_LIST` / `$BITRISE_AAB_PATH_LIST` Environment Variable output that contains APKs/AABs built for ALL build variants defined above. We will need this output Environment Variable later. ### Signing and deploying multi-flavor APKs 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add one **Android Sign** Step AFTER the **Gradle Runner** Step if it’s missing from your Workflow. 1. Set the **App file path** input to `$BITRISE_APK_PATH_LIST` or `$BITRISE_AAB_PATH_LIST` depending on which app format you built in the previous **Gradle Runner** Step. This will make sure all APKs or AABs get code signed with the keystore file you uploaded to the **Code Signing** tab. The Step will export either the `$BITRISE_SIGNED_APK_PATH_LIST` or the `$BITRISE_SIGNED_AAB_PATH_LIST` Environment Variable output which contains the path of the signed app files for each build variant. 1. Make sure you set the following input fields in the **Android Sign** Step: - **Keystore url** - **Keystore password** - **Key alias** 1. Add the **Google Play Deploy** Step AFTER the **Android Sign** Step. 1. Set the `$BITRISE_SIGNED_APK_PATH` or the `$BITRISE_SIGNED_AAB_PATH` Environment Variable in the **APK or App Bundle file path** Step input field so that the **Google Play Deploy** Step can release all your build variants to the app store. --- ## Generating and deploying Android app bundles Creating an Android App Bundle with Bitrise is almost the same as generating an APK. All you have to do is tweaking a few Step inputs to compile an Android App Bundle (.aab) file from your code, then get the bundle signed and deployed to Google Play Store. :::important[Step versions supporting bundle creation] The following Steps must be of the indicated version or newer - older versions of the Steps do NOT support bundle creation. - [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build) 0.10.0 or newer - [**Gradle Runner**](https://github.com/bitrise-io/steps-gradle-runner) 1.9.0 or newer - [**Android Sign**](https://github.com/bitrise-steplib/steps-sign-apk) 1.3.0 or newer - **Deploy to Google Play** 1.6.0 or newer ::: ### Generating an Android App Bundle file You can create an Android App Bundle with either the **Gradle Runner** Step or with the **Android Build** Step. #### Using the Gradle Runner Step **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Insert the **Gradle Runner** Step after the **Android Unit Test** and **Android Lint** Steps in your Workflow. 1. Click the **Config** section of **Gradle Runner**. 1. In the **Gradle task to run** input field, set, for example, `bundleRelease` or `bundleDebug` to create a bundle of your project. ![Generating_and_deploying_Android_app_bundles.jpg](/img/_paligo/uuid-b0a21607-f817-bdff-5480-e82a6f9a0152.jpg) :::tip[APK and AAB in the same Workflow] If you wish to generate an Android App Bundle and an APK in one Workflow, you can specify an additional task in the **Gradle task to run** input field: set the input value to `bundleRelease assembleRelease` to generate release versions. ::: **Configuration YAML** 1. Open your app's Configuration YAML file. 1. Insert the `gradle-runner` Step after the `android-unit-test` and `android-lint` Steps in your Workflow. ```yaml my-workflow: steps: - activate-ssh-key: run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' - git-clone: {} - install-missing-android-tools: {} - android-lint: {} - android-unit-test: {} - gradle-runner: ``` 1. In the `gradle_task` input of `gradle-runner`, set, for example, `bundleRelease` or `bundleDebug` to create a bundle of your project. ```yaml my-workflow: steps: - activate-ssh-key: run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' - git-clone: {} - install-missing-android-tools: {} - android-lint: {} - android-unit-test: {} - gradle-runner: inputs: - gradle_task: bundleRelease ``` :::tip[APK and AAB in the same Workflow] If you wish to generate an Android App Bundle and an APK in one Workflow, you can specify an additional task in the `gradle_task` input field: set the input value to `bundleRelease assembleRelease` to generate release versions. ::: This way the Step will generate an Android App Bundle instead of an APK. #### Using the Android Build Step You can generate an Android App Bundle for your Android app with our **Android Build** Step as well: **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add the **Android Build** Step after the **Android Unit Test** and **Android Lint** Steps in your Workflow. 1. Provide the root directory of your Android project in the **Project Location** input field. 1. Go to **Build type** and select `aab` as build type. ![Generating_and_deploying_Android_app_bundles.jpg](/img/_paligo/uuid-e786c907-9370-70be-0d2f-7c9c6f028ac7.jpg) :::tip[APK and AAB in the same Workflow] If you wish to generate an APK and an Android App Bundle in one Workflow, add two **Android Build** Steps after each other and configure one to build an Android App Bundle and the other to build an APK. ::: **Configuration YAML** 1. Open your app's Configuration YAML. 1. Add the `android-build` Step after the `android-unit-test` and `android-lint` Steps in your Workflow. ```yaml my-workflow: steps: - activate-ssh-key: run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' - git-clone: {} - install-missing-android-tools: {} - android-lint: {} - android-unit-test: {} - android-build: ``` 1. Provide the root directory of your Android project in the `project_location` input field. 1. Set the value of the `build_type` input to `aab`. ```yaml my-workflow: steps: - activate-ssh-key: run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' - git-clone: {} - install-missing-android-tools: {} - android-lint: {} - android-unit-test: {} - android-build: inputs: - build_type: aab ``` :::tip[APK and AAB in the same Workflow] If you wish to generate an APK and an Android App Bundle in one Workflow, add two `android-build` Steps after each other and configure one to build an Android App Bundle and the other to build an APK. ::: ### Signing an Android App bundle Signing an Android App Bundle file works the same way as signing an APK: the most convenient method is to upload your keystore files to Bitrise and use the **Android Sign** Step: **Workflow Editor** 1. Upload your keystore file to Bitrise. 1. Open your Workflow in the Workflow Editor, and add the **Android Sign** Step AFTER the build Step. 1. Make sure that the **Keystore password**, **Key alias** and the **Key password** input fields are filled out. :::tip[Default input values] If you have uploaded your keystore file and filled out the required credentials, the **Android Sign** Step's **Keystore url**, **Keystore password**, **Keystore alias**, and the **Private key password** inputs will get populated automatically! ::: 1. Make sure the **App file path** input field displays the same output env var as the output of the build Step you've been using. For example, **Android Build** exports either a $BITRISE_APK_PATH or a $BITRISE_AAB_PATH Env Var that points to the APK and/or AAB file the Step generated. By default, this input points at these Env Vars. ![Generating_and_deploying_Android_app_bundles.jpg](/img/_paligo/uuid-8b24a99b-a80b-f23a-7708-af1136ffbedb.jpg) :::tip[Further configuration options] Check out all the available configuration options of the **Android Sign** Step in the Workflow Editor. You can: - Enable or disable memory page alignment with the **Page alignment** input. - Choose which tool signs the app with the **Signer tool** input: `automatic` (default, uses `apksigner` for APKs and `jarsigner` for AABs), `apksigner`, or `jarsigner`. - Enforce a specific [Signature Scheme](https://source.android.com/docs/security/features/apksigning#schemes) with the **APK Signature Scheme** input. ::: **Configuration YAML** 1. Upload your keystore file to Bitrise. 1. In your app's Configuration YAML file, add the `sign-apk` Step AFTER the build Step - for example, `android-build` - in your Workflow. ```yaml sign-android-workflow: steps: - android-build: {} - sign-apk@1: inputs: ``` 1. Make sure that the `keystore_url`, `keystore_password`, and `keystore_alias` inputs point to the correct location. ```yaml sign-android-workflow: steps: - android-build: {} - sign-apk@: inputs: - keystore_url: "$BITRISEIO_ANDROID_KEYSTORE_URL" - keystore_password: "$BITRISEIO_ANDROID_KEYSTORE_PASSWORD" - keystore_alias: "$BITRISEIO_ANDROID_KEYSTORE_ALIAS" ``` :::tip[Default input values] If you have uploaded your keystore file to Bitrise and filled out the required credentials, you do not have to set the inputs at all: the default values, defined in the Step's `step.yml` configuration file, will point to the keystore file and the necessary credentials. ::: 1. Make sure the `android_app` input field displays the same output Env Var as the output of the build Step you've been using. For example, `android-build` exports either a $BITRISE_APK_PATH or a $BITRISE_AAB_PATH Env Var that points to the APK and/or AAB file the Step generated. By default, this input points at these Env Vars. The Step will look for a binary to sign at the locations provided in this input. ```yaml sign-android-workflow: steps: - android-build: {} - sign-apk@1: inputs: - keystore_url: "$BITRISEIO_ANDROID_KEYSTORE_URL" - keystore_password: "$BITRISEIO_ANDROID_KEYSTORE_PASSWORD" - keystore_alias: "$BITRISEIO_ANDROID_KEYSTORE_ALIAS" - android_app: "$BITRISE_APK_PATH\\n$BITRISE_AAB_PATH" ``` :::tip[Further configuration options] Check out all the available configuration options of the `android-sign` Step in [its step.yml file](https://github.com/bitrise-steplib/steps-sign-apk/blob/master/step.yml). You can: - Enable or disable memory page alignment with the `page_align` input. - Choose which tool signs the app with the `signer_tool` input: `automatic` (default, uses `apksigner` for APKs and `jarsigner` for AABs), `apksigner`, or `jarsigner`. - Enforce a specific [Signature Scheme](https://source.android.com/docs/security/features/apksigning#schemes) with the `signer_scheme` input. ::: ### Deploying your Android App Bundle to Google Play Deploying an AAB file isn't significantly different from deploying an APK to Google Play. If you want to check the bundle prior to app store distribution, you can add the **Deploy to Bitrise.io** Step after the **Gradle Runner / Android Build** Steps. It uploads the bundle into the **Artifacts** tab of your Build’s page. #### Setting up Google Play deployment for the first time Deploying to Google play publishes your app to Google's online store. When you do it for the first time, this requires a bit more work than simply deploying to [bitrise.io](https://www.bitrise.io/). Once the necessary configurations are in place, it becomes very simple. When configuring Google Play deployment for the first time, you need to link your Google Play Developer account to an API project, set up API access, and upload the service account JSON key to Bitrise. 1. Upload the first AAB or APK manually to Google Play [using the Google Play Console](https://support.google.com/googleplay/android-developer/answer/113469?hl=en). 1. [Link](https://developers.google.com/android-publisher/getting_started) your Google Play Developer Console to an API project. 1. [Set up API Access Clients using a service account](https://developers.google.com/android-publisher/getting_started): Please note when you create your service account on the Google Developer Console, you have to choose `json` as **Key Type**. 1. Grant the necessary rights to the service account with your [Google Play Console](https://play.google.com/apps/publish). Go to **Settings**, then **Users & permissions**, then **Invite new user**. Due to the way the Google Play Publisher API works, you have to grant at least the following permissions to the service account: - Access level: View app information. - Release management: Manage production releases, manage testing track releases. - Store presence: Edit store listing, pricing & distribution. 1. As an optional step, you can add translations to your Store Listing: [Translate & localize your app](https://support.google.com/googleplay/android-developer/answer/3125566?hl=en). 1. [Connect your Google service account to Bitrise](/bitrise-platform/integrations/connecting-a-google-service-account-to-bitrise). #### Deploying to Google Play Deploying to Google Play requires [a signed APK or AAB file](/bitrise-ci/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step) and the **[Google Play Deploy](https://www.bitrise.io/integrations/steps/google-play-deploy)** Step. **Workflow Editor** 1. [Upload your service account JSON key to the **Files** section](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds). 1. In the **Files** section, copy the **Download URL** of your service account file. For example, `BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL`. 1. Open the Workflow Editor and select **Secrets**. 1. Create a Secret with the copied download URL as the value. If you uploaded the JSON key file to Bitrise, the download URL is an Environment Variable so check the **Replace variables in inputs** checkbox. :::note[Direct link] If you use a direct link to your keystore file without uploading it to Bitrise, you don't need to check the **Replace the variables in inputs** option. ::: 1. Add the **Google Play Deploy** Step to your Workflow. 1. In the **Service Account JSON key file path** input, paste the Secret you created. 1. In the **Package name** input, add the package name of your app. 1. In the **Track** input, add the track where you want to deploy your APK (for example, alpha/beta/rollout/production or any custom track you set). **Configuration YAML** 1. [Upload your service account JSON key to the **Files** section](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds). :::note[Uploading the service account JSON key file] We recommend uploading the service account JSON key to Bitrise but it is not mandatory: you can store it elsewhere and provide a direct link to it. ::: 1. Open your app's Configuration YAML file and add the `google-play-deploy` Step to it. ```yaml deploy-workflow: steps: - google-play-deploy: inputs: ``` 1. In the `service_account_json_key_path` input, you need to provide the path to the service account JSON key file. [Create a Secret](/bitrise-ci/configure-builds/secrets) to the path and reference that here. ```yaml deploy-workflow: steps: - google-play-deploy: inputs: - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL" ``` 1. In the `package` input, add [the package name](https://support.google.com/admob/answer/9972781?hl=en#:~:text=The%20package%20name%20of%20an,supported%20third%2Dparty%20Android%20stores.) of your app. ```yaml deploy-workflow: steps: - google-play-deploy: inputs: - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL" - package_name: myApp ``` 1. In the `track` input, add the track where you want to deploy your app binary (for example, alpha/beta/rollout/production or any custom track you set). ```yaml deploy-workflow: steps: - google-play-deploy: inputs: - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL" - package_name: myApp - track: alpha ``` That’s all! Start or schedule a build and share the URL with external testers or distribute your app on an app store of your choice! --- ## Bitrise OTA app deployment Bitrise has an integrated deployment system you can use to distribute your apps and other build artifacts. You can distribute your apps over the air for your app’s team members or any stakeholder, even if they don't have a Bitrise account. You can also use it to archive your app and other build artifact files which will be available on the Bitrise project’s **Builds** page for viewing and downloading. Here is a short recap on the different build Steps per platform. | Platform | Build Step | Deploy Step to Bitrise | | --- | --- | --- | | iOS | [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive) | **Deploy to Bitrise.io - Apps, Logs, Artifacts** | | Android | [**Gradle Runner**](https://github.com/bitrise-io/steps-gradle-runner) or [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build) | **Deploy to Bitrise.io - Apps, Logs, Artifacts** | | React Native | [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build) and/or [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive) | **Deploy to Bitrise.io - Apps, Logs, Artifacts** | | Ionic | [**Ionic Archive**](https://github.com/bitrise-steplib/steps-ionic-archive) | **Deploy to Bitrise.io - Apps, Logs, Artifacts** | | Cordova | [**Cordova Archive**](https://github.com/bitrise-steplib/steps-cordova-archive) | **Deploy to Bitrise.io - Apps, Logs, Artifacts** | | MacOS | [**Xcode Archive for Mac**](https://github.com/bitrise-steplib/steps-xcode-archive-mac) and/or [**Export macOS Xcode Archive**](https://github.com/bitrise-steplib/steps-export-xcarchive-mac) | **Deploy to Bitrise.io - Apps, Logs, Artifacts** | ### Deploying with the Deploy to Bitrise.io Step The **Deploy to Bitrise.io** Step can perform several different functions: - It allows you to create and distribute a public install page for your app and notify users about new builds of the app. - It uploads app binaries and other build artifacts to the **Artifacts** tab of the build's page. - It can send test results and logs to [test reports](/bitrise-ci/testing/deploying-and-viewing-test-results). In this guide, we'll talk about how to use the Step to deploy app binaries (IPA/APK/AAB files) and distribute the link to the public install page. ![Bitrise_OTA_app_Deployment.png](/img/_paligo/uuid-23eca453-8f3c-1bbf-e189-eae6a638e144.png) #### The deploy directory The **Deploy directory or file path** input defines the path that the Step will check for files to deploy. If the input value is a file path, it will deploy that file. If the input value is a directory, it will deploy all files in the directory. The default value is the BITRISE_DEPLOY_DIR [Environment Variable](/bitrise-ci/configure-builds/environment-variables) (Env Var). In most cases, you don't have to change this or worry about it in any way. If you use the official Bitrise Steps to build your apps, they will export all necessary files into this directory. In certain cases, it's worth checking whether your files end up in the correct location for deployment: - If you use a **Script** Step to build your app, the best practice is to configure the Step to export the files to the BITRISE_DEPLOY_DIR Env Var. - If you use a Step that isn't maintained by Bitrise, check where the Step exports any files it generates. If it isn't the BITRISE_DEPLOY_DIR, set the input to point to that location. :::tip[Compressing all files into a .zip] If you wish to compress all files found in the deploy directory into a single .zip file, set the **Compress artifacts into one file?** input to **true**. ::: #### The public install page The **Enable public page for the App?** input determines whether the app can be installed by accessing a publicly available web page. Anyone who has the link to the page can install the app on their device. :::note[Registering test devices] For Android apps, you don’t have to register your test devices to be able to install the app on them, as Android apps don’t have per-device install restrictions. However, you’ll have to enable the **Unknown Sources** option in Android to be able to install the APK/AAB from outside of the Google Play Store. For iOS apps, [the test devices must be registered and provisioned](/bitrise-ci/deploying/ios-deployment/installing-an-ipa-file-from-the-public-install-page), otherwise, you can't install the app from the public install page on them. ::: The page includes all the important details of the build, such as filename, size, version code, minimum SDK version, and build number. If the public install page is enabled, users defined in the **Notify: Emails** and **Notify: User Roles** inputs rec3eive the link to the page. By default, the input value is set to **true**. If you disable the option, only the members of your app's Bitrise team will be able to install the app on their devices. They can find the installable binary on the **Artifacts** tab on the build page. #### Notifying users The **Deploy to Bitrise.io Step** can send email notifications to specified users. The notification can include the build URL and the public install page link. The Step can notify users in two ways: - The **Notify: User Groups** input allows you to notify the users on the app's Bitrise team. If the **Enable public page for the App?** input is set to **true**, the notification includes the link to the public install page. If it's set to **false**, the specified user groups will receive the build URL instead. The default value is **everyone**: this means everyone on the app's Bitrise team gets a notification. You can choose any other role: in that case, only users with that particular role will get a notification. - The **Notify: Email** input allows you to notify anyone via email. This includes people who don't have a Bitrise account. This way, you can send the public install page to anyone, inviting them to install the app. :::important[Public install page required] If the **Enable public page for the App?** input is set to **false**, the **Notify: Email** input is ignored! ::: :::caution[Use a Secret] The input only takes [Secrets](/bitrise-ci/configure-builds/secrets) as a value: you must create a Secret and specify the email addresses in the Secret's value. ::: --- ## Deploying apps to Applivery [Applivery](https://www.applivery.com) is a mobile app distribution platform for iOS and Android that provides a powerful mobile app management and distribution system to simplify app delivery for both testers and employees, with a focus on an easy-to-use experience. Applivery has many features to better manage your in-development and production-ready apps that will help speed up your development, get better feedback and deliver better applications. Some of the features are: - Single or Multi App customized App Stores with a seamless user experience for non-technical users. - Multi-track and fully customized app distribution with multiple security configurations including SSO, non-registered users, password protected and unlisted apps. - Automatic and forced in-app updates. - Feedback and bug reporting. Combined with Bitrise, you can cover the entire development life cycle, from testing and building to delivery and feedback. ![App_life_cycle_with_Applivery_and_Bitrise.png](/img/_paligo/uuid-841839d9-140d-afa4-254a-5587922a594b.png) ### Deploying your app to Applivery 1. Add the **Applivery iOS Deploy** or the **Applivery Android Deploy** Step to your Workflow. Make sure you add the Step after the Steps that build your app. 1. Get your Applivery App Token to link your Bitrise app with your Applivery app. [Read more about how to get your App Token](https://www.applivery.com/docs/api/app-distribution/apps-api-authentication/). 1. Open your app on Bitrise and click the **Workflows** tab to open the Workflow Editor. 1. Go to the **Secrets** tab. 1. Click **Add New** and type `APPLIVERY_APP_TOKEN` in the key input field. 1. Paste your Applivery App Token in the value input field and click **Save**. ![Configuring_Applivery_App_Token.png](/img/_paligo/uuid-cf02074e-b629-4880-6b9c-92ee73910849.png) ### Configuring the Applivery Step There are many optional parameters that you can customize for a better and deeper integration: | Input Variables | Type | Description | | --- | --- | --- | | File path | File | App’s binary file. By default gets $BITRISE_IPA_PATH or $BITRISE_APK_PATH. | | App Token | String | Applivery App token. By default gets $APPLIVERY_APP_TOKEN Secret var. | | Changelog | String | Additional build/release notes or changelog attached to the deploy. | | Notify Collaborators? | Boolean | Automatically notify your project Collaborators vía emai. | | Notify Employees? | Boolean | Automatically notify your project Employees vía emai. | | Notification message | String | Notification message to be sent along with the email notification. | | Tags | String | Comma-separated list of tags to easily identify the build or multitrack App Distribution | | Version name | String | Human readable version name for a better identification of the build. | | Upload Certificates | Boolean | Download your code signing files from Bitrise **Code Signing & Files** tab and upload them to Applivery. | ### Distribution with Applivery ![Distribution_in_Applivery.png](/img/_paligo/uuid-62976d61-b5fa-6258-5880-7f55090b5881.png) Applivery provides multiple different ways for app distribution from customized App Stores (public or private) to Distribution Pages (public, private, unlisted, or password-protected shareable installation links). It also enables multitrack app delivery based on the information gathered from your Bitrise workflows, such as GitHub Branches, Tags or customized labels. --- ## Deploying apps to DeployGate from Bitrise [**DeployGate**](https://deploygate.com?locale=en) is a mobile app distribution platform for iOS and Android, delivering your in-development iOS/Android apps to your dev team, members, employees, QA testing team in your organization or testers outside of your company. DeployGate has many features to accelerate your app development cycle including QA testing and app improvement with beta tester’s feedbacks. DeployGate offers: - Real-time App distribution with automatic version control, even without requiring accounts for testers - Flexible user account management with granular access control - Git-like multi-track distribution allows individual version/user/device management for the same app With DeployGate and Bitrise, you can quickly build a fully automated in-house dogfooding environment for your team. To see more details, please visit [DeployGate Features](https://deploygate.com/features?locale=en). ![Automated_app_distribution_workflow.png](/img/_paligo/uuid-541a72f2-6396-7422-0446-823ce23549a0.png) To upload your app to DeployGate, add the `DeployGate Upload` Step to your bitrise Workflow. ![new-dg-step.png](/img/_paligo/uuid-b69592cf-9d58-0267-7327-c3265b1e4462.png) This Step should be added after the Step that builds your app's binary that will be uploaded. You need to set several required parameters as below: | Input Variables | Description | | --- | --- | | API Key | Set upload user’s DeployGate API Key from Account Settings. If you want to upload apps as organization account, please use organization’s API Key. Upload account will be shown on the activity timeline. | | Owner Name | App owner’s account name in DeployGate. You can use username or organization name. | | App file path | App’s binary file (IPA/APK) to be uploaded. For default setting, use $BITRISE_APK_PATH for Android or $BITRISE_IPA_PATH for iOS | You can also set optional variables for using advanced features as below: | Input Variables | Description | | --- | --- | | Short Message | Summary of update shown on DeployGate. You can use $BITRISE_GIT_MESSAGE if you want to use the commit message, the pull request title, or the message you specified when you triggered the build manually. | | Distribution Key | You can make multiple public install links (we called it Distribution Page) for a different version of app binary in the same app. By specifying the distribution page’s hash, that distribution page will be updated simultaneously. The “xxxx” portion of the distributed page’s URL like https://deploygate.com/distributions/xxxx | | Distribution Name | Specify the name of the updated distribution page. If nothing exists, a new distribution page will be created. Possible usage includes creating distribution pages for each Git branch name. (for example $BITRISE_GIT_BRANCH) | | Release Note | Message for the new release in distribution page. This message will be notified to your distribution page’s testers | | Disable Notify(iOS Only) | There is no DeployGate client app in iOS platform. By default, we use email notifications for release updates. If you don’t need email notification, please set this option as true | These options are based on [**DeployGate API**](https://docs.deploygate.com/docs/api/). For more details, please read the references at [DeployGate.com](https://deploygate.com?locale=en). You can use DeployGate's **Distribution Page** (Shareable link) feature to generate a landing page for the app installation of your app’s specific version. ![Distribution_Page.png](/img/_paligo/uuid-b1dd1c66-369b-691d-8842-752bd6f33919.png) When you upload an app to DeployGate, the system automatically assigns a sequential number (we are calling it `**Revision Number**`) for each uploaded build. On the Distribution Page, you can choose specific revision of app to distribute for each group of testers. This feature is handy for distributing your app to multiple tester groups for different purposes such as QAs, Dog Fooding, or Test Marketing. You can also generate a distribution page when you upload an app from Bitrise with [DeployGate Upload](https://github.com/DeployGate/upload-app-bitrise-step) Step. Please refer to the optional variables above. --- ## Deploying to TestFairy with Bitrise If you are looking for a deployment service that also gives you lots of insights about your application, then [TestFairy](https://www.testfairy.com/) is a great service to check out. When testing apps in the crowd, you never know what exactly was tested and what exactly went wrong on the client side. TestFairy solves this problem by providing a video of everything that happened on the mobile device, including detailed internal metrics such as CPU, memory, GPS, network, logs, crash reports, and a lot more. To get these insights on iOS you need to [integrate their iOS SDK into your app](http://docs.testfairy.com/iOS_SDK/Integrating_iOS_SDK.html). To deploy your app on the TestFairy platform you just simply need to add the **TestFairy** Step to your app’s Workflow (on [bitrise.io](https://www.bitrise.io)). The only required parameter you have to add is your API Key on TestFairy. To get it you should navigate to your [account preferences](https://app.testfairy.com/settings/) on TestFairy and find the key under your API Key menu. :::note[Email notifications and Auto update] You can also enable or disable the email notifications and set the tester groups you would like to notify. There’s an option to make your users always upgrade to the latest build by enabling Auto update in the Step, and you can also start recording video and set the length of it. ::: There’s nothing else you need to do, simply work on your awesome app and we ensure your app is automatically deployed to TestFairy every time you update your code. --- ## Deploying your app to Appaloosa Would you like to **beta test** and **deploy** your app to 1 or thousands of users? [**Appaloosa**](http://appaloosa.io) helps you distribute your mobile apps privately, collect feedback and analyse your deployment’s efficiency. [Check it out!](http://appaloosa.io) Appaloosa is a simple and secure enterprise App Store. They help mobile & digital teams build, test and deploy their apps privately. You can manage your apps on Android, iOS and Windows Phone, all in the same place. Appaloosa also provides a native app store to increase your users’ engagement. They will receive a push notification on each update of the app and be able to test and use the latest version of your mobile apps. Appaloosa also gives you great insight on the efficiency of your deployment with download and usage stats as well as feedbacks and ratings from the users. They are entreprise ready with LDAP, OAuth, SAML and Active Directory integrations as well as a RESTful API. [Get in touch](mailto:sales@appaloosa-store.com) for more details. Plus your mobile apps can be targeted to groups of users or distributed to all collaborators. To deploy your app on Appaloosa, add the **Appaloosa** Step to your app’s Workflow. You need an Appaloosa account before you can use the Step. - You need your *store id* and *API Key* from your Appaloosa account. - Optionally you can provide a *description*, *screenshot* urls (up to 5), and *group ids*. With Bitrise and Appaloosa, you can focus on your mobile app development and we take care of the rest! --- ## Deploying an iOS app for external testing Before deploying your app to the App Store, you might want to release it to external testers who can test it on their devices outside the development environment. If you do not want to use Testflight, then you can do this by exporting an IPA file with the `ad-hoc` export method. :::important[Using Testflight] If you wish to invite external testers using Testflight, you CANNOT use the `ad-hoc` export method. You need an IPA with the `app-store` export method. ::: 1. Generate an IPA file on your own machine at least once. 1. [Upload all necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) to Bitrise. For the `ad-hoc` export method, you need a Distribution type certificate and an Ad Hoc type provisioning profile. Only upload a provisioning profile if you use manual provisioning: [Managing iOS code signing files - manual provisioning](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---manual-provisioning). 1. Make sure the [**Xcode Archive & Export for iOS**](https://github.com/bitrise-steplib/steps-xcode-archive) Step is in your Workflow. 1. Set the **Distribution method** input of the Step to `ad-hoc`. 1. Set the**Automatic code signing method** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t do automatic code signing. - `api-key` [if you use API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` [if you use Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Make sure you have the [**Deploy to Bitrise.io**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step in your Workflow. 1. Start a build. 1. When the build is finished, go to the app’s **Builds** page and click the latest build. 1. Click the **Artifacts** tab to find your IPA file that you can distribute. --- ## Deploying an iOS app for simulators You can build and deploy your iOS application to a simulator, to show it off in a browser, for example. On Bitrise, we have [a dedicated Step](https://www.bitrise.io/integrations/steps/xcode-build-for-simulator) to build for a simulator: the [**Xcode build for simulator**](https://github.com/bitrise-steplib/steps-xcode-build-for-simulator) Step runs the `xcodebuild` command with an iOS simulator destination and generates an .app file. The .app file can be run on any simulator. On Bitrise, we have a Step to upload your app to Appetize.io: the [**Appetize.io deploy**](https://github.com/bitrise-steplib/steps-appetize-io-deploy) Step. With this Step, you can deploy your app so you can run it in a browser. To build the app for a simulator, you do not need code signing files! ### Building an iOS app for a simulator You can build an iOS app for an iOS or tvOS simulator platform. To do this, you'll need the **Xcode Build for Simulator** Step. The Step creates an `.app` file which you can install on any macOS device or send to, for example, testers. This requires no code signing at all, so it is an easy way to create a distributable version of your iOS app. The Step also creates an `.xctestrun` file which you can use to run tests. Both the `.app` file and the `.xctestrun` file can be accessed by subsequent Steps referring to their output variable, and they can be [downloaded as a build artifact](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online). To build the app for a simulator: **Workflow Editor** 1. Make sure you install all necessary dependencies in your Workflow. We have dedicated Steps for many different dependency managers, including: - [Carthage](https://bitrise.io/integrations/steps/carthage) - [CocoaPods](https://bitrise.io/integrations/steps/cocoapods-install) - [Homebrew](https://bitrise.io/integrations/steps/brew-install) 1. Add the **Xcode Build for Simulator** Step to your Workflow after the Step(s) installing dependencies. 1. Make sure the **Project path** input points to either your `.xcodeproj` or `.xcworkspace` file. The input sets the `-project` or `-workspace` option of the `xcodebuild` command. In most cases, if your app has been automatically configured by the project scanner during the [process of adding the app](/bitrise-ci/getting-started/adding-a-new-project), the default value does not need to be changed. 1. In the **Scheme** input, set the name of the [Xcode scheme](https://developer.apple.com/documentation/xcode/customizing-the-build-schemes-for-a-project/) you want to use to build the app. ![scheme-input.png](/img/_paligo/uuid-2700f022-4822-82fe-77e4-1a0995b41ab6.png) The input sets the `-scheme` option of the `xcodebuild` command. The default value is an Environment Variable created when adding the app and performing the first-time configuration. If you need to use a different scheme, you can type its name here. :::tip[Build configuration] By default, the Step will use the build configuration specified in the scheme. However, you can override it and use a different build configuration: add the name of the desired build configuration to the **Configuration name** input. This input is optional and you only need it if you don't want to use the build configuration specified in the selected scheme. You can create new build configurations in your Xcode project at any time: [Adding a build configuration file to your project](https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project). ::: 1. In the **Device destination specifier** input, select **generic/platform=iOS Simulator** ![ios-simulator-destination.png](/img/_paligo/uuid-7235d345-4190-c1be-6ee3-fc25e1eb183e.png) 1. Optionally, set the **Build settings (xcconfig), allow code signing** input to **CODE_SIGNING_ALLOWED=YES**. This allows code signing files to be installed during the build. In most cases, you don't need code signing for an app built for a simulator. It might be required for certain test cases or third-party dependencies. To set up code signing, see [iOS code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). 1. To access your app as a build artifact, add the **Deploy to Bitrise.io** Step to the end of your Workflow. By default, you don't have to modify anything in the Step's configuration. **Configuration YAML** 1. Make sure you install all necessary dependencies in your Workflow. We have dedicated Steps for many different dependency managers, including: - [Carthage](https://bitrise.io/integrations/steps/carthage) - [CocoaPods](https://bitrise.io/integrations/steps/cocoapods-install) - [Homebrew](https://bitrise.io/integrations/steps/brew-install) 1. Add the `[xcode-build-for-simulator](https://github.com/bitrise-steplib/steps-xcode-build-for-simulator)` Step to your Workflow after the Step(s) installing dependencies. ```yaml workflows: primary: steps: - cocoapods-install - xcode-build-for-simulator: inputs: ``` 1. Make sure the `project_path` input points to either your `.xcodeproj` or `.xcworkspace` file. The input sets the `-project` or `-workspace` option of the `xcodebuild` command. In most cases, if your app has been automatically configured by the project scanner during the [process of adding the app](/bitrise-ci/getting-started/adding-a-new-project), the default value does not need to be changed. ```yaml - xcode-build-for-simulator: inputs: - project_path: $BITRISE_PROJECT_PATH ``` 1. In the `scheme` input, set the name of the [Xcode scheme](https://developer.apple.com/documentation/xcode/customizing-the-build-schemes-for-a-project/) you want to use to build the app. The input sets the `-scheme` option of the `xcodebuild` command. The default value is an Environment Variable created when adding the app and performing the first-time configuration. If you need to use a different scheme, make sure to type the name of the scheme correctly. ```yaml - xcode-build-for-simulator: inputs: - scheme: $BITRISE_SCHEME - project_path: $BITRISE_PROJECT_PATH ``` :::tip[Build configuration] By default, the Step will use the build configuration specified in the scheme. However, you can override it and use a different build configuration: add the name of the desired build configuration to the `configuration` input. This input is optional and you only need it if you don't want to use the build configuration specified in the selected scheme. You can create new build configurations in your Xcode project at any time: [Adding a build configuration file to your project](https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project). ::: 1. Set the `destination` input to `generic/platform=iOS Simulator`. ```yaml - xcode-build-for-simulator: inputs: - scheme: $BITRISE_SCHEME - destination: generic/platform=iOS Simulator - project_path: $BITRISE_PROJECT_PATH ``` 1. Optionally, set the `xcconfig_content` input with the value `CODE_SIGNING_ALLOWED=YES`. This allows code signing files to be installed during the build. In most cases, you don't need code signing for an app built for a simulator. It might be required for certain test cases or third-party dependencies. To set up code signing, see [iOS code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). ```yaml - xcode-build-for-simulator: inputs: - scheme: $BITRISE_SCHEME - destination: generic/platform=iOS Simulator - xcconfig_content: |- CODE_SIGNING_ALLOWED=YES COMPILER_INDEX_STORE_ENABLE = NO - project_path: $BITRISE_PROJECT_PATH ``` 1. To access your app as a build artifact, add the `deploy-to-bitrise-io` Step to the end of your Workflow. By default, you don't have to modify anything in the Step's configuration. ```yaml primary: steps: - generate-cordova-build-configuration@0: {} - xcode-build-for-test@2: {} - xcode-test@4: {} - xcode-build-for-simulator@0.12: inputs: - scheme: $BITRISE_SCHEME - destination: generic/platform=iOS Simulator - configuration: debug - xcconfig_content: |- CODE_SIGNING_ALLOWED=YES COMPILER_INDEX_STORE_ENABLE = NO - project_path: $BITRISE_PROJECT_PATH - deploy-to-bitrise-io ``` ### Deploying the app to Appetize.io An .app file built with our **Xcode build for simulator** Step works with just about any simulator. But if you want to easily and quickly integrate it to a simulator that allows you to run your app in a browser, we recommend using the **Appetize.io deploy** Step. It uploads your app to Appetize.io and provides a public URL to use the app in a browser. 1. Request an Appetize.io API token. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add and configure the **Xcode build for simulator** Step to your Workflow. 1. Add the **Appetize.io deploy** Step to your Workflow. ![Deploying_an_iOS_app_for_simulators.png](/img/_paligo/uuid-d24fc560-4da7-49d1-f0b4-e14e365fba68.png) 1. Add the Appetize.io API token to the **Appetize.io token** input. 1. Enter the path to the .app file to the **Application path** input. The easiest solution is to use the `BITRISE_APP_DIR_PATH_LIST` Environment Variable that is an output of the **Xcode build for simulator** Step. Optionally, you can also enable verbose logging for more efficient debugging. The `Appetize.io deploy` Step will produce one output: the `APPETIZE_APP_URL` Environment Variable. it is a public URL where you can access your app. Enjoy showing it off! --- ## Deploying an iOS app to App Store Connect You can deploy an app to App Store Connect to: - Invite testers on Testflight. - Release your app on the App Store. On Bitrise, you can either simply just upload your binary to App Store Connect or you can also submit it for review. ### Deploy to App Store Connect Steps To deploy the app to App Store Connect, we have two Steps: - **Deploy to App Store Connect** - **Deploy to App Store Connect - Application Loader** **Deploy to App Store Connect - Application Loader** is simple: it simply pushes an .ipa or .pkg binary file to App Store Connect. With this Step, you cannot submit the app for review on the App Store, for example. With the **Deploy to App Store Connect** Step, you can: - Submit your app to the App Store for review. - You can upload apps of three different platforms (iOS, OS X, AppleTVOS). - Tell Bitrise whether you want to upload your screenshots and the app’s metadata along with the binary. ### Deploying the app to App Store Connect Keep in mind that every time you want to push an app to App Store Connect, it must have a unique build and version number: [increment either or both](/bitrise-ci/run-and-analyze-builds/build-numbering-and-app-versioning) before deploying. 1. Make sure you have a working [connection to your Apple Developer account](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Generate an IPA file on your own machine at least once. 1. [Upload all necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) to Bitrise. To deploy an app to App Store Connect, you need a Distribution type certificate and an App Store type provisioning profile. 1. Make sure the **Xcode Archive & Export for iOS** Step is in your Workflow. 1. Set the **Automatic code signing** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t use automatic code signing, or if you exclusively use Step inputs for Apple service authentication. - `api-key` if you use [API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` if you use [Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Set the **Distribution method** input of the Step to `app-store`. The Step will store the path of the exported .ipa file in the $BITRISE_IPA_PATH Environment Variable. 1. Add the **Deploy to App Store Connect** Step to your Workflow. 1. Fill the required inputs. - Either the app’s Apple ID or its Bundle ID is a required input. One of the two must be provided. - If you set the **Submit for Review** to `yes`, the Step will wait for your submission to be processed on App Store Connect and then submit the given version of the app for review. - The default value of the **Skip App Version Update** input is `No`. Change it only if you incremented the app version number in another way. - If you use an App Store Connect account that is linked to multiple teams, provide either a Team ID or a Team name! 1. Start a build. If all goes well, your app will be submitted to App Store and you can distribute it via Testflight or via the App Store! --- ## Deploying an iOS app to Bitrise.io Deploy an app to Bitrise to be able to download the IPA file and install it on devices specified in the app’s Development type provisioning profile. This way, your internal testers can easily test the app. :::note[Clear the cache] When trying to install an app from the public install page, you should clear the cache: click the link appearing in the **If you synced your settings from your old device, you need to clear the cache and register your new device** line. The link redirects to the **Profile settings** page where you can follow the procedure described in our guide. ::: :::important[Developer certificate and Development profile] To deploy an iOS app to [bitrise.io](https://www.bitrise.io/), you will always need a Developer type certificate and a Development type provisioning profile. Even if you want to deploy to the App Store, these are still required: they are used to create the .xcodearchive file from the provided code in the process of exporting the IPA file. ::: 1. Generate an IPA file on your own machine at least once. 1. [Upload all necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) to Bitrise. 1. If you want your internal testers to test the app, [register test devices](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device). 1. Make sure the **Xcode Archive & Export for iOS** Step is in your Workflow. 1. Set the **Automatic code signing** input to the Apple service connection you want to use for code signing. The available options are: - `off`if you don’t do automatic code signing. - `api-key`if you use [API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id`if you use [Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Set the **Distribution method** input of the Step to `development`. You can use other export methods, too, but if you only deploy to Bitrise and want to install your app on the specified devices of internal testers, `development` is sufficient. 1. Make sure the [**Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step is in your Workflow. By default, the value of the **Enable public page for the App?** input is set to `true`. This way, once the build runs, a public install page will be available with a long and random URL which can be shared with others who are not registered on Bitrise. This URL is sent to the users in an email. The **Notify: User Roles** and the **Notify: Emails** inputs determine which users get the email. 1. Start a build. 1. When the build is finished, go to the app’s **Builds** page and click the latest build. 1. Click the **Artifacts** tab to find your IPA file. You can also find the public install URL here. Click **View artifact** next to the IPA file to open its details page, then click **Manage access** and make sure the public install link is set to **Enabled** so you’re able to send the link to non-Bitrise users. To install an app from the public install page, you must use a native Safari browser of the iOS device. You cannot click the installation link if you’re browsing from a third-party app. For more information, check out [Installing an .ipa file on test devices from the Artifacts tab](/bitrise-ci/deploying/ios-deployment/installing-an-ipa-file-from-the-public-install-page#installing-an-ipa-file-on-test-devices-from-the-artifacts-tab) ![Deploying_Android_apps_to_Bitrise_and_Google_Play.png](/img/_paligo/uuid-43ba1d01-1168-f540-9414-ace775c44ac5.png) And that’s it! The file can now be installed on all the devices included in the app’s provisioning profile. Remember: the installation link must be accessed from an iOS device’s Safari browser! --- ## Installing an ipa file from the public install page You can install .ipa files generated during a Bitrise build on test devices in two ways: - [Using the public install page](#installing-an-ipa-file-on-test-devices-from-the-public-install-page). The public install page is a generated URL that can be distributed to users who have access to provisioned and registered test devices. - [Downloading the file from the **Artifacts** tab](#installing-an-ipa-file-on-test-devices-from-the-artifacts-tab) on the build's page on Bitrise. Installing an .ipa file on a test device consist of three phases: initiating the device compatibility check, installing a configuration profile on the test device, then finishing up with installing the app on the device. In this tutorial we’re describing: - How to install an app on a registered test device without a Bitrise account (for anyone who has not subscribed to Bitrise but wishes to check out the current version of the app). - How to install an app on a test device which is yet to be registered on Bitrise (for Bitrise users). :::note[Installing an .ipa file from the Artifacts tab] Installing an .ipa file from the **Artifacts** tab is only possible for Bitrise users. ::: ### Prepping for installation Before installing the app on any test device, the app’s developer has to complete a couple of steps to build the app and share it with anyone: - The device, on which the app will be installed, is registered as a test device at the developer’s Apple account. - The device has to be included in the provisioning profile of the app. - The device meets the minimum OS requirements of the app. Please note that if the test device is not registered on the Apple Developer portal, the developer has to manually add it to the device list, and re-build the app so that the .ipa file contains the test device/s the app can be installed on. We also recommend you [register the test device on Bitrise](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device) as well. :::tip[Which browser should I use with the public install page?] Anyone who wishes to install the app on a test device has to make sure that the public install page of the app is opened in a native Safari session with non-incognito mode. ::: #### Installing an .ipa file from Bitrise's public install page to an iPad with iPadOS If you are using an iPad running iPadOS, make sure that you open the Bitrise public install page in mobile mode. When you open the public install page of an .ipa file, Bitrise checks if the device is stored in the embedded provisioning profile or not. This check can only complete if you visit the public install page in mobile mode instead of the desktop version. We suggest that you switch to mobile mode temporarily. You can easily switch to mobile mode temporarily if you tap the ᴀA icon on the left corner of the Safari address bar and then tap the **Show Mobile Website**option. ### Installing an .ipa file on test devices from the public install page The public install page is a convenient way of sharing the latest version of your app with team members and any other stakeholders who wish to check the app out. The page includes all the important details of the build such as filename, size, version code, minimum SDK version, and build number. You can configure the **Deploy to Bitrise.io** Step to send an email to users with a link to the public install page. This link can be shared with anyone. During this whole flow, use a native, non-incognito Safari session instead of any other in-app browser type. If you follow the link in the notification email you got from Bitrise, the public install page will automatically open in a native Safari session. :::tip[Would you rather download the app?] If you only wish to download the app and manually upload it somewhere else, you can find the download button on the **Artifacts** page of the build. Please note that downloading an app does not mean you can install it on the test device. ::: #### Installing an app on a test device without a Bitrise account 1. Long tap on the link you received from Bitrise. To open the link in native Safari, tap **Open Link**. It brings up the public install page in a native Safari session. If you copy the link from the email, make sure you paste it in a native Safari session. 1. Tap the link in the **Click here to check device compatibility of this device with this app** yellow message box. If you cannot see this message, you are most likely using another browser so switch to Safari. ![Installing_an_ipa_file_from_the_public_install_page.png](/img/_paligo/uuid-a747ddb7-7aea-2ad2-8934-7540228c4ad8.png) 1. Tap **Allow** on the pop-up to install the configuration profile on your device. This configuration profile makes the device’s UDID available to Bitrise for the compatibility check. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-29d5ecf3-28a9-e914-1ffa-e8f8ffa9c744.jpg) 1. A pop-up confirms the configuration profile has been downloaded, and it can be installed in the **Settings** app. Tap **Close**. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-d443aa9e-a514-c8ab-eb2c-3ffb05847a9d.jpg) 1. Tap the **Home** button to go the the home screen. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-a660119f-d305-200d-a30b-8dbf66e6a054.jpg) 1. Open **Settings**. You can find the downloaded profile at the top of the **Settings**. Tap **Profile Downloaded** menu item on the left to install the profile. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-0f079f8c-ae86-fcff-2b7b-978d7545e551.jpg) 1. Tap **Install**. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-de20be05-7f66-9b1d-fb5d-042d92b0af3c.jpg) 1. Type your device’s passcode in the **Enter passcode** pop-up. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-324132c7-6f52-185f-1d59-917938fd4174.jpg) 1. Tap **Install** again. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-dd095ae4-b0b8-5e20-70db-91b30bf9b6eb.jpg) 1. Wait until the profile is installed. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-f13c2746-f8bf-10d2-0284-1090f23c47e0.jpg) 1. Once the profile is installed, you’re directed to the public install page. As you can see, the **Install** button is now available. Tap it! ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-bb823f44-e4f5-b338-c82f-e2175f034f30.jpg) 1. Tap **OK** on the next pop-up. ![Installing_an_ipa_file_from_the_public_install_page.png](/img/_paligo/uuid-480a1aea-dba2-c5e7-ad91-f05c9d144541.png) 1. As a final confirmation, tap on **Install** and press the **Home** button. Now you’re installing the app to your test device. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-6556fa37-6a3c-7358-f031-137d1ca1d26c.jpg) 1. Wait till the app installs on your test device’s home screen. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-b7e8b6d7-ad45-1950-e950-e6c37907d0d0.jpg) Check out the app you’ve successfully installed on your test device. ##### Installing an app on a test device not registered to Bitrise If you’re accessing the public install page from a test device which displays the below message, you’ll have to register the device on Bitrise which is only a few steps different from the above flow. Please note that you can only add a test device to Bitrise if you already have a Bitrise account. ![Installing_an_ipa_file_from_the_public_install_page.png](/img/_paligo/uuid-a747ddb7-7aea-2ad2-8934-7540228c4ad8.png) 1. Tap **Click here** to start the device registration process. 1. Tap **Allow** to download the configuration profile. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-29d5ecf3-28a9-e914-1ffa-e8f8ffa9c744.jpg) 1. When the configuration profile is downloaded, tap **Close**. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-d443aa9e-a514-c8ab-eb2c-3ffb05847a9d.jpg) 1. Tap the **Home** button to go to your **Settings** app on your test device’s home screen. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-a660119f-d305-200d-a30b-8dbf66e6a054.jpg) 1. Open **Settings**. You can find the downloaded profile at the top of the **Settings**. Tap **Profile Downloaded** menu item on the left to install the profile. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-0f079f8c-ae86-fcff-2b7b-978d7545e551.jpg) 1. Tap **Install**. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-de20be05-7f66-9b1d-fb5d-042d92b0af3c.jpg) 1. Type your device’s passcode in the **Enter Passcode** pop-up. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-324132c7-6f52-185f-1d59-917938fd4174.jpg) 1. Tap **Install** again in the **Install Profile** pop-up. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-dd095ae4-b0b8-5e20-70db-91b30bf9b6eb.jpg) 1. Wait until the profile installation is complete. You automatically get redirected to the **Register your test device** page. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-f13c2746-f8bf-10d2-0284-1090f23c47e0.jpg) 1. Your device’s name and UDID gets populated automatically. You can only change the device name here. Tap **Register Device**. 1. You land on the public install page where the **Install** button is now available. Tap it! ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-bb823f44-e4f5-b338-c82f-e2175f034f30.jpg) 1. Tap **OK** on the prompt. ![Installing_an_ipa_file_from_the_public_install_page.png](/img/_paligo/uuid-480a1aea-dba2-c5e7-ad91-f05c9d144541.png) 1. To install the app on your test device, tap on **Install**. Then press the **Home** button to follow the installment of your app. If all went well, you can find the installed app on your test device’s Home page. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-b7e8b6d7-ad45-1950-e950-e6c37907d0d0.jpg) #### Installing an app on a test device not registered to Bitrise If you’re accessing the public install page from a test device which displays the below message, you’ll have to register the device on Bitrise which is only a few steps different from the above flow. Please note that you can only add a test device to Bitrise if you already have a Bitrise account. ![Installing_an_ipa_file_from_the_public_install_page.png](/img/_paligo/uuid-a747ddb7-7aea-2ad2-8934-7540228c4ad8.png) 1. Tap **Click here** to start the device registration process. 1. Tap **Allow** to download the configuration profile. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-29d5ecf3-28a9-e914-1ffa-e8f8ffa9c744.jpg) 1. When the configuration profile is downloaded, tap **Close**. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-d443aa9e-a514-c8ab-eb2c-3ffb05847a9d.jpg) 1. Tap the **Home** button to go to your **Settings** app on your test device’s home screen. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-a660119f-d305-200d-a30b-8dbf66e6a054.jpg) 1. Open **Settings**. You can find the downloaded profile at the top of the **Settings**. Tap **Profile Downloaded** menu item on the left to install the profile. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-0f079f8c-ae86-fcff-2b7b-978d7545e551.jpg) 1. Tap **Install**. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-de20be05-7f66-9b1d-fb5d-042d92b0af3c.jpg) 1. Type your device’s passcode in the **Enter Passcode** pop-up. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-324132c7-6f52-185f-1d59-917938fd4174.jpg) 1. Tap **Install** again in the **Install Profile** pop-up. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-dd095ae4-b0b8-5e20-70db-91b30bf9b6eb.jpg) 1. Wait until the profile installation is complete. You automatically get redirected to the **Register your test device** page. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-f13c2746-f8bf-10d2-0284-1090f23c47e0.jpg) 1. Your device’s name and UDID gets populated automatically. You can only change the device name here. Tap **Register Device**. 1. You land on the public install page where the **Install** button is now available. Tap it! ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-bb823f44-e4f5-b338-c82f-e2175f034f30.jpg) 1. Tap **OK** on the prompt. ![Installing_an_ipa_file_from_the_public_install_page.png](/img/_paligo/uuid-480a1aea-dba2-c5e7-ad91-f05c9d144541.png) 1. To install the app on your test device, tap on **Install**. Then press the **Home** button to follow the installment of your app. If all went well, you can find the installed app on your test device’s Home page. ![Installing_an_ipa_file_from_the_public_install_page.jpg](/img/_paligo/uuid-b7e8b6d7-ad45-1950-e950-e6c37907d0d0.jpg) ### Installing an .ipa file on test devices from the Artifacts tab You can install an .ipa file from the **Artifacts** tab of your app's build. This provides a more secure way compared to the public install page but requires you to log in to your Bitrise account, making it less viable for external testers. To install an .ipa file from the **Artifacts** tab: 1. Open your app on Bitrise. 1. Select the build with the .ipa file you would like to install. 1. Go to the **Artifacts** tab. 1. Click on **Download** next to the .ipa file. ![ipafile.png](/img/_paligo/uuid-caac5c40-bb61-c1fd-af8b-5e454a9680da.png) 1. Click **Install**, under the **Install the app on your iOS device** section. --- ## Adding a new project Adding a project to Bitrise means one of two things: - Adding a new project with a CI configuration, connecting a Git repository to the project. During the process, we also run our [project scanner](https://github.com/bitrise-steplib/steps-project-scanner) that detects the platform type of the project — for example, iOS — and generate default Workflows with all the necessary Steps to build and deploy an app. - Adding a new project with a new Release Management app: [Adding a new app to Release Management](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management). Each Bitrise project is owned by a [workspace](/bitrise-platform/workspaces/workspaces-overview). :::note[The project scanner] Supporting a platform/framework means that our project scanner can detect the type of the project and set up a basic Bitrise configuration based on the type. You can add any other project, too, regardless of how it's built, but you'll have to configure it manually. ::: In this guide, we'll go through how to add a new CI project to Bitrise. 1. On the **Dashboard**, click **New project**. 1. Select **Configure Bitrise CI**. ![Add CI config entry point — choose how you want to get started modal](/img/getting-started/2026-06-27-add-ci-config-dashboard-modal.png) :::tip[Release Management] Select **Add your app** to add a new app to Release Management instead. See [Adding a new app to Release Management](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management). ::: The **Add CI config** wizard has three stages: **Repository**, **CI configuration**, and **Build settings**. ### Repository Complete each of the following sub-steps in order. #### Connecting to your Git provider Under **Connect to your Git provider**, select a connection method from the **Connection method** dropdown: - **GitHub App (recommended)**: connect via the GitHub App integration. Requires your Workspace admin to configure credentials in **Workspace settings > Integrations** first. See [GitHub App integration](/bitrise-platform/repository-access/github-app-integration). - **GitHub OAuth**, **GitLab**, **Bitbucket**: connect via OAuth to your account on the respective provider. See [Repository access with OAuth](/bitrise-platform/repository-access/repository-access-with-oauth). - **[GitHub Enterprise Server](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise)**, **Bitbucket Server**, **[Self-hosted GitLab](/bitrise-platform/repository-access/connecting-self-hosted-gitlab-instances)**: for self-hosted Git providers. - **Other**: connect any other Git repository by entering its URL manually. Once you select a provider, click **Connect provider** to set up the connection, or **Select repository** if the provider is already connected. ![Connect to your Git provider — connection method dropdown with GitHub OAuth selected](/img/getting-started/2026-06-27-add-ci-config-connect-git-provider.png) #### Selecting a repository Select the repository you want to connect: - **Select from list**: use the account dropdown to filter by organization or user, then select a repository from the list. Use the search field to find a specific one. - **Add URL manually**: enter the repository URL directly. Click **Confirm selection**. ![Select repository — browsing repositories by account](/img/getting-started/2026-06-27-add-ci-config-select-repository.png) :::note If you can't find a repository, you may need to request org approval for the Bitrise OAuth app. The link appears below the repository list. ::: #### Authorizing Bitrise :::note This step is only required if you are not using the GitHub App and your repository is connected via an SSH URL. Repositories connected via HTTPS URLs do not require SSH key configuration. The wizard skips this step automatically if it is not needed. ::: Choose how Bitrise accesses your repository: - **Auto-add a generated SSH key to your repository**: Bitrise adds the key automatically. Requires admin rights on your Git provider. - **Copy a generated SSH key to your Git provider manually**: use this if your build needs to access additional private repositories beyond the one you're connecting (for example, a private CocoaPods spec repository, Fastlane match storage, or Git submodules). Copy the generated key and add it to each repository manually. - **Add your own SSH key to Bitrise**: use an existing SSH key pair. For more information, see [Configuring SSH keys](/bitrise-platform/repository-access/configuring-ssh-keys). ![Authorize Bitrise — SSH key options](/img/getting-started/2026-06-27-add-ci-config-authorize-bitrise.png) #### Selecting the default branch Select the branch Bitrise will use for builds when no other configuration specifies a different one: - If your repository is connected, select a branch from the dropdown. - If you added a URL manually, type the branch name directly. You can [change the default branch](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch) later. Click **Next** to proceed to the next stage. ![Select default branch — branch dropdown with main selected](/img/getting-started/2026-06-27-add-ci-config-select-default-branch.png) ### CI configuration Bitrise scans your repository and generates a starter CI configuration automatically. ![CI configuration — scanning repository](/img/getting-started/2026-06-27-add-ci-config-ci-configuration-scanning.png) Once scanning completes: - If a project type is detected, it appears under the **Detected options** tab. - If no project type is detected, switch to the **Manual setup** tab and select your project type from the **Project type** dropdown. ![CI configuration — manual project type selection](/img/getting-started/2026-06-27-add-ci-config-project-type-picker.png) Click **Skip** if you want to skip automatic configuration and set it up manually later. ### Build settings Review and adjust the build settings for your project: - **Build machine** and **Stack**: Bitrise pre-selects optimal settings based on your project type. You can change these later in the Workflow Editor. See [Build machine types](/bitrise-build-hub/infrastructure/build-machine-types) and [Build stacks](/bitrise-build-hub/infrastructure/build-stacks/about-build-stacks). - **Access to builds**: choose **Private** (only Workspace members can access build logs and the CI configuration file) or **Public** (anyone with the link can view them). See [Public projects](/bitrise-platform/projects/public-projects). - **Register webhooks**: enable this toggle to let Bitrise automatically register a webhook in your repository so builds trigger on code changes. Not needed if you use the GitHub App. See [Adding incoming webhooks](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks). ![Build settings — machine, stack, access, and webhooks](/img/getting-started/2026-06-27-add-ci-config-build-settings.png) Click **Finish**. Bitrise kicks off your first build and takes you to the build page where you can watch it run in real time. From there, you can start [editing your Workflows](/bitrise-ci/workflows-and-pipelines/workflows/workflows-overview) and [run builds](/bitrise-ci/run-and-analyze-builds/starting-builds/approving-pull-request-builds). --- ## Getting started Bitrise is the CI/CD Platform built for Mobile DevOps. With scalable infrastructure, robust collaboration features, and a wide range of integrations, our platform offers the tools to fit all your Mobile DevOps needs. Sign up via email or via a Git hosting provider: [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise). After signing up, you can explore Bitrise but you can't start CI builds. You can add new projects and CI configurations but you won’t be able to start more builds without either our 30-day trial or a Pro subscription. To start the 30-day trial, you need to provide credit card details: - Your card will be charged $0.01 during the verification process and the transaction will be voided immediately after the process completes, meaning the 30 day Pro trial is completely free to you. - We’re NOT going to automatically sign you up to a paid plan when your trial expires. - Your billing data is retained so you can use the same credit card info & billing address to subscribe to a paid plan if you choose to do so. For more information about the trial and the paid subscription plans, check out our [Pricing page](https://bitrise.io/pricing). ### Adding your first CI project :::note[First workspace] Bitrise automatically creates your first [workspace](/bitrise-platform/workspaces/workspaces-overview). You need at least one workspace to be able to add projects and run builds. Your subscriptions are also tied to your workspaces. ::: On the **Dashboard**, click **New project** and select **Configure Bitrise CI**. The **Add CI config** wizard walks you through three stages: :::note[Release Management] If you want to add an app to [Release Management](/release-management) instead, select **Add your app** in the same dialog. ::: 1. **Repository**: connect to your Git provider, select a repository, authorize Bitrise to access it, and select a default branch. 1. **CI configuration**: Bitrise scans your repository and generates a starter configuration. If it can’t detect your project type automatically, select it manually from the **Project type** dropdown. 1. **Build settings**: review the pre-selected build machine and stack, choose whether builds are private or public, and optionally register a webhook so builds trigger on code changes automatically. Click **Finish**. Bitrise kicks off your first build and takes you to the build page where you can watch it run in real time. For the full step-by-step guide, see [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project). ### Changing your project settings You can change your project settings at any time. To do so, open your project on the [Bitrise CI page](https://app.bitrise.io/ci) and click **Project settings**. ![project-settings-button.png](/img/_paligo/uuid-56c193b1-5aaf-9bc1-63f3-61739dfcd68d.png) Clicking the button takes you to the **Project settings** page. ![project-settings-main-page.png](/img/_paligo/uuid-b76a80c6-dd43-0542-65aa-98a4f8e44407.png) The settings you can change include: - Name and project type. - [Repository URL and default branch](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch). - [Team members of the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). - [Git connection](/bitrise-platform/repository-access/repository-access-with-oauth) and [access to online services](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) such as the Apple Store or Google Play. - [Build notification settings](/bitrise-ci/configure-builds/configuring-build-settings/configuring-email-notifications). You can also set up [rolling builds](/bitrise-ci/configure-builds/configuring-build-settings/rolling-builds) and [selective builds](/bitrise-ci/configure-builds/configuring-build-settings/selective-builds), upload [code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects), upload [generic files to Bitrise](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy), [register test devices](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device), and check your [caching](/bitrise-ci/dependencies-and-caching/dependencies-and-caching-overview) data. ### Editing your build configuration Your CI build configuration is defined in YAML format. The root configuration file is called `bitrise.yml`: it contains a project's entire build configuration. To edit the configuration on Bitrise: 1. Open the [Bitrise CI page](https://app.bitrise.io/ci). 1. Select your project from the list of projects on the right. You can use the Search field to search for a specific one. ![project-list.png](/img/_paligo/uuid-624fc88e-8389-faf0-8638-465d3a7978ee.png) 1. Click **Workflows**. This takes you to the Workflow Editor where you can configure: - [Steps, Workflows, and Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/about-pipelines). - [Build stacks](/bitrise-build-hub/infrastructure/build-stacks/about-build-stacks) and [machine types](/bitrise-build-hub/infrastructure/build-machine-types). - [Environment Variables](/bitrise-ci/configure-builds/environment-variables) on the project level. - [Build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) that allow you to automatically trigger builds when a code event happens. :::note[Editing the YAML file directly] Select **Configuration YAML** to edit the configuration file directly. For detailed YAML syntax, see [Configuration YAML reference](/bitrise-ci/references/configuration-yaml-reference). ::: ### Running a build After successfully adding a project, your first build starts automatically. You are automatically taken to the **Builds** page of your project where you can see the build in progress. Click on the build to see its [details](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/checking-build-details) and current progress. To start a CI build manually, click **Start build**. ![start-build.png](/img/_paligo/uuid-111feaf8-6180-9531-fae4-51424aeb75dc.png) This opens up the dialog for [manually starting a build](/bitrise-ci/run-and-analyze-builds/starting-builds/starting-builds-manually). ![start-build-basic.png](/img/_paligo/uuid-2fe105a3-6faa-4394-35fd-41fd3ed5cc42.png) A build is a series of jobs, defined in the project's [Workflows](/bitrise-ci/workflows-and-pipelines/workflows/workflows-overview) and [Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/about-pipelines). The jobs are called [Steps](/bitrise-ci/workflows-and-pipelines/steps/steps-overview) which represent blocks of script executions. You only need to specify a branch and a Workflow or Pipeline to run a build with the **Basic** options. When adding a new project, Bitrise automatically generates at least one [default Workflow](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) for you so you can immediately run your first build. When ready, click **Start build**. It takes you to the build page where you can track the progress of the build, view the [build logs](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/build-logs), and check the [generated build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online). :::note[Triggering builds] You can also trigger builds automatically. Whenever a specified code event happens, Bitrise automatically starts a build: [Configuring build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers). ::: ### Managing your Workspaces Workspaces are fundamental to all aspects of Bitrise: only Workspaces can own projects and all subscriptions belong to Workspaces. When signing up for a personal account, we automatically create a new Workspace for you. A Bitrise personal account can own multiple Workspaces and can be invited to Workspaces owned by other accounts. To manage your Workspace, you have to get to the **Workspace settings** page: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. On the **Workspace settings** page, you can: - Edit the basic information of the Workspace. - Manage your subscription. - [Invite members to your Workspace](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration) and create [Workspace groups](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups). - Set up [SAML SSO](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise). - Check your projects, [transfer project ownership](/bitrise-platform/projects/changing-the-owner-of-a-project), and add new projects. - Configure [Git integration for repository access](/bitrise-platform/repository-access/github-app-integration) and access to online stores. ### Testing, installing, deploying Testing your app and deploying your app are both done with the help of our Steps: we have Steps dedicated to both these functions, based on the platform type. Unit testing, UI testing, and real device testing are all possible on Bitrise: - [Device testing for Android](/bitrise-ci/testing/device-testing-with-firebase/device-testing-for-android) - [Device testing for iOS](/bitrise-ci/testing/device-testing-with-firebase/device-testing-for-ios) - [Android unit tests](/bitrise-ci/testing/testing-android-apps/android-unit-tests) - [Running unit and UI tests for iOS apps](/bitrise-ci/testing/testing-ios-apps/running-unit-and-ui-tests-for-ios-apps) You can find all your generated installable binaries in one place on Bitrise: [The Installable artifacts page](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online#the-installable-artifacts-page). From this page, you can easily install your apps on test devices, using either a private install page or by distributing a link to [a public install page](/bitrise-ci/deploying/ios-deployment/installing-an-ipa-file-from-the-public-install-page). Once your app is tested, built and ready to go, you can quickly deploy it to the store of your choice, for example, Google Play or the App Store. We also recommend trying out Release Management, our one-stop solution for all release-specific tasks. Once you have an installable binary, you can use Release Management to automatically take care of everything else related to releases: [Release Management](/release-management). --- ## Key Bitrise concepts Bitrise manages your builds with Steps, Workflows, and Pipelines. - Steps are individual build tasks: for example, cloning your repository, running unit tests, or creating an installable binary are all individual build tasks. - Workflows are sequences of Steps: when running a Bitrise build, each Step is executed in the order that is defined in a Workflow. - Pipelines represent the top level of a Bitrise CI/CD configuration. Pipelines can be used to organize the entire CI/CD process and to set up advanced configurations with multiple different tasks running parallel and/or sequentially. The configuration is defined entirely in a `bitrise.yml` file that you can store on Bitrise or in your own repository. It also defines the infrastructure used for the build: Bitrise builds run in a clean virtual machine, with preinstalled tools and services for most mobile development use cases. These are defined by our stacks which are updated regularly. ### Steps and Workflows [Workflows](/bitrise-ci/workflows-and-pipelines/workflows/workflows-overview) are a collection of [Steps](/bitrise-ci/workflows-and-pipelines/steps/steps-overview) which are executed in order. This order can be configured in the Workflow Editor, or by editing the `bitrise.yml` file directly. Each Bitrise build runs at least one Workflow. You can start builds by triggering a specific Workflow: in such a build, Workflows can be chained together but they run sequentially. In a Pipeline, Workflows are organized in stages, and in each stage, Workflows run in parallel. When you add a new app on Bitrise, we automatically create default Workflows for you. They contain the most frequently used Step for the app's platform. You can add or remove Steps any time from a Workflow. Steps can be configured via Step inputs and they can generate data that can be used by subsequent Steps in the same Workflow. Bitrise Steps are open source: you can suggest improvements to existing Steps or develop, share, and use your own. ### Pipelines [Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/pipelines-with-stages/configuring-a-pipeline-with-stages) enable a complex CI/CD configuration for advanced use cases. Pipelines can be used to organize the entire CI/CD process and to set up advanced configurations with multiple different tasks running parallel and/or sequentially. A Pipeline allows you to configure dependencies between Workflows. Each Workflow starts executing when its parent Workflows are done. Workflows on the same level are executed in parallel. You can configure build triggers to trigger a Pipeline directly. When a Pipeline is triggered, the build machine starts executing all the Workflows of the first stage. ### Environment Variables and Secrets You can store and use configuration data, or any other data in key-value pairs called [Environment Variables](/bitrise-ci/configure-builds/environment-variables). This enables, among other things, the reuse of build configurations across multiple different apps: in each app, Env Vars with the same key can store different values. Env Vars have different scopes: You can configure app-level and Workflow-level Env Vars, as well as create new variables during the build, and pass these on to subsequent Steps and Workflows in the build. Any Bitrise Step that generates some sort of output makes that output available to subsequent Steps in the form of Env Vars. Secrets are specific types of Env Vars: they are stored in encrypted format and their values are never exposed in build logs or in the `bitrise.yml` file. ### Build machines and stacks Bitrise builds run in clean virtual machines that are destroyed once the build is finished, ensuring the security of your code. You can select the type of the build machine: the operating system (macOS or Linux) and the amount of computing resources the machine offers. A build stack defines what tools and services are installed on the VM that runs your build. For example, our Xcode stacks each come with a different version of Xcode. --- ## About migrating to Bitrise If you have been looking to switch to Bitrise to speed up your mobile CI/CD flow and ease dedicated manpower, look no further. These guides introduce the most important Bitrise features and how you can quickly settle into Bitrise. We have dedicated migration guides for Jenkins and the former Visual Studio App Center: - [Migrating from Jenkins to Bitrise](/bitrise-ci/getting-started/migrating-to-bitrise/migrating-from-jenkins-to-bitrise). - [Migrating from App Center to Bitrise](/bitrise-ci/getting-started/migrating-to-bitrise/migrating-from-app-center-to-bitrise). These guides are meant to help the migration process by comparing the features of the other CI/CD services to Bitrise and introduce you to the most important concepts of how Bitrise works. If you want to migrate to Bitrise from some other CI/CD or DevOps platform, we recommend familiarizing yourself with our key concepts: - [Key concepts of the Bitrise platform](/bitrise-platform/getting-started/key-concepts-of-the-bitrise-platform). - [Key Bitrise concepts](/bitrise-ci/getting-started/key-bitrise-concepts). - [Release Management concepts](/release-management/getting-started-with-release-management/release-management-concepts). Once you're familiar with these concepts, we offer quick start guides to get you through the first steps: - [Getting started with the Bitrise platform](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache). - [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started). - [Getting started with the Build Cache](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache). - [Getting started with Release Management](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management). --- ## Migrating from App Center to Bitrise Visual Studio App Center has been taken offline on March 31, 2025. This guide is meant to help you migrating your projects from App Center to Bitrise. We strongly recommend going through our [Getting started](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache) guide. The [Key Bitrise concepts](/bitrise-ci/getting-started/key-bitrise-concepts) document can also help understanding how Bitrise works. In this guide, we'll be going through the similarities and differences between Bitrise and App Center. ### App Center orgs and Bitrise Workspaces On App Center, your user account can own apps. Organizations are optional: App Center recommends creating an organization for any apps with multiple collaborators. A [Bitrise Workspace](/bitrise-platform/workspaces/workspaces-overview) is a little different: when you sign up for the first time, we automatically create your first Workspace, too. This is because only Workspaces can own Bitrise projects. Projects are not tied to your account but to Workspaces. A Workspace can own several projects but a project cannot be linked to multiple Workspaces. A Bitrise Workspace has four main roles: - **Owner**: The owner of the Workspace. Full administrative control over the Workspace without restrictions. A Workspace can have multiple Owners. The default Owner is the account that created the Workspace. - **Manager**: The user can access and modify Workspace settings such as connected service accounts, can manage members but can't access billing details and can't delete the Workspace. - **Contributor**: Can create new CI projects and add Release Management apps. - **Viewer**: Can only view selected Workspace settings (Projects and Integrations). On App Center, you can create teams within organizations. On Bitrise, Workspace members can be added to Workspace groups: this makes it easier to assign multiple people to projects at the same time. ### User roles and collaboration App Center offers three different roles to manage access to your apps. On Bitrise, control is a little more granular: on each project's team, you can set five different roles to make sure that your team members have the exact right access to the project. For more information, check out [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ### App Center Build service and Bitrise builds The App Center Build service helps you build your apps using a secure cloud infrastructure. A Bitrise build works the same way: you can [connect a repository](/bitrise-platform/repository-access/repository-access-with-oauth) to our service and build your project every time a code event happens in the repository. Bitrise supports multiple mobile frameworks, including iOS, Android, React Native, Flutter, Ionic, and Cordova. When [adding a new project](/bitrise-ci/getting-started/adding-a-new-project), we automatically detect your framework and set up a configuration best suited for that particular framework. #### Repository connections Bitrise supports connections to multiple code repository services: - GitHub (including the GitHub app and GitHub Enterprise Server) - GitLab (including self-hosted GitLab) - Bitbucket (including Bitbucket Server) - Any other Git repository via a generic Git connection For most cases, you can use OAuth connections and [SSH keys](/bitrise-platform/repository-access/configuring-ssh-keys) to set up repository access. [HTTPS authorization](/bitrise-platform/repository-access/configuring-https-authorization-credentials) is also supported. #### GitHub App Just like App Center, Bitrise offers a [GitHub App](/bitrise-platform/repository-access/github-app-integration) to integrate your Bitrise Workspace to a GitHub account or organization. With the GitHub App, you can: - Connect Bitrise to GitHub without using an SSH key. - Improve code security: the app relies on short-lived one-time tokens for access. - [Link multiple repositories](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app) to the same project. - Report your build status to GitHub. #### Configuring your build On App Center, your build configuration is tied to the branches of your repository. On Bitrise, these are separate: the build configuration is independent of the branches of the repository. The process generally works like this: 1. You set up a build configuration: create [Workflows and Pipelines](/bitrise-ci/workflows-and-pipelines/workflows/workflows-overview) and configure the Steps inside them. Your configuration is stored in YAML format but you can create and modify it using the graphical Workflow Editor. You can also set up [Environment Variables](/bitrise-ci/configure-builds/environment-variables) on the project level or on Workflow level. 1. You create [automatic build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers): define the code events that should automatically start Bitrise builds. In addition to simple code push, you can create triggers for pull requests and Git tags. And you have further, more granular control: for example, you can configure a trigger that only starts a build if a certain file has changed in a pull request. You can also specify a branch or branches for a trigger so that only code events on the specified branch trigger a build. 1. You select the [stack](/bitrise-build-hub/infrastructure/build-stacks/about-build-stacks) and the [machine type](/bitrise-build-hub/infrastructure/build-machine-types) of your build. 1. On the **Project settings** page, you can configure additional options for your builds: - Set up [build notifications](/bitrise-ci/configure-builds/configuring-build-settings/configuring-email-notifications). - Set up [rolling builds](/bitrise-ci/configure-builds/configuring-build-settings/rolling-builds). - Configure [connection to services](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) such as App Store Connect or Google Play to ensure your builds can can always access them. - Upload [code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) files or any other files that your builds need. - Configure or download your [build cache](/bitrise-ci/dependencies-and-caching/key-based-caching/accessing-key-based-cache-archives). #### Running a build Just like on App Center, every Bitrise build runs in a clean virtual machine that is discarded once the build is finished while generated artifacts are stored on our servers. On Bitrise, you can also select your build stack: for example, you can always choose between several different versions of Xcode. And we're always aiming to make new Xcode versions available as soon as possible. You can [start builds manually](/bitrise-ci/run-and-analyze-builds/starting-builds/starting-builds-manually), trigger them automatically, or [schedule them](/bitrise-ci/run-and-analyze-builds/starting-builds/scheduling-builds). Once a build has run, you can check out detailed, structured [build logs](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/build-logs). ### Testing on App Center and on Bitrise App Center Test is a test automation service for mobile apps: you can upload your app binary and test files to execute tests. Bitrise offers everything App Center Test does in our CI/CD service: we have multiple, platform-specific dedicated testing Steps that can find and run tests within your code. You can run your tests in simulators and on real devices. In addition to the dedicated testing Steps, you can run any script you want, so you can fully customize your tests. Just like building and deploying, testing is also automatic: set up build triggers so that code events trigger builds with tests. Everything can be integrated: you can build, test, and deploy your app within the very same Workflow, if you choose to. You can view all your test results and generated test artifacts in one place: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). :::note[Test distribution solution] An enhanced Release Management solution with test distribution features is coming soon. You will be able to: - Easily access and distribute different versions of your app for testing from a directory-like page for IPA, APK, and AAB files. - Share your app via either a public or a private install page, or distribute builds to your testers early, in the pre-production phase. ::: ### App Center Distribute and Bitrise Release Management The App Center Distribute service allows you to manage app distribution across multiple platforms in one place. Bitrise [Release Management](/release-management) offers exactly that: a one-stop shop for your release requirements. You can: - Automate all your releases. - Release your apps across multiple platforms at the same time. - Have full granular control over the entire release process without leaving Release Management. To get started, you just need to [connect an app](/release-management/getting-started-with-release-management/connecting-an-app). Once you successfully connected an app, you don't have to go through any of the online stores to manage your releases. We also offer [a fully featured REST API](/release-management/release-management-api) to make the most of Release Management. --- ## Migrating from Jenkins to Bitrise If you have been looking to switch from [Jenkins](https://www.jenkins.io/) to Bitrise to speed up your mobile CI/CD flow and ease dedicated manpower, look no further. This guide introduces the most important Bitrise features and how you can quickly settle into Bitrise from your Jenkins world. ### Why bother migrating? Jenkins is a self-hosted CI server where you have to manually install and maintain most of the functionalities before you could run any build. It also requires dedicated engineering resources for regular maintenance. When you switch to Bitrise, you get to experience the comfort of using a cloud-based, mobile first CI/CD platform which offers out-of-the box functionalities for all your mobile development needs on one platform. This means there is: - No need to download anything. - No need for any on-premise servers or plugins. - No need to worry about infrastructure, tools and virtualization. Bitrise takes care of all of the above. We have a vast array of automatized Steps, [API](/bitrise-ci/api/api-overview), [CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli), and [up-to-date Stacks](https://stacks.bitrise.io) with a highly intuitive GUI, called Workflow Editor, all available at your fingertips. Learn more about our security measures on our [Security page](https://bitrise.io/platform/devops/security) which includes details on product, data, application, network, physical and business security. Check out the world of automated mobile development with Bitrise! :::note[How Bitrise helped top companies migrate] - Discover how payments giant PagSeguro optimized mobile CI by moving from Jenkins to Bitrise: [Read the case study](https://bitrise.io/blog/post/smart-ways-to-optimize-your-ci). - Looking for a feature-by-feature breakdown of Bitrise vs Jenkins? [Check out our comparison page](https://bitrise.io/resources/compare/jenkins). ::: ### Quick start guide This Quick Start Guide helps you start your first build on Bitrise with minimum config. 1. [Sign up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) if you don’t have an account yet. 1. [Connect a repo](/bitrise-platform/getting-started/getting-started-with-the-bitrise-platform) and run an automatically configured standard Workflow on any project. 1. Once you’ve looked through the generated YML, make the changes you need: if you’re opting for a custom code, pop it into our [Script Step](https://www.bitrise.io/integrations/steps/script), and run your first build. Or find the Steps in our [Step Library](https://www.github.com/bitrise-io/bitrise-steplib) to replicate your Jenkinsfile’s behaviors. You can also run builds locally on your computer by installing our [Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli), Bitrise's open source runner. 1. After getting to your new Workflow’s first green build, set up other jobs by configuring [automatic triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) or [scheduled builds](/bitrise-ci/run-and-analyze-builds/starting-builds/scheduling-builds). 1. Optimize your Workflows with [key-based caching](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching) for faster, safer, and more reproducible builds. 1. Need help? [Contact us](https://support.bitrise.io/hc/en-us). If you are interested in the main Jenkins-Bitrise differences and how Bitrise enhance your mobile development process, then continue with the guide below. ### Managing builds on Jenkins and on Bitrise A build on Bitrise is the process specified by the app’s [Workflow](/bitrise-ci/workflows-and-pipelines/workflows/workflows-overview). It is a series of [Steps](/bitrise-ci/workflows-and-pipelines/steps/steps-overview), defined in a Workflow, executed by the [Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli) on a clean virtual machine or locally on your machine. You can check your app’s builds on the Bitrise **Dashboard** or you can analyze your [build logs](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/build-logs) on your app’s own **Builds** page. #### Triggering builds on Jenkins and Bitrise In this section we describe how you can trigger builds on Bitrise: - The **Build Now** function on Jenkins corresponds with [starting a build manually](/bitrise-ci/run-and-analyze-builds/starting-builds/starting-builds-manually): click the button on your builds page and either simply start a new build or tinker away with the [Advanced configuration options](/bitrise-ci/run-and-analyze-builds/starting-builds/scheduling-builds#advanced-configuration-options-for-startingscheduling-builds). - The **Build periodically** function of Jenkins is the [Scheduling builds](/bitrise-ci/run-and-analyze-builds/starting-builds/scheduling-builds) function on Bitrise. A big advantage of Bitrise is that you don’t have to set up a `cron` job, like you would on Jenkins, to schedule a specific time. Instead, you can use a visual scheduler to pick the days and time, or enter a `cron` expression directly if you prefer. - For any Git related events, such as code push, pull requests, and Git tags, you can [configure triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) that automatically start a build on Bitrise. - The **Build after other projects** function of Jenkins is equivalent to the [chaining Workflows together](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows) on Bitrise where the Workflows run in succession. It’s surprisingly easy to chain Workflows together on Bitrise. - You can trigger builds by any other remote system: use [Webhooks overview](/bitrise-platform/integrations/webhooks/webhooks-overview). We’re integrated with GitHub, Gitlab, Bitbucket, Gogs, Slack, Visual Studio, Assembla, and Deveo. - You can also [push back build status reports](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider) to your Git provider (GitHub/GitLab/Bitbucket). #### Environment Variables and Secrets on Bitrise [Environment Variables](/bitrise-ci/configure-builds/environment-variables) (a key and value pair) can be defined on app, Workflow and Steps level. You can do lots of interesting things with Env Vars: - [Expose them and reuse them in another Step.](/bitrise-ci/configure-builds/environment-variables#setting-and-managing-env-vars-during-a-build) - Copy an Env Var to another key. - Overwrite an Env Var. - Parameterize a build by adding custom Env Vars to a build. - Set up Workflow-specific Env Vars on the **Env Vars** tab to run Workflows with Env Vars that are only available for that particular Workflow. Secrets are a type of Environment Variables but special ones. They hide sensitive information in an encrypted format so that your private input is not exposed in the build logs or in the `bitrise.yml`. Secret Environment Variables, or Secrets in short, can be set by adding a key and the variable in the **Secrets** tab of the Workflow Editor. This is again a built-in feature of Bitrise which ensures the following: - Your secrets are not shown in the `bitrise.yml`. - Your secrets are stored encrypted. - You can prevent exposing secrets on the UI by making them protected. - Note that anyone might be able to do a workaround and log the value of secrets with a pull request, thus we advise NOT to expose secrets in PRs. #### Build caching Every build on Bitrise runs on a clean virtual machine but it does not mean you have to do everything from scratch - [you can cache contents of important files and preserve them between builds.](/bitrise-ci/dependencies-and-caching/dependencies-and-caching-overview) ### Jenkins plugins and Bitrise Steps A [Step](/bitrise-ci/workflows-and-pipelines/steps/steps-overview) is a pre-defined task in Bitrise just like the Jenkins Steps, however, a Bitrise Step can be easily configured on our intuitive UI or you can even pull in your own Step from your repository. You can configure the inputs and parameters that define a Step task, and view/reuse the outputs a Step generates. Reusing the output means that another Step in the same Workflow can use it as the value of one of its inputs. As being a continuous integration tool itself, Jenkins integrates with other services with the help of plugins. Jenkins users have to manage plugins in a centralized place, called **Manage plugins**, install them globally (on their Jenkins server), then use them in their specific projects. If Jenkins notifies of a newer plugin version, Jenkins admins have to doublecheck with their teams if they’re running any builds since updating a plugin requires the server to restart. With Jenkins plugins, reverting to an older version is not possible, since only the latest version is available. In Bitrise, however, you do not have to install any Steps first, because you can add or remove any Step in your Bitrise Workflow at any time as you wish and it won’t block any running builds of the project. You can always revert back to a previous Step version too if that’s what you need. What’s more: When editing your Workflow in the **Workflow Editor**, you can easily search for a Step based on functionality or platform you are looking for in the **Step Library** and add it to your Workflow straightaway - there is no need to install them prior to setting up your Workflow. You can [create your own custom Step](/bitrise-ci/workflows-and-pipelines/developing-your-own-bitrise-step/developing-a-new-step) too and store in a repository, then you can reference it by a URL in your Workflow. :::tip[A Step jolly joker: our Script Step] Do you have a [custom script](https://bitrise.io/integrations/steps/script) you’d like to run in your Workflow? Select the **Script** Step from the Step Library and add your custom code to the **Script content** input. ::: Discover our Steps on our [Integrations](https://www.bitrise.io/integrations/steps) page or right when editing your Workflow. Learn what else you can do with Steps: - [Adding Steps to a Workflow](/bitrise-ci/workflows-and-pipelines/steps/adding-steps-to-a-workflow). - [Step versions](/bitrise-ci/workflows-and-pipelines/steps/step-versions). - [Enabling or disabling a Step conditionally](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally). - [Developing your own Bitrise Step](/bitrise-ci/workflows-and-pipelines/developing-your-own-bitrise-step/creating-your-own-bitrise-project-scanner). :::note[Using fastlane in Jenkins?] You can easily put your fastlane lanes to work on Bitrise too. All you have to do is add a Bitrise’s [**Fastlane**](https://www.bitrise.io/integrations/steps/fastlane) Step to your Workflow and add your lane name into the Step. Start a build and your lane will run on Bitrise. ::: ### Jenkins Pipeline - Bitrise Workflow A Jenkins Pipeline is equivalent to a [Bitrise Workflow](/bitrise-ci/workflows-and-pipelines/workflows/workflows-overview), but the Bitrise Workflows are much easier to manage: you can quickly create new Workflows based on existing ones, chain multiple Workflows together in a single build, or delete Workflows that you no longer need. A Bitrise **Workflow** is a series of Steps, such as test, code sign, build APK/ ipa and deploy. When you add an project to Bitrise, a primary Workflow, created based on the project scanner’s findings, gets kicked off/triggered automatically. You can have several Workflows for a certain project. For example: - For any PR events, create a Workflow that, once triggered, runs quickly and only executes basic tests such as smoke tests. - For a meatier Workflow, that runs all your test, we recommend creating another Workflow and run it overnight or schedule it on 6/12/24 hour interval. The **Workflow Editor** is the main place for configuring your Workflow. Jenkins **Stages** are equal to multiple Bitrise Workflows chained together inside a main Workflow. On Bitrise the Workflow Editor helps you to chain Workflows like one would chain toy trains after each other. The Workflow Editor has other powerful features built in to assist you with mobile development: - [Code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects): Upload certificates, provisioning profiles, and keystores into Bitrise and and use our [iOS](/bitrise-ci/code-signing/ios-code-signing/ios-code-signing) and [Android](/bitrise-ci/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step) signing Steps to do all the code signing automatically for you before releasing an app to an app store. - [Secrets](/bitrise-ci/configure-builds/secrets): check out your project's secret Environment Variables or add new ones. - [Environment Variables](/bitrise-ci/configure-builds/environment-variables): there is no confusion of secrets and Env Vars in Bitrise. They are neatly organized into separate tabs so that you know where’s what. Add project Env Vars or Workflow specific Env Vars here. You can also reference Secrets as Env Vars with $. - [Triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers): You can configure triggers: code push events, pull requests, or tags can all be set up to automatically start builds on Bitrise. - [Stack](/bitrise-build-hub/infrastructure/build-stacks/about-build-stacks): Check out the default stack of your project, select a new one from a dropdown menu or select a specific stack for one of your Workflows. ### Dashboards in Jenkins and Bitrise This is the main landing page where you find yourself when logging into Bitrise. From here you can navigate to your [projects](/bitrise-ci/getting-started/the-bitrise-dashboard#checking-project-details), [your CI builds](/bitrise-ci/getting-started/getting-started), [Bitrise Build Cache](/bitrise-ci/dependencies-and-caching/dependencies-and-caching-overview) and [Release Management](/release-management/getting-started-with-release-management/getting-started-with-release-management). ![bitrisedashboard.png](/img/_paligo/uuid-59d1dcd7-7e29-7221-cbfb-b648ab73102b.png) On Jenkins, build statuses are listed in the **Build Executor Status** or on the Blue Ocean **Dashboard**. When using Bitrise you get a user-friendly graphical interface right from the start, whereas, with Jenkins, you have to install the plugin first. Bitrise build statuses are shown on both the **Dashboard**, and on the **Builds** page of your app. #### Adding a new app to Bitrise What **New item** means in Jenkins is the **adding a new project flow** on Bitrise, either [on the web UI](/bitrise-ci/getting-started/adding-a-new-project) or [from the CLI](/bitrise-ci/bitrise-cli/adding-a-new-project-from-a-cli). This is a highly automated flow where minimal configuration is needed from you and literally within a minute your new build starts. Our flow takes you through all the important phases: setting privacy, connecting your repository, setting up repository access, choosing a branch, configuring your project, setting up your build configuration and [configuring webhooks](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks). #### Webhooks on Bitrise Bitrise makes extensive use of webhooks, which you can enable with a simple click when connecting a project to Bitrise. It all makes sense to add the webhook during the initial setup and not having to search for this functionality when you try to quickly get your project to speed. In short, there are two types of [Webhooks](/bitrise-ci/api/incoming-and-outgoing-webhooks): - Incoming webhooks, registered with your Git service provider, are used to automatically trigger builds on Bitrise. - Outgoing webhooks are used to send reports of build events to other services, such as Slack. They can be added either on the website or via the [API overview](/bitrise-ci/api/api-overview). ### Jenkinsfile - Bitrise YAML A Jenkins Pipeline uses groovy code, while Bitrise uses the more highly structured YAML format. All Workflows are defined in the `bitrise.yml` file in YAML format, which you can edit by clicking the **bitrise.yml** tab of the Workflow Editor. You can store the `bitrise.yml` file of your app either on [bitrise.io](http://bitrise.io/) or [in your repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository). Don’t worry, your secrets (for example, credentials and IDs) are safe with us. You can also download the current `bitrise.yml` configuration of your app and run it locally with the [Installing and updating the Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli). #### Jenkinsfile - Bitrise yml file comparison If you have been using a Jenkinsfile (Pipeline project) in Jenkins and and considering to switch to Bitrise, you can easily match Jenkinsfile stages with Bitrise Steps. If you have been using the old-school Freestyle project, then you have to map your configuration’s settings with a matching Bitrise Step or a Bitrise function. For example, match the **Build** section of your Freestyle project with a Bitrise build Step, such as the [Android Build](https://app.bitrise.io/integrations/steps/android-build) Step, or map the **Build Trigger** section of Jenkins with the [Triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) function of Bitrise. Make sure you check out our [Step Library](https://www.bitrise.io/integrations/steps) for more inspiration. :::tip[Migrating your Android app from Jenkins to Bitrise: a step-by-step guide] Check out our [blogpost](https://blog.bitrise.io/post/migrate-your-android-app-from-jenkins) on how to migrate your Android project from Jenkins to Bitrise. ::: ### Master and agent on Jenkins - Bitrise stack A stack is the type of virtual machine we use to run your build. For example, for a native iOS app, the best stack is one of our Xcode stacks. Stacks come with all of the necessary tools pre-installed, and are regularly updated to make sure they will serve all of your needs. This way you don’t have to bother with maintaining master and agent instances or adding a node machine to your groovy code to run a build on a certain platform. When you add your app to Bitrise, our project selector automatically detects the type of your project and based on its platform type, adds a default stack to it. Your first build will run on this stack, which is a virtual machine with all the required tools pre-installed on it. Should you wish to use another stack, you can simply select it from the **Default Stack** dropdown menu on the **Stacks & Machines** tab. If you click the **More information** link, you can see the preinstalled tools with their versions. We support the latest Xcode version shortly after its official release. In our [system reports](https://bitrise.io/stacks) you can check the installed tools and their versions on each stack. Learn more about our [macOS stack update policy](/bitrise-build-hub/infrastructure/build-stacks/macos-stack-update-policy). If you are interested in how to have a Bitrise-managed infrastructure on your AWS environment, check out our [guides](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/bitrise-on-aws-overview). You can also run Bitrise on your self-hosted infrastructure if you follow [this guide](/bitrise-platform/infrastructure/running-bitrise-builds-on-premise). ### Managing teams and roles in Jenkins and Bitrise A Bitrise user is an individual with a Bitrise account and belongs to one or more workspace/s. A workspace is a group of users who collaborate on projects. You can create multiple workspaces and a contributor can be invited to multiple workspaces by other Bitrise contributors. A contributor must be assigned to a project to be able to work on it. Learn how you can [add contributors to a project](/bitrise-platform/projects/managing-user-access-to-a-project) on the web UI either by adding existing workspace members or inviting outside contributors. Contributors can have different roles in workspaces that determine what they can do and cannot do: - When it comes to Bitrise CI, we differentiate [Owner, Admin, Platform Engineer, Developer, Testers/QA](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) roles - When it comes to [Release Management](/release-management/configuring-connected-apps/release-management-roles-and-permissions), we differentiate workspace-level roles (Workspace Owner, Workspace Manager, Contributor and Viewer) and Release-level roles (Release Manager and App tester). Check out roles and permission tables on [Release management apps](/release-management/configuring-connected-apps/release-management-roles-and-permissions#roles-and-permissions-for-release-management-apps) and [build distribution and releases](/release-management/configuring-connected-apps/release-management-roles-and-permissions). You need a workspace to have a [paid subscription plan](https://bitrise.io/pricing?utm_medium=paid_search&utm_source=google&utm_campaign=all_misc_signup_paid_search_all_2025-04-10&utm_content=branding_pricing_emea&utm_source=google&utm_medium=cpc&utm_campaign=&utm_term=bitrise%20pricing&gad_source=1&gad_campaignid=22492269029&gbraid=0AAAAADEBC46C3y8wDrPzZEypPjE85IZGF&gclid=Cj0KCQiAq7HIBhDoARIsAOATDxDmUOF1Nw6xSIWC_imk3x-MBAxQW3VVSarlhc14CuKm4jV2yT3UDxMaApjPEALw_wcB) on Bitrise. Each of your workspaces can have a different subscription plan which determines how many credits your workspace's projects can use. You can use [SAML SSO or SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise) to securely onboard or offboard an enterprise to your workspace. ### Integrated SSO management on Bitrise While in Jenkins you have to install an authorization plugin for SSO management, in Bitrise it comes as an integral part of our [paid plans](https://bitrise.io/pricing). Workspace with such plans [can set up SAML SSO](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise) as their single gateway to their Workspace on Bitrise. No more remembering usernames and credentials! All the Workspace owner has to do is set up Bitrise as a SAML SSO app on the SAML SSO provider and invite Workspace members to the Bitrise Org. We have specific guides to the [different SAML SSO providers](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise) to guide you through the steps. --- ## Getting started with Android projects In this guide, we’ll walk you through how to add an Android app to Bitrise, what the default Workflows can do, and finally how to test and deploy your app to [bitrise.io](https://www.bitrise.io/) and to Google Play Store. :::note[Do you have a Bitrise account?] Make sure you have signed up to [bitrise.io](https://www.bitrise.io) and can access your Bitrise account. There are multiple ways of registering an account: - [Signing up with email](/bitrise-platform/getting-started/signing-up-for-bitrise#signing-up-with-email) - [Signing up with a Git provider](/bitrise-platform/getting-started/signing-up-for-bitrise#signing-up-with-a-git-provider) ::: ### Adding an Android project to Bitrise Add your project the same way as any other: see [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project) for the full walkthrough of the wizard. This section covers what's specific to Android. #### How the scanner detects an Android project The project scanner looks for a Gradle wrapper script (`gradlew`) in your repository, then checks the Gradle build scripts next to it for the `com.android.application` plugin. If it finds this plugin in at least one `build.gradle` or `build.gradle.kts` file, it registers your project as Android. The scanner skips common non-source directories, such as `.git`, `.gradle`, `.idea`, `build`, and `node_modules`. It also steps aside if your repository is already detected as Flutter, React Native, Cordova, Ionic, or Kotlin Multiplatform, since those scanners handle their own Android configuration. #### What you can configure During the **CI configuration** stage, the wizard shows: - **Project location**: the directory that contains your `gradlew` file. If the scanner finds more than one, you can pick which one to use. - **Module**: the Gradle module to build, for example `app`. - **Variant**: the build variant to use, for example `Debug`. You can leave this blank and add variants later. ### Managing dependencies for Android projects The Gradle build system allows you include external binaries or other library modules as dependencies. Bitrise can install these dependencies for your project during the build process. :::tip[Adding build dependencies] You can read more about adding dependencies to your Android project: [https://developer.android.com/studio/build/dependencies](https://developer.android.com/studio/build/dependencies) ::: 1. Make sure your project's `build.gradle` file lists all your dependencies. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Make sure your Workflow includes the **Android Build** Step. If the project scanner generated a Workflow called **build_apk** when first adding your app, that Workflow includes the Step. It installs all dependencies listed in the `build.gradle` file without any additional configuration. 1. Make sure your Workflow includes the **Install missing Android SDK components** Step. The Step must be BEFORE the **Android Build** Step in the Workflow. It will install all Android SDK tool that your project might need. ### Testing your Android app We have several Steps dedicated to assisting you in testing your Android app during the CI process. - The **[Android Lint](https://www.bitrise.io/integrations/steps/android-lint)** Step runs Lint on your Android project source files and detects potential syntax errors to keep your code error free. - The **[Android Unit Test](https://www.bitrise.io/integrations/steps/android-unit-test)** Step runs your project's unit tests. You can run it for all your different modules and flavors. [Android unit tests](/bitrise-ci/testing/testing-android-apps/android-unit-tests) - The [**Virtual Device Testing for Android**](https://www.bitrise.io/integrations/steps/virtual-device-testing-for-android) uses Firebase TestLab to run Android tests on virtual devices. [Device testing for Android](/bitrise-ci/testing/device-testing-with-firebase/device-testing-for-android) The **[Android Unit Test](https://www.bitrise.io/integrations/steps/android-unit-test)** Step and the [**Virtual Device Testing for Android**](https://www.bitrise.io/integrations/steps/virtual-device-testing-for-android) Step can both export their results to [test reports](/bitrise-ci/testing/deploying-and-viewing-test-results). To do so, simply make sure that your Workflow includes the **Deploy to Bitrise.io** Step at the very end of the Workflow. ### Signing your Android app In order to publish an Android app to Google Play, you need to digitally sign the app. Bitrise can also do this for you: you'll just need to upload a keystore file, and provide the necessary authentication. :::note[Other code signing options] In this section, we'll go through how to sign an Android app with the Android Sign Step. There are other ways to sign your app - check out the other options in our relevant guides: [Android code signing](/bitrise-ci/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step). ::: 1. [Generate a keystore file](https://developer.android.com/studio/publish/app-signing#generate-key)[Generate a keystore file](https://reactnative.dev/docs/signed-apk-android#generating-an-upload-key). 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Code signing** from the menu. 1. Drag-and-drop your keystore file to the **ANDROID KEYSTORE FILE** field. 1. Fill out the **Keystore password**, **Keystore alias**, and **Private key password** fields and click **Save metadata**. ![keystore-alias.png](/img/_paligo/uuid-0b79fc48-3861-0744-0f53-53a6c65ffc2c.png) 1. Open the Workflow Editor. 1. Add the **Android Sign** Step to your Workflow. And that's it. The next time you'll run a build, the **Android Sign** Step will sign the generated binary. ### Deploying an Android app to bitrise.io In this section, we'll go through how to deploy your Android project to [bitrise.io](https://www.bitrise.io/). Deploying to [bitrise.io](https://www.bitrise.io) means that the build artifacts generated during the build will be available for download once the build is finished. You can use this to test your Android app on your own test devices, for example. To deploy your app to [bitrise.io](https://www.bitrise.io/): **Workflow Editor** 1. Make sure your Workflow contains the **[Android Build](https://www.bitrise.io/integrations/steps/android-build)** Step to build your app. Optionally, you can build your app with the **[Gradle Runner](https://www.bitrise.io/integrations/steps/gradle-runner)** Step. This requires a bit more configuration from you but allows for more extensive customization. 1. Add the **[Deploy to Bitrise.io](https://www.bitrise.io/integrations/steps/deploy-to-bitrise-io)** Step to your Workflow. :::tip[Notifying other users] You can use the **Notify: User Roles** and the **Notify: Emails** inputs of the Step to set up notifications about your deploy. Click the input names to reveal more information about how to configure them. ::: 1. Optionally, set the **Enable public page for the App?** input of the Step to **true** so the Step [enables the public install page](/bitrise-ci/deploying/bitrise-ota-app-deployment#deploying-with-the-deploy-to-bitriseio-step) for your app. 1. Run a build. **Configuration YAML** 1. Open the `bitrise.yml` file of your app. 1. Make sure your Workflow contains the `android-build` Step to build your app. ```yaml workflows: example-workflow: steps: - android-build@1: ``` Optionally, you can build your app with the `gradle-runner` Step. This requires a bit more configuration from you but allows for more extensive customization. 1. Set the `module` and/or `variant` input to tell the Step what to build. In this example, we're building a debug variant of the Android project. ```yaml workflows: example-workflow: steps: - android-build@1: inputs: - variant: debug - deploy-to-bitrise-io: {} ``` 1. Add the `deploy-to-bitrise-io` Step to your Workflow. ```yaml workflows: example-workflow: steps: - android-build@1: inputs: - variant: debug - deploy-to-bitrise-io: {} ``` :::tip[Notifying other users] You can use the `notify_user_groups` and the `notify_email_list` inputs of the Step to set up notifications about your deploy: - The `notify_user_groups` input allows you to send notifications based on the [access roles](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) granted to users. For example, you can set the input to notify everyone with an **Admin** and a **Developer** role. Set multiple roles separated by a comma: `- notify_user_groups: admins, testers`. - The `notify_email_list` input only accepts Secrets, and the Secret should contain comma-separated lists of email addresses. ::: 1. Optionally, set the **Enable public page for the App?** input of the Step to **true** so the Step [enables the public install page](/bitrise-ci/deploying/bitrise-ota-app-deployment#deploying-with-the-deploy-to-bitriseio-step) for your app. 1. Run a build. The **Deploy to Bitrise.io** Step will deploy the app. You can share the generated binary with your team members using the build’s URL. **A bitrise.yml for deploying an Android app to Bitrise** In this example, we're building the `debug` variant of an Android app, and deploy it to bitrise.io, as. ### Setting up Google Play deployment for the first time Deploying to Google play publishes your app to Google's online store. When you do it for the first time, this requires a bit more work than simply deploying to [bitrise.io](https://www.bitrise.io/). Once the necessary configurations are in place, it becomes very simple. When configuring Google Play deployment for the first time, you need to link your Google Play Developer account to an API project, set up API access, and upload the service account JSON key to Bitrise. 1. Upload the first AAB or APK manually to Google Play [using the Google Play Console](https://support.google.com/googleplay/android-developer/answer/113469?hl=en). 1. [Link](https://developers.google.com/android-publisher/getting_started) your Google Play Developer Console to an API project. 1. [Set up API Access Clients using a service account](https://developers.google.com/android-publisher/getting_started): Please note when you create your service account on the Google Developer Console, you have to choose `json` as **Key Type**. 1. Grant the necessary rights to the service account with your [Google Play Console](https://play.google.com/apps/publish). Go to **Settings**, then **Users & permissions**, then **Invite new user**. Due to the way the Google Play Publisher API works, you have to grant at least the following permissions to the service account: - Access level: View app information. - Release management: Manage production releases, manage testing track releases. - Store presence: Edit store listing, pricing & distribution. 1. As an optional step, you can add translations to your Store Listing: [Translate & localize your app](https://support.google.com/googleplay/android-developer/answer/3125566?hl=en). 1. [Connect your Google service account to Bitrise](/bitrise-platform/integrations/connecting-a-google-service-account-to-bitrise). ### Deploying to Google Play Deploying to Google Play requires [a signed APK or AAB file](/bitrise-ci/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step) and the **[Google Play Deploy](https://www.bitrise.io/integrations/steps/google-play-deploy)** Step. **Workflow Editor** 1. [Upload your service account JSON key to the **Files** section](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds). 1. In the **Files** section, copy the **Download URL** of your service account file. For example, `BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL`. 1. Open the Workflow Editor and select **Secrets**. 1. Create a Secret with the copied download URL as the value. If you uploaded the JSON key file to Bitrise, the download URL is an Environment Variable so check the **Replace variables in inputs** checkbox. :::note[Direct link] If you use a direct link to your keystore file without uploading it to Bitrise, you don't need to check the **Replace the variables in inputs** option. ::: 1. Add the **Google Play Deploy** Step to your Workflow. 1. In the **Service Account JSON key file path** input, paste the Secret you created. 1. In the **Package name** input, add the package name of your app. 1. In the **Track** input, add the track where you want to deploy your APK (for example, alpha/beta/rollout/production or any custom track you set). **Configuration YAML** 1. [Upload your service account JSON key to the **Files** section](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds). :::note[Uploading the service account JSON key file] We recommend uploading the service account JSON key to Bitrise but it is not mandatory: you can store it elsewhere and provide a direct link to it. ::: 1. Open your app's Configuration YAML file and add the `google-play-deploy` Step to it. ```yaml deploy-workflow: steps: - google-play-deploy: inputs: ``` 1. In the `service_account_json_key_path` input, you need to provide the path to the service account JSON key file. [Create a Secret](/bitrise-ci/configure-builds/secrets) to the path and reference that here. ```yaml deploy-workflow: steps: - google-play-deploy: inputs: - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL" ``` 1. In the `package` input, add [the package name](https://support.google.com/admob/answer/9972781?hl=en#:~:text=The%20package%20name%20of%20an,supported%20third%2Dparty%20Android%20stores.) of your app. ```yaml deploy-workflow: steps: - google-play-deploy: inputs: - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL" - package_name: myApp ``` 1. In the `track` input, add the track where you want to deploy your app binary (for example, alpha/beta/rollout/production or any custom track you set). ```yaml deploy-workflow: steps: - google-play-deploy: inputs: - service_account_json_key_path: "$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL" - package_name: myApp - track: alpha ``` That’s all! Start or schedule a build and share the URL with external testers or distribute your app on an app store of your choice! --- ## Getting started with Expo projects You can generate React Native projects [with the React Native CLI or with the Expo CLI](https://facebook.github.io/react-native/docs/getting-started.html). [Expo](https://docs.expo.dev/versions/latest/) is a toolchain that allows you to quickly get a React Native app up and running without having to use native code in Xcode or Android Studio. In this guide we discuss how to set up, test, code sign and deploy your React Native project built with the [Expo CLI](https://docs.expo.dev/get-started/installation/). ### Adding an Expo project to Bitrise Add your project the same way as any other: see [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project) for the full walkthrough of the wizard. This section covers what's specific to Expo. #### How the scanner detects an Expo project The project scanner first looks for a `package.json` file that lists `react-native` as a dependency. If it also lists `expo` as a dependency, and there's an `app.json`, `app.config.js`, or `app.config.ts` file alongside `package.json`, Bitrise registers the project as Expo-based rather than plain React Native. In this mode, the scanner skips checking for native `ios/` and `android/` directories. #### What you can configure During the **CI configuration** stage, the wizard shows: - **Expo project directory**: the directory containing your `package.json` and Expo config file. - **Platform**: which platform to build for EAS Build: all, Android, or iOS. ### Installing JavaScript dependencies If the Bitrise project scanner has successfully scanned your project, **Run npm command** or **Run yarn command** Steps will be included in your default Workflows. These Steps can install the missing JavaScript dependencies for your app. For native Android dependencies, you can use the **Install missing Android SDK components** Step. For native iOS dependencies, you can use, among others, the **Brew install** Step or the **Run CocoaPods install** Step. To install JavaScript dependencies with npm: :::note[Using Yarn instead of npm] In this guide, we're using npm to install JavaScript dependencies. However, you can use the **Run yarn command** Step: it can install missing JS dependencies without any additional configuration required. ::: 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Make sure your Workflow includes the **Run npm command** Step. 1. In **The 'npm' command with arguments to run** input variable, type `install`. ![Getting_started_with_React_Native_apps.png](/img/_paligo/uuid-021a140f-5b4c-697c-a5ac-4b5429ce1bab.png) :::tip[Using the `npm ci` command instead of `npm install`] If you already have an up to date `package-lock.json` file in your project, we recommend using the `ci` command in **The 'npm' command with arguments to run** input. Using `npm ci` can not only result in much faster build times compared to `npm install` but more reliable builds as well. ::: ### Deploying your Expo project Bitrise supports [Expo Application Services](https://expo.dev/eas) (EAS) for Expo projects, and the default deploy Bitrise Workflow uses the [Run Expo Application Services (EAS) build](https://www.bitrise.io/integrations/steps/run-eas-build) Step to trigger a build on EAS. In case you don’t want to use EAS, you can use [Turtle CLI](https://docs.expo.dev/eas/cli/) for your Bitrise Workflows. See the [Expo build using Turtle CLI](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/react-native-expo-build-using-turtle-cli.md) recipe on GitHub for details. :::note[CodePush] You can deploy updates to your users' devices with Bitrise CodePush. CodePush is part of [Release Management](/release-management) and it is supported for React Native and Expo apps. For more information about CodePush, check out the official guides: [CodePush](/release-management/codepush/about-codepush). ::: --- ## Getting started with Flutter projects Flutter is a mobile app SDK that allows developers to create native apps for both iOS and Android. [Bitrise](https://app.bitrise.io/users/sign_in) supports Flutter apps: we have dedicated Steps to help you with all your Flutter needs. This guide walks you through setting up, testing, building and deploying a simple Flutter project on Bitrise. ### Adding a Flutter project to Bitrise Add your project the same way as any other: see [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project) for the full walkthrough of the wizard. This section covers what's specific to Flutter. #### How the scanner detects a Flutter project The project scanner looks for a `pubspec.yaml` file anywhere in your repository, excluding `node_modules`. Every directory that has one is a candidate Flutter project. For each candidate, the scanner also checks for: - A `test/` directory with at least one `*_test.dart` file, to enable testing. - An `ios/Runner.xcworkspace` directory, to enable iOS builds. - An `android/build.gradle` or `android/build.gradle.kts` file, to enable Android builds. - A `web/` directory, to enable web builds. It suppresses the standalone iOS, macOS, and Android scanners for the same project, since the generated Flutter Workflow already handles those platforms. #### What you can configure During the **CI configuration** stage, the wizard shows a single option: **Project location**, the directory that contains your `pubspec.yaml` file. Everything else, including which platforms to build, is detected automatically and baked into the generated Workflow. ### Testing a Flutter app You can write and run unit-, widget-, and integration tests with Flutter. For more information, check out [Flutter’s official documentation](https://flutter.io/docs/testing). You can use our automatically generated **primary** Workflow to test your Flutter app. It can include the **Flutter Test** Step that runs Flutter tests and can also generate code coverage reports. :::note[Test reports] The **Deploy to Bitrise.io** Step exports the results of the **Flutter Test** Step to **Tests** tab by default. ::: To run tests on a Flutter app: 1. Open your app’s Workflow Editor and open the **primary** Workflow, or any of your Workflows that you want to use to run tests. 1. In the **Flutter Install** Step, fill in the **Flutter SDK version or bundle URL** input. You can specify either tags or branches of the Flutter SDK’s git repository. The default value is `stable`. This will use the latest stable branch of Flutter. - To find the available version tags, check: [https://github.com/flutter/flutter/releases](https://github.com/flutter/flutter/releases). - To see the the available branches, check: [https://github.com/flutter/flutter/branches](https://github.com/flutter/flutter/branches). 1. Add the **Flutter Test** Step. In the **Additional parameters** input, enter any flags you wish to use to. The Step runs the `flutter test` command with the specified flags. To check the available flags, open a command line interface on your own machine and run `flutter test --help`. ![Getting_started_with_Flutter_apps.png](/img/_paligo/uuid-3c8c65d8-1de1-0a50-62cf-acf76dc76bf9.png) 1. Make sure the **Project Location** input of the **Flutter Test** Step is correct. The default value is the the Environment Variable (Env Var) created for your Flutter project’s location. 1. If you want to generate code coverage reports, set the **Generate code coverage files?** input to `yes`. This runs the `flutter test` command with the `--coverage` flag. 1. To export the test results to the **Tests** tab, add the **Deploy to Bitrise.io** Step to the end of your Workflow. For more information, check out [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). ### Deploying a Flutter app To build and deploy a Flutter app, a Workflow must contain these Flutter Steps: - **Flutter Install** - **Flutter Build** If you have platforms specified in your repository, a deployment Workflow will be automatically generated when adding the project on Bitrise. The content of this Workflow depends on the platforms: for example, if your Flutter project contains only an iOS project, the Workflow will contain the **Certificate and profile installer** Step. You can build both iOS and Android projects at the same time or you can build them separately, each using their own Workflow. You can set this in the **Platform** input of the **Flutter Build** Step any time. By default, the Step is configured according to the platform or platforms that the scanner detected when adding the app on Bitrise. Here’s an example Workflow we’ll use in this configuration, with all the necessary Steps: ![Getting_started_with_Flutter_apps.jpg](/img/_paligo/uuid-f655a8a5-c151-d103-6de5-55a0b3355322.jpg) :::tip[Pipelines for parallelization] In these examples, we're assuming that you are building and deploying both the iOS and Android versions of your app in the same Workflow, performing the necessary operations serially. However, you can do both versions in parallel with a single build trigger by using Pipelines: - [Build Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/about-pipelines) - [Configuring a Bitrise Pipeline](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline) ::: :::note[Packages and libraries] We also support building Flutter packages and libraries. Unlike in the case of apps, there is no artifact to build so there is no need for a **Flutter Build** Step in your Workflow. ::: #### Deploying a cross-platform app to bitrise.io The **Deploy to bitrise.io** Step uploads all the artifacts related to your build into the [**Artifacts**](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) tab on your Build’s page. You can share the generated binary file (APK for Android or an IPA file for iOS) with your team members using the public install page. The public install page is a URL you can share with others who can install the generated app binary on their device. You can also notify user groups or individual users that your APK or IPA file has been built. :::important[Publishing to expo.io] The **Deploy to Bitrise.io** Step does not use Expo commands and doesn’t publish to [expo.io](https://docs.expo.dev/workflow/publishing/). This Step publishes artifacts to Bitrise and is not specific to a particular platform. If you need to publish to [expo.io](https://docs.expo.dev/workflow/publishing/), set the **Run expo publish after eject?** input of the **Expo Eject** Step to `yes`. Be aware that in that case you have to provide your username and password for your Expo account to publish to [expo.io.](http://expo.io/) ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Make sure you have the **Deploy to bitrise.io** Step in your Workflow. 1. In the **Notify: User Roles**, add the role so that only those get notified who have been granted with this role. Or fill out the **Notify: Emails** field with email addresses of the users you want to notify. Make sure you set those email addresses as [Secrets](/bitrise-ci/configure-builds/secrets)! These details can be also modified under **Notifications** if you click the **eye** icon next to your generated binary in the **Artifacts** tab. 1. If you want the Step to generate a public install page for you, set the **Enable public page for the App?** input to `true`. #### Deploying a Flutter app to App Store Connect To deploy your iOS Flutter project to the App Store, you’ll need to build the app, export an IPA file and submit it to the App Store. Unlike testing, this requires code signing files: - An iOS Distribution Certificate (a .p12 file). - An App Store Provisioning Profile. For Flutter applications, code signing requires setting a Team ID in the project settings in Xcode. ##### Configuring Team ID for Flutter apps Once you created your iOS project locally, you will need to review the project settings for it in Xcode. More specifically, you need to set a valid Team ID: without that, your build will fail on Bitrise. 1. In Xcode, open **Runner.xcworkspace** in your app’s **ios** folder. 1. To view your app’s settings, select the **Runner** project in the Xcode project navigator. Then, in the main view sidebar, select the **Runner** target. 1. Select the **General** tab. 1. In the **Signing** section, find the **Team** menu and set it to the team associated with your registered Apple Developer account. 1. Commit the change to your repository! :::important[Don't forget to commit your changes!] If you only set the Team ID locally, your build will still FAIL on Bitrise! ::: ##### Configuring Flutter deployment to the App Store on Bitrise To deploy your app to the App Store, you need to upload the code signing files. You have two options: - Upload the code signing certificate(s) to Bitrise and use automatic code signing with the [Manage iOS Code signing](https://bitrise.io/integrations/steps/manage-ios-code-signing) Step. - Upload the provisioning profile(s) and the code signing certificate(s) to Bitrise and use manual code signing with the [Certificate and profile installer](https://bitrise.io/integrations/steps/certificate-and-profile-installer) Step. In this guide, we will focus on the second option, manual code signing: 1. Make sure you have the **Certificate and profile installer** Step in your Workflow. 1. Upload the required code signing files to [Bitrise](https://app.bitrise.io/users/sign_in). 1. Open the **Flutter Build** Step and find the **iOS Platform Configs** input group. 1. Make sure the **Additional parameters** input has the value `--release`. 1. Check the **Platform** input of the Step: make sure it’s set to either `iOS` or `both`. 1. Set the **iOS output artifact type** input to **archive**. ![flutter-build-ios-config.png](/img/_paligo/uuid-821c4edf-e9a6-a85e-a6e5-8cce61ab5f42.png) 1. Add the **Export iOS and tvOS Xcode archive** Step to your Workflow. It should be after the **Flutter Build** Step. 1. Set the **Distribution method** input of the Step to **app-store**. 1. Add the **Deploy to App Store Connect** Step to the end of the Workflow. 1. Provide your Apple credentials in the respective input fields. - Apple ID. - password or, if you use two-factor authentication on App Store Connect, your application password. Don’t worry, the password will not be visible in the logs or exposed . 1. Start a build! If all goes well, the Step will submit the app to App Store Connect. You can, from the App Store Connect page, distribute the app to external testers via Testflight, or release it to the App Store itself. #### Deploying a Flutter app to Google Play To deploy your app to Google Play, you need to export an App Bundle file and sign it. You have two options: - You can [configure code signing](https://flutter.dev/docs/deployment/android#configure-signing-in-gradle) in the app’s `build.gradle` file and then Flutter will sign your app during the build phase. - Sign your AAB or APK file on Bitrise with our dedicated Step. The scope of this guide is the second option: signing your AAB/APK file with the **Android Sign** Step. 1. [Generate a keystore file](https://flutter.io/docs/deployment/android#create-a-keystore). The keystore file is required for code signing. 1. Open an app on Bitrise and go to **Workflow** > **Code signing** > **Android Code Signing**. 1. Drag and drop the keystore file, and fill out the metadata. 1. [Configure Google Play access.](/bitrise-ci/deploying/android-deployment/generating-and-deploying-android-app-bundles#setting-up-google-play-deployment-for-the-first-time) You only need to do this for your very first Google Play deployment of the app. 1. In the **Flutter Build** Step, find the **Android Platform Configs** input group and make sure the **Additional parameters** input has the value `--release`. 1. In the **Android output artifact type** input field, select either **APK** or **appbundle** depending on your deployment requirements. 1. In the **Output (.apk, .aab) pattern** input, set the path where the **Deploy to Google Play** Step will be able to access the generated binary. The path should be relative to the project source directory, stored in the BITRISE_SOURCE_DIR Environment Variable. 1. Make sure you have the **Deploy to Google Play** Step after the **Android Sign** Step in your Workflow. 1. Fill out the required input fields as follows: - **Service Account JSON key file path**: This field can accept a remote URL so you have to provide the Env Var which contains your uploaded service account JSON key. For example: `$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL`. - **Package name**: The package name of your Android app. - **Track**: The track where you want to deploy your APK (for example, alpha/beta/rollout/production or any custom track you set). ### Additional Flutter content - [Building Android apps with Flutter modules](https://support.bitrise.io/hc/en-us/articles/360015714357) - [Flutter Test Step freezes on "Waiting for another flutter command to release the startup lock..."](https://support.bitrise.io/hc/en-us/articles/360015714217) - [Reducing build time for Flutter apps](https://support.bitrise.io/hc/en-us/articles/360020722937) - [Could not resolve package dependencies in Flutter](https://support.bitrise.io/hc/en-us/articles/360019760178) --- ## Getting started with Ionic/Cordova projects You can use Cordova and Ionic frameworks to develop cross-platform apps. Bitrise can help you with its automated testing, code signing and deployment procedures so that you can ship your iOS and/or Android app/s to the respective marketplace in no time! If your Workspace has more than one concurrency, you can have Android and iOS builds run simultaneously. Now let us guide you through the process! :::note[Do you have a Bitrise account?] Make sure you have signed up to [bitrise.io](https://www.bitrise.io) and can access your Bitrise account. There are multiple ways of registering an account: - [Signing up with email](/bitrise-platform/getting-started/signing-up-for-bitrise#signing-up-with-email) - [Signing up with a Git provider](/bitrise-platform/getting-started/signing-up-for-bitrise#signing-up-with-a-git-provider) ::: ### Adding an Ionic/Cordova project to Bitrise Add your project the same way as any other: see [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project) for the full walkthrough of the wizard. This section covers what's specific to Ionic and Cordova. #### How the scanner tells Ionic and Cordova apart The project scanner checks for an `ionic.config.json` file first, or the legacy `ionic.project` file. If it finds one, it registers the project as Ionic and doesn't check for `config.xml` at all. If neither Ionic file is present, the scanner looks for a `config.xml` file with a `cordova.apache.org` namespace and registers the project as Cordova. If it also finds an Ionic config file alongside that `config.xml`, it defers to Ionic instead. #### What you can configure During the **CI configuration** stage, the wizard shows: - **Directory of the config.xml file**: shown only if your config file isn't at the root of your repository. - **Platform**: which platform to build for, Android, iOS, or both. ### Installing JavaScript dependencies If the Bitrise project scanner has successfully scanned your project, **Run npm command** or **Run yarn command** Steps will be included in your default Workflows. These Steps can install the missing JavaScript dependencies for your app. For native Android dependencies, you can use the **Install missing Android SDK components** Step. For native iOS dependencies, you can use, among others, the **Brew install** Step or the **Run CocoaPods install** Step. To install JavaScript dependencies with npm: :::note[Using Yarn instead of npm] In this guide, we're using npm to install JavaScript dependencies. However, you can use the **Run yarn command** Step: it can install missing JS dependencies without any additional configuration required. ::: 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Make sure your Workflow includes the **Run npm command** Step. 1. In **The 'npm' command with arguments to run** input variable, type `install`. ![Getting_started_with_React_Native_apps.png](/img/_paligo/uuid-021a140f-5b4c-697c-a5ac-4b5429ce1bab.png) :::tip[Using the `npm ci` command instead of `npm install`] If you already have an up to date `package-lock.json` file in your project, we recommend using the `ci` command in **The 'npm' command with arguments to run** input. Using `npm ci` can not only result in much faster build times compared to `npm install` but more reliable builds as well. ::: ### Testing Ionic/Cordova apps You can run unit tests for Ionic/Cordova apps on Bitrise by using our **Karma Jasmine Test Runner** or **Jasmine Test Runner** Steps. If your Cordova/Ionic project has a Karma Jasmine dependency in its **package.json** file and a `karma.conf.js` file in the project root, our scanner will detect it when you're adding your app and automatically insert the respective testing Step into your Workflow. If this dependency is missing from your project, you can manually insert one of our testing steps to your Workflow using our Workflow Editor. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Make sure you have a testing Step in your Workflow. :::important[Installing dependencies] Make sure you've completed [Installing JavaScript dependencies](#installing-javascript-dependencies) before you run tests. ::: You can choose between the **Karma Jasmine Test Runner** and the **Jasmine Test Runner** Steps. **Cordova app configuration with Karma Jasmine Test Runner** In this example, you can find a `bitrise.yml` configuration that includes a Workflow called **primary**. This Workflow includes the **Karma Jasmine Test Runner** Step. ```yaml primary: steps: - activate-ssh-key@4.0.3: run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}' - git-clone@4.0.11: {} - script@1.1.5: title: Do anything with Script step - npm@0.9.1: inputs: - command: install - karma-jasmine-runner@0.9.1: {} - deploy-to-bitrise-io@1.3.15: {} ``` ### Code signing Ionic/Cordova projects If you want to build an app for iOS or Android, you need to upload the platform-specific files on the **Project settings** page. You can also generate builds for both platforms which requires uploading all code signing files of the platforms. #### iOS code signing for Ionic and Cordova projects Naturally, Bitrise supports iOS applications built with either **Ionic** or **Cordova**. However, the code signing process is slightly different compared to a native Xcode project. Bitrise supports both manual and automatic provisioning for Ionic and Cordova apps as well - and once again, the processes are somewhat different. ##### Ionic/Cordova code signing with manual code signing asset management 1. Generate the native Xcode project locally from your Ionic or Cordova project by calling `cordova platform add ios` or `ionic cordova platform add ios`. 1. Upload the files to [bitrise.io](https://www.bitrise.io): open the **Project settings** page and select **Code signing** on the left. Upload a certificate and a provisioning profile. ![upload-code-signing.png](/img/_paligo/uuid-88a3d6bf-be6f-1811-a908-9072b4b88a9a.png) 1. Make sure you have the **Certificate and profile installer** Step in your Workflow. 1. Add the **Generate cordova build configuration** Step to your Workflow. It must come after the **Certificate and profile installer** Step. 1. Fill in the required inputs for the Step. Please note that both the **Code Signing Identity** and the **Provisioning Profile** are required inputs for iOS apps even though they are not marked as such. - **Build configuration**: you can set it to either `debug` or `release`. - **Code Sign Identity**: enter a Developer or a Distribution identity. - **Provisioning Profile**: enter the appropriate provisioning profile. - **Packaging Type**: this controls what type of build is generated by Xcode. Set the type of code signing you need. ![gen-cordova-build.png](/img/_paligo/uuid-bc068222-9d71-6b17-2d07-9bdca30fa368.png) 1. Add the **Cordova archive** or the **Ionic archive** Step to your Workflow. 1. Fill in the required inputs. - The **Platform** input needs to be set to: `device`. - The **Build command configuration** input must match the **Build configuration** input of the **Generate cordova build configuration** Step. This Step must come after the **Generate cordova build configuration** Step in the Workflow. 1. Run your build! ##### Ionic/Cordova code signing with automatic code signing asset management 1. Make sure your .p12 signing certificates are uploaded to [bitrise.io](https://www.bitrise.io). 1. Add the **Cordova prepare** or the **Ionic prepare** Step to your Workflow. These Steps call the `platform rm` and `platform add` commands. 1. Add the **[Manage iOS Code Signing](https://www.bitrise.io/integrations/steps/manage-ios-code-signing)** Step to your Workflow. If you have both the **Certificate and Profile Installer** and the **Manage iOS Code Signing** Steps in your Workflow, your build might encounter unexpected issues. The Step will export: - The project’s development team. - The installed codesign identity’s name. - The installed provisioning profile. :::caution[One code signing Step only] If you have both the **Certificate and profile installer** and the **Manage iOS Code Signing** Steps in your Workflow, your build might encounter unexpected issues. ::: 1. Select the **Apple service connection method** (based on the [Apple service you have set up in Bitrise](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services)) and the **Distribution method**. ![manage-ios-code.png](/img/_paligo/uuid-de743a8c-7a79-dda4-b9de-e3c71f2ac32a.png) 1. Add the **Generate cordova build configuration** Step to your Workflow. 1. Configure the Step to use the code signing settings exported by the **Manage iOS Code Signing** Step: **Development distribution example**: ```yaml - generate-cordova-build-configuration: inputs: - development_team: $BITRISE_DEVELOPER_TEAM - package_type: development - code_sign_identity: iPhone Developer - configuration: debug ``` **Production distribution example**: ```yaml - generate-cordova-build-configuration: inputs: - development_team: $BITRISE_DEVELOPER_TEAM - package_type: app-store - code_sign_identity: iPhone Developer - configuration: release ``` 1. Add the **Cordova Archive** or the **Ionic Archive** Step to your Workflow. 1. Fill in the required inputs. - The **Platform** input needs to be set to: `device`. - The **Build command configuration** input must match the **Build configuration** input of the **Generate cordova build configuration** Step. ![gen-cordova-build.png](/img/_paligo/uuid-bc068222-9d71-6b17-2d07-9bdca30fa368.png) 1. Set the **Should remove platforms as prepare step?** to `false`. This is crucial: it ensures the Step will not remove and re-add the platform of the native projects generated in the **Cordova prepare** or the **Ionic prepare** Step. 1. Run your build! #### Android code signing using the Android Sign Step You can create a signed APK using the **Android Sign** Step in your Bitrise Workflow. This Step is configured to run if you have already uploaded your [keystore file](https://developer.android.com/studio/publish/app-signing#generate-key) to Bitrise. The **Android Sign** Step is not required if signing is configured in your project’s `build.gradle` file. If so, running the **Android Build** Step (or the **Gradle Runner** Step) signs the output (APK or AAB) automatically. Nevertheless, we recommend that you use the **Android Sign** Step to sign your project in an easy and secure way. :::note[jarsign and apksigner] APKs can be signed with either `jarsigner` or `apksigner`. For APKs, if you wish to use apksigner to sign your project, then in the Android Sign Step you have to first set the Enables `apksigner` input to true and leave the APK Signature Scheme input on automatic. This way `apksigner` checks your APK’s minimum and target SDK versions and chooses the required schemes. It signs your project with V1 scheme if your minimum supported version is low and it also signs with other schemes for newer systems. Please note that AAB files can only be signed with jarsigner. The Step uses `jarsigner` if it detects a file ending with `.aab` ::: 1. [Upload your keystore file to Bitrise](/bitrise-ci/code-signing/android-code-signing/uploading-android-keystore-files-to-bitrise). 1. Add the **Android Sign** Step to your Workflow after the Step that builds your APK or AAB file. Bitrise uses the above Environment Variables and sets them as inputs into the respective fields of the **Android Sign** Step. Once the Step runs, it produces either a signed APK or an AAB. The signed APK or AAB is used in deploy Steps, for example, the**Google Play Deploy** Step or the **Deploy to Bitrise.io** Step. The latter deploys the APK/AAB on the **Artifacts** tab. You can also use [Release Management](/release-management) to deploy your app once you built an installable artifact. :::note[Downloading your keystore file] You can download your keystore file to the project directory using the **[File Downloader](https://www.bitrise.io/integrations/steps/file-downloader)** Step: ```yaml - file-downloader: inputs: - source: $BITRISEIO_ANDROID_KEYSTORE_URL - destination: "$HOME/keystores/my_keystore.jks" #native android# ``` If a Step requires the keystore file, make sure to include that Step AFTER the **File Downloader** Step. After this Step, `my_keystore.jks` will be available at `$HOME/keystores/my_keystore.jks`. ::: ### Deploying Ionic/Cordova apps To build and deploy an Ionic or Cordova app on Bitrise, you need to digitally sign both the Android and iOS project (if you're building both) and then use the Cordova Archive or the Ionic Archive Step to build the app before deploying it. You can deploy the successfully built app to: - Online stores, such as the Google Play Store or Apple's App Store. - Bitrise.io: the generated binaries will be available on the **Artifacts** tab of the build's page. You can download them from there or share them with others via the public install page. #### Deploying a cross-platform app to bitrise.io The **Deploy to bitrise.io** Step uploads all the artifacts related to your build into the [**Artifacts**](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) tab on your Build’s page. You can share the generated binary file (APK for Android or an IPA file for iOS) with your team members using the public install page. The public install page is a URL you can share with others who can install the generated app binary on their device. You can also notify user groups or individual users that your APK or IPA file has been built. :::important[Publishing to expo.io] The **Deploy to Bitrise.io** Step does not use Expo commands and doesn’t publish to [expo.io](https://docs.expo.dev/workflow/publishing/). This Step publishes artifacts to Bitrise and is not specific to a particular platform. If you need to publish to [expo.io](https://docs.expo.dev/workflow/publishing/), set the **Run expo publish after eject?** input of the **Expo Eject** Step to `yes`. Be aware that in that case you have to provide your username and password for your Expo account to publish to [expo.io.](http://expo.io/) ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Make sure you have the **Deploy to bitrise.io** Step in your Workflow. 1. In the **Notify: User Roles**, add the role so that only those get notified who have been granted with this role. Or fill out the **Notify: Emails** field with email addresses of the users you want to notify. Make sure you set those email addresses as [Secrets](/bitrise-ci/configure-builds/secrets)! These details can be also modified under **Notifications** if you click the **eye** icon next to your generated binary in the **Artifacts** tab. 1. If you want the Step to generate a public install page for you, set the **Enable public page for the App?** input to `true`. #### Deploying your Android project to Google Play You can use the **Deploy to Google Play** Step in your Workflow to upload your digitally signed AAB/APK to the Google Play Store. 1. Add the **Cordova archive** or the **Ionic archive** Step to your Workflow. Note that if you’re building for both iOS and Android in one project, and either of your apps fails, the whole **Cordova archive/Ionic archive** Step will fail. 1. Fill in the required inputs. - Set **Platform to use in cordova-cli commands** (Cordova) or **Platform to use in ionic-cli commands** (Ionic) to **android** (or **ios,android** if building for both platforms). - Set **Build command target** to **device**. - The **Build command configuration** input must match the **Build configuration** input of the **Generate cordova build configuration** Step. The archive Step must come after the **Generate cordova build configuration** Step in the Workflow. 1. [Configure code signing](/bitrise-ci/getting-started/quick-start-guides/getting-started-with-react-native-projects#signing-your-android-project) for your app. 1. [Configure Google Play access.](/bitrise-ci/deploying/android-deployment/generating-and-deploying-android-app-bundles#setting-up-google-play-deployment-for-the-first-time) You only need to do this for your very first Google Play deployment of the app. 1. Make sure you have the **Deploy to Google Play** Step after the **Android Sign** and **Cordova Archive** or **Ionic Archive** Step in your Workflow. 1. Fill out the required input fields as follows: - **Service Account JSON key file path**: This field can accept a remote URL so you have to provide the Env Var which contains your uploaded service account JSON key. For example: `$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL`. - **Package name**: The package name of your Android app. - **Track**: The track where you want to deploy your APK (for example, alpha/beta/rollout/production or any custom track you set). #### Deploying your iOS project to the App Store 1. Add the **Cordova archive** or the **Ionic archive** Step to your Workflow. Note that if you’re building for both iOS and Android in one project, and either of your apps fails, the whole **Cordova archive/Ionic archive** Step will fail. 1. Fill in the required inputs. - The **Platform** input needs to be set to **device**. - The **Build command configuration** input must match the **Build configuration** input of the **Generate cordova build configuration** Step. The archive Step must come after the **Generate cordova build configuration** Step in the Workflow. 1. [Configure iOS code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) for your iOS project. 1. Add the **Deploy to App Store Connect - Application Loader (formerly iTunes Connect)** Step to your Workflow, after the **Xcode Archive & Export for iOS** Step but preferably before the **Deploy to Bitrise.io** Step. 1. Provide your Apple credentials in the **Deploy to App Store Connect - Application Loader (formerly iTunes Connect)** Step. The Step will need your: - Apple ID. - Password or, if you use two-factor authentication on App Store Connect, your application password. Don’t worry, the password will not be visible in the logs or exposed. 1. [Start a build.](/bitrise-ci/run-and-analyze-builds/starting-builds/approving-pull-request-builds) --- ## Getting started with iOS projects Developing for iOS is complex - our aim is to make it as easy as possible for you! In this guide, we’ll walk you through how to add an iOS project to Bitrise, how to run Xcode tests, manage your code signing files, and deploy the finished app to [bitrise.io](https://www.bitrise.io/) and to the App Store. :::tip[Integrating fastlane to Bitrise] You can run your fastlane lane on Bitrise with the same commands you would use locally. Bitrise’s automated Step provides extra functionality to your lane and speed up your builds: [fastlane](https://github.com/bitrise-io/steps-fastlane). ::: ### Adding an iOS project to Bitrise Add your project the same way as any other: see [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project) for the full walkthrough of the wizard. This section covers what's specific to iOS. #### How the scanner detects an iOS project The project scanner looks for `.xcodeproj` files and `.xcworkspace` directories, then checks each one's build settings: if `SDKROOT` is set to `iphoneos` (or `SUPPORTED_PLATFORMS` includes it), the scanner registers the project as iOS. A project that's already a member of a workspace isn't listed separately, since the workspace covers it. If your repository has no Xcode project or workspace, the scanner falls back to a `Package.swift` file and treats it as a Swift package. It also detects a `Podfile` for CocoaPods and a `Cartfile` for Carthage, and adjusts the generated Workflow to install those dependencies. #### What you can configure During the **CI configuration** stage, the wizard shows: - **Project or workspace path**: the `.xcodeproj`, `.xcworkspace`, or `Package.swift` file to build. - **Scheme name**: any shared scheme found in your project or workspace. The scanner can only detect shared schemes, not user-specific ones. - **Distribution method**: how Bitrise exports your app, for example App Store, Ad Hoc, Enterprise, or Development. This option isn't shown for Swift packages, since those aren't archived. ### Testing your iOS app If you have test targets defined, the default Workflows of an iOS project include the two Steps you need to run your Xcode tests, and view their results on [bitrise.io](https://www.bitrise.io/): - **Xcode Test for iOS** - **Deploy to Bitrise.io** The **Xcode Test for iOS** Step runs the pre-defined Xcode tests. It has a default configuration that does not need to be modified: if the tests are written correctly, they will work. You can find the same configuration options in Xcode, too. :::tip[Checking your selected stack] We recommend checking that the stack selected for your project has the same Xcode version you used to build the project. For example, if your simulator test fails with the Ineligible destinations for the scheme message, then make sure the Xcode version in the **Stacks & Machines** section is correct. You can read more about our stacks: [Build stacks](/bitrise-build-hub/infrastructure/build-stacks/about-build-stacks). ::: The Deploy to Bitrise.io Step will deploy the following to the **Logs** and **Artifacts** tab of the build: - Your Xcode test results. - Your raw xcodebuildoutput log. The **Deploy to Bitrise.io** Step also exports the results of the **Xcode Test for iOS** Step to [test reports](/bitrise-ci/testing/deploying-and-viewing-test-results). ### Creating a signed IPA for Xcode projects :::note[Overview on iOS code signing in Bitrise] For a comprehensive overview on what Steps are available for code signing asset management, visit the [iOS code signing page](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). ::: You can easily create a signed IPA file for your Xcode project with Bitrise. - You have set up [Apple service connection](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) on Bitrise. - Your [code signing files are managed correctly](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). - You set the relevant inputs of our **Xcode Archive & Export for iOS** Step. :::important[Upload the distribution AND the development signing certificates] We strongly recommend uploading BOTH the development and distribution signing certificates for your project. If you don't have an uploaded development signing certificate, Steps with automatic provisioning options will generate one on the fly every time you start a build. This can eventually lead to reaching the maximum number of certificates, blocking you from starting new builds. ::: If you’re all set, proceed to setting up IPA export in your Workflow. **Workflow Editor** 1. Make sure the necessary [code signing files have been collected and uploaded](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning#uploading-ios-code-signing-certificates-to-bitrise). 1. Make sure you have the **Xcode Archive & Export for iOS** Step in your Workflow. 1. Set the **Distribution method** input of the Step. ![xcode-archive.png](/img/_paligo/uuid-fced107c-9b69-e5af-1472-4d96fbada364.png) The options are: - `app-store`: Choose this if you want to deploy the app to the App Store. Requires a Distribution certificate and an App Store provisioning profile. - `ad-hoc`: Choose this if you want to deploy the app to ad-hoc testers. Requires a Distribution certificate and an Ad Hoc provisioning profile. - `enterprise`: Choose this if you have an Apple Enterprise account and want to use that to distribute your app. - `development`: Choose this for internal testing. Requires a Developer certificate and a Development provisioning profile. 1. Set the **Automatic code signing** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t use automatic code signing. - `api-key` [if you use API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` [if you use Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Save the Workflow, and start a new build. **Configuration YAML** 1. Make sure all the [necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) are available for your build. 1. Open the `bitrise.yml` file of your app. 1. Make sure you have the `xcode-archive` Step in your Workflow. ```yaml my-workflow: steps: - xcode-archive: inputs: ``` 1. Set the `distribution_method` input to the correct value. The available options are: - `app-store`: Choose this if you want to deploy the app to the App Store. Requires a Distribution certificate and an App Store provisioning profile. - `ad-hoc`: Choose this if you want to deploy the app to ad-hoc testers. Requires a Distribution certificate and an Ad Hoc provisioning profile. - `enterprise`: Choose this if you have an Apple Enterprise account and want to use that to distribute your app. - `development`: Choose this for internal testing. Requires a Developer certificate and a Development provisioning profile. ```yaml my-workflow: steps: - xcode-archive: inputs: - distribution_method: development ``` 1. Set the `automatic_code_signing` input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t do automatic code signing. - `api-key` [if you use API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` [if you use Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). ```yaml my-workflow: steps: - xcode-archive: inputs: - automatic_code_signing: api-key - distribution_method: development ``` That’s all. Xcode will automatically select the right signing files based on your project’s Bundle ID and Team ID settings, and the export method you set. #### Signing an IPA file with a different team’s code signing file You might want to sign the IPA file with a different team’s code signing files. For example: - If you use your company’s code signing files for internal builds, but your client’s code signing files are used for App Store distribution. - If you use Apple ID for automatic code signing and the Apple ID belongs to multiple teams, use The Developer Portal team to use for this export input to specify which team should be used for automatic code signing asset management. To do so: 1. Make sure the right code signing files of the new development team are uploaded to Bitrise. 1. Set the The Developer Portal team to use for this export option as well (in addition to the **Distribution method**). 1. Set the **Distribution method**. ### Deploying the app to App Store Connect Keep in mind that every time you want to push an app to App Store Connect, it must have a unique build and version number: [increment either or both](/bitrise-ci/run-and-analyze-builds/build-numbering-and-app-versioning) before deploying. 1. Make sure you have a working [connection to your Apple Developer account](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Generate an IPA file on your own machine at least once. 1. [Upload all necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) to Bitrise. To deploy an app to App Store Connect, you need a Distribution type certificate and an App Store type provisioning profile. 1. Make sure the **Xcode Archive & Export for iOS** Step is in your Workflow. 1. Set the **Automatic code signing** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t use automatic code signing, or if you exclusively use Step inputs for Apple service authentication. - `api-key` if you use [API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` if you use [Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Set the **Distribution method** input of the Step to `app-store`. The Step will store the path of the exported .ipa file in the $BITRISE_IPA_PATH Environment Variable. 1. Add the **Deploy to App Store Connect** Step to your Workflow. 1. Fill the required inputs. - Either the app’s Apple ID or its Bundle ID is a required input. One of the two must be provided. - If you set the **Submit for Review** to `yes`, the Step will wait for your submission to be processed on App Store Connect and then submit the given version of the app for review. - The default value of the **Skip App Version Update** input is `No`. Change it only if you incremented the app version number in another way. - If you use an App Store Connect account that is linked to multiple teams, provide either a Team ID or a Team name! 1. Start a build. If all goes well, your app will be submitted to App Store and you can distribute it via Testflight or via the App Store! --- ## Getting started with MacOS projects In this guide, we’ll walk you through how to add a macOS project to Bitrise, how to run Xcode tests, manage your code signing files and deploy the finished app to bitrise.io and to the App Store. ### Adding a macOS project to Bitrise Add your project the same way as any other: see [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project) for the full walkthrough of the wizard. This section covers what's specific to macOS. #### How the scanner detects a macOS project The project scanner looks for `.xcodeproj` files and `.xcworkspace` directories, the same way it does for iOS. To tell the two apart, it checks each build configuration's `SDKROOT`: a `macosx` value (or a `SUPPORTED_PLATFORMS` list that includes it) registers the project as macOS, while `iphoneos` registers it as iOS. As with iOS, a `Package.swift` file without an Xcode project or workspace is treated as a Swift package, and matched to macOS if its declared platforms include `macos`. #### What you can configure During the **CI configuration** stage, the wizard shows: - **Project or workspace path**: the `.xcodeproj`, `.xcworkspace`, or `Package.swift` file to build. - **Scheme name**: any shared scheme found in your project or workspace. - **Export method**: how Bitrise exports your app, for example App Store, Developer ID, Development, or none, which exports a copy of the `.app` file without re-signing it. This option isn't shown for Swift packages. ### Testing your macOS app If you have test targets defined, a default Workflow of a macOS project includes the two Steps you need to run your Xcode tests, and view their results on [bitrise.io](https://bitrise.io/): - **Xcode Test for Mac** - **Deploy to Bitrise.io** :::note[Code signing files] Running Xcode tests and deploying their results to Bitrise do not require any code signing files. So don’t worry about them just yet! ::: The **Xcode Test for Mac** Step runs the pre-defined Xcode tests. It has a default configuration that does not need to be modified: if the tests are written correctly, they will work. You can find the same configuration options in Xcode, too. The **Deploy to Bitrise.io** will deploy the following: - your Xcode test results. - your raw `xcodebuildoutput` log. You can view the results in one place: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). ### Code signing and exporting a macOS app To install and test the app on other physical devices, you will need to create and export an .app or .pkg file. This requires setting up code signing. In the example, we’ll be exporting an app with the **development** export method: you cannot upload such an app to Testflight but you can test it, for example, on the devices of your internal testers. :::note[Automatic Provisioning] The example procedure described here uses manual provisioning, with the **Certificate and profile installer** Step. However, Bitrise also supports [automatic provisioning](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning) but it is not in the scope of this guide. ::: You will need: - the automatically created `deploy` workflow. - a **Development** certificate (a .p12 certificate file). - a **Development** type Provisioning Profile. For a macOS project, the file extension of the provisioning profile is `.provisionprofile`. 1. Set the code signing type of your project in Xcode to either manual or automatic (Xcode managed), and generate the package file locally. 1. Collect and upload the code signing files. The tool can also upload your code signing files to Bitrise - we recommend doing so! Otherwise, upload them manually: enter the Workflow Editor and select the **Code signing** tab, then upload the files in their respective fields. 1. Go to your app’s Workflow Editor, and select the **deploy** workflow in the **WORKFLOW** dropdown menu in the top left corner. 1. Check that you have the **Certificate and profile installer** Step in your Workflow. It must be before the **Xcode Archive for Mac** Step (you can have other Steps between the two, like **Xcode Test for Mac**). 1. Check the **Export method** input under the **app/pkg export configs** input group of the **Xcode Archive for Mac** Step. If you selected **development** when you added the app to Bitrise, you don’t need to change the input. Otherwise, manually set it to **development**. The available options are: - **development**: Signs the app with your Development identity for internal testing. - **app-store**: Signs and packages the app for distribution in the Mac App Store. - **developer-id**: Signs the app with your Developer ID for distribution outside the App Store. - **none**: Exports the app without re-signing. ![macOS_export_method.png](/img/_paligo/uuid-0edf6398-0b97-f558-978e-f7d8bae394e0.png) 1. Start a build. If you uploaded the correct code signing files, the **Certificate and profile installer** Step should install your code signing files and the **Xcode Archive for Mac** Step should export an .app or .pkg file with the development export method. If you have the **Deploy to Bitrise.io** Step in your workflow, you can find the binary package file on the **Artifacts** tab of the build page. ### Deploying the app to the App Store Connect If you set up your code signing files and created an .app or .pkg file for your internal testers, it is time to involve external testers and then to publish your macOS app to the App Store. Let’s see how! :::tip[Developer ID] If you want to distribute your app outside the App Store, you can sign it with a [Developer ID](https://developer.apple.com/support/developer-id/). This method is not in the scope of this guide but on Bitrise, it works the same way: you just need to upload the appropriate code signing files. ::: To deploy to the App Store, you will need these code signing files: - a **Mac App** **Distribution** certificate. - a **Mac** **Installer Distribution** certificate. 1. On your local machine, set up App Store code signing for your project in Xcode, and export an .app or .pkg file. If this fails locally, it will definitely fail on Bitrise, too! 1. Collect and upload the code signing files. 1. Go to the app’s Workflow Editor and create a new Workflow: click the **+** button next to the Workflow dropdown menu, enter the name of your new Workflow and in the **BASED ON** dropdown menu, select **deploy**. This way the new Workflow will be a copy of the basic **deploy** Workflow. 1. Click on the the **app/pkg export methods** , and set the **Export Method** input of the **Xcode Archive for Mac** Step to **app-store**. You can export multiple binaries with different export methods: use the **Export macOS Xcode archive** Step in your Workflow, to do so. 1. Add the **Deploy to App Store Connect - Application Loader (formerly iTunes Connect)** Step to your workflow, after the **Xcode Archive for Mac** Step but preferably before the **Deploy to Bitrise.io** Step. 1. Provide your Apple credentials in the **Deploy to App Store Connect - Application Loader (formerly iTunes Connect)** Step. The Step will need your: - Apple ID. - password or, if you use two-factor authentication on iTunes Connect, your application password. Don’t worry, the password will not be visible in the logs or exposed - [that’s why it is marked SENSITIVE](/bitrise-ci/configure-builds/secrets). And that’s it! Start a build - if everything went well, you should see your app on Testflight. From there, you can distribute it to external testers or release it to the App Store. --- ## Getting started with React Native projects :::tip[Expo projects] If you use Expo in a React Native project, we have a dedicated guide: [Getting started with Expo projects](/bitrise-ci/getting-started/quick-start-guides/getting-started-with-expo-projects). ::: You can easily set up and configure your React Native project on [Bitrise](https://app.bitrise.io/users/sign_in). A React Native repo can consist of an Android and an iOS project so configurations should be done as you would normally do with Android and iOS apps. When running a React Native project on Bitrise, you will see that first an Android, then an iOS build gets built. :::note[Do you have a Bitrise account?] Make sure you have signed up to [bitrise.io](https://www.bitrise.io) and can access your Bitrise account. There are multiple ways of registering an account: - [Signing up with email](/bitrise-platform/getting-started/signing-up-for-bitrise#signing-up-with-email) - [Signing up with a Git provider](/bitrise-platform/getting-started/signing-up-for-bitrise#signing-up-with-a-git-provider) ::: ### Adding a React Native project to Bitrise Add your project the same way as any other: see [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project) for the full walkthrough of the wizard. This section covers what's specific to React Native. #### How the scanner detects a React Native project The project scanner looks for a `package.json` file that lists `react-native` as a dependency, skipping anything under `node_modules`. It then checks for an `ios/` and an `android/` directory next to it, and only registers the project as React Native if at least one of them exists. The scanner also checks whether your project uses Expo: if `package.json` lists `expo` as a dependency and there's an `app.json`, `app.config.js`, or `app.config.ts` file alongside it, Bitrise treats the project as Expo-based instead, and skips the native `ios/`/`android/` check. See [Getting started with Expo projects](/bitrise-ci/getting-started/quick-start-guides/getting-started-with-expo-projects) for that flow. #### What you can configure During the **CI configuration** stage, the wizard shows: - **React Native project directory**: the directory containing your `package.json` file. - For the Android part of your project: **Project root directory**, **Module** (defaults to `app`), and **Variant** (defaults to `Debug`). - For the iOS part of your project: **Project or workspace path**, **Scheme name**, and **Distribution method**. ### Installing JavaScript dependencies If the Bitrise project scanner has successfully scanned your project, **Run npm command** or **Run yarn command** Steps will be included in your default Workflows. These Steps can install the missing JavaScript dependencies for your app. For native Android dependencies, you can use the **Install missing Android SDK components** Step. For native iOS dependencies, you can use, among others, the **Brew install** Step or the **Run CocoaPods install** Step. To install JavaScript dependencies with npm: :::note[Using Yarn instead of npm] In this guide, we're using npm to install JavaScript dependencies. However, you can use the **Run yarn command** Step: it can install missing JS dependencies without any additional configuration required. ::: 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Make sure your Workflow includes the **Run npm command** Step. 1. In **The 'npm' command with arguments to run** input variable, type `install`. ![Getting_started_with_React_Native_apps.png](/img/_paligo/uuid-021a140f-5b4c-697c-a5ac-4b5429ce1bab.png) :::tip[Using the `npm ci` command instead of `npm install`] If you already have an up to date `package-lock.json` file in your project, we recommend using the `ci` command in **The 'npm' command with arguments to run** input. Using `npm ci` can not only result in much faster build times compared to `npm install` but more reliable builds as well. ::: ### Code signing for React Native projects A React Native project can consist of an Android and an iOS project. Both have different signing procedures. Follow our platform-specific instructions to code sign your mobile app for both iOS and Android. #### Signing your Android project All Android apps must be digitally signed with a certificate before they can be installed on Android devices. On Bitrise, you can use our dedicated Step for this purpose but first you'll need a keystore file. 1. [Generate a keystore file](https://reactnative.dev/docs/signed-apk-android#generating-an-upload-key). 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Code signing** from the menu. 1. On the **Android** tab, click **Add keystore file**. 1. In the dialog, drag-and-drop the file and fill out the required fields then click **Continue** ![keystore-alias.png](/img/_paligo/uuid-0b79fc48-3861-0744-0f53-53a6c65ffc2c.png) 1. Open the Workflow Editor. 1. Add the **Android Sign** Step to your Workflow. If you uploaded your keystore file and filled out the metadata, the required inputs of the Step are already filled and require no more configuration from you. :::important[Prerequisite of the Android Sign Step] Make sure to add the **Android Sign** Step after a build Step (**Android Build** Step or **Gradle Runner** Step) in your Workflow. ::: #### Creating a signed IPA for Xcode projects :::note[Overview on iOS code signing in Bitrise] For a comprehensive overview on what Steps are available for code signing asset management, visit the [iOS code signing page](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). ::: You can easily create a signed IPA file for your Xcode project with Bitrise. - You have set up [Apple service connection](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) on Bitrise. - Your [code signing files are managed correctly](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). - You set the relevant inputs of our **Xcode Archive & Export for iOS** Step. :::important[Upload the distribution AND the development signing certificates] We strongly recommend uploading BOTH the development and distribution signing certificates for your project. If you don't have an uploaded development signing certificate, Steps with automatic provisioning options will generate one on the fly every time you start a build. This can eventually lead to reaching the maximum number of certificates, blocking you from starting new builds. ::: If you’re all set, proceed to setting up IPA export in your Workflow. **Workflow Editor** 1. Make sure the necessary [code signing files have been collected and uploaded](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning#uploading-ios-code-signing-certificates-to-bitrise). 1. Make sure you have the **Xcode Archive & Export for iOS** Step in your Workflow. 1. Set the **Distribution method** input of the Step. ![xcode-archive.png](/img/_paligo/uuid-fced107c-9b69-e5af-1472-4d96fbada364.png) The options are: - `app-store`: Choose this if you want to deploy the app to the App Store. Requires a Distribution certificate and an App Store provisioning profile. - `ad-hoc`: Choose this if you want to deploy the app to ad-hoc testers. Requires a Distribution certificate and an Ad Hoc provisioning profile. - `enterprise`: Choose this if you have an Apple Enterprise account and want to use that to distribute your app. - `development`: Choose this for internal testing. Requires a Developer certificate and a Development provisioning profile. 1. Set the **Automatic code signing** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t use automatic code signing. - `api-key` [if you use API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` [if you use Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Save the Workflow, and start a new build. **Configuration YAML** 1. Make sure all the [necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) are available for your build. 1. Open the `bitrise.yml` file of your app. 1. Make sure you have the `xcode-archive` Step in your Workflow. ```yaml my-workflow: steps: - xcode-archive: inputs: ``` 1. Set the `distribution_method` input to the correct value. The available options are: - `app-store`: Choose this if you want to deploy the app to the App Store. Requires a Distribution certificate and an App Store provisioning profile. - `ad-hoc`: Choose this if you want to deploy the app to ad-hoc testers. Requires a Distribution certificate and an Ad Hoc provisioning profile. - `enterprise`: Choose this if you have an Apple Enterprise account and want to use that to distribute your app. - `development`: Choose this for internal testing. Requires a Developer certificate and a Development provisioning profile. ```yaml my-workflow: steps: - xcode-archive: inputs: - distribution_method: development ``` 1. Set the `automatic_code_signing` input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t do automatic code signing. - `api-key` [if you use API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` [if you use Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). ```yaml my-workflow: steps: - xcode-archive: inputs: - automatic_code_signing: api-key - distribution_method: development ``` That’s all. Xcode will automatically select the right signing files based on your project’s Bundle ID and Team ID settings, and the export method you set. ##### Signing an IPA file with a different team’s code signing file You might want to sign the IPA file with a different team’s code signing files. For example: - If you use your company’s code signing files for internal builds, but your client’s code signing files are used for App Store distribution. - If you use Apple ID for automatic code signing and the Apple ID belongs to multiple teams, use The Developer Portal team to use for this export input to specify which team should be used for automatic code signing asset management. To do so: 1. Make sure the right code signing files of the new development team are uploaded to Bitrise. 1. Set the The Developer Portal team to use for this export option as well (in addition to the **Distribution method**). 1. Set the **Distribution method**. ### Testing your React Native app You can use React Native’s built in testing method, called **jest** to perform unit tests. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add the **run npm command** Step to your Workflow. 1. In the **npm command with arguments to run** input field, type `test`. ![Getting_started_with_React_Native_apps.png](/img/_paligo/uuid-f5f86a6c-d609-1970-a451-0de6d5b4edb3.png) For more detailed guides on React Native testing, check out [Testing React Native apps](/bitrise-ci/testing/testing-react-native-apps/running-detox-tests-on-bitrise). #### Viewing React Native test results Bitrise allows you to view and analyze your test results in one convenient place: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). By default, tests run with the **Run npm command** Step won't show up in test reports. However, you can export the results. . The basic process is as follows: 1. Generate a `junit.xml` file during the build. For example, you can use [jest-junit](https://www.npmjs.com/package/jest-junit) to prepare a report. 1. Add the **Export test results to Test Reports** Step to your Workflow. ![Managing_an_app_s_bitrise.png](/img/_paligo/uuid-fd13332e-571f-e706-88ed-a20a29db7aea.png) 1. In the **Path where custom test results reside** input, add the folder in which your `junit.xml` file and other test results are located. 1. In the **Test result search pattern** input, set `*.xml`. 1. In the **The name of the test** input, set the name of the test run. The test results will be under this name. 1. Make sure you have the **Deploy to Bitrise.io** Step in your Workflow. ### Deploying a React Native app You can deploy your React Native app to: - bitrise.io: This allows you download the generated binary, and to share it with others via the public install page. - Online stores: we have integrations for multiple different online stores. In these guides, we'll show you how to publish to Google Play and to Apple's App Store. :::note[CodePush] You can deploy updates to your users' devices with Bitrise CodePush. CodePush is part of [Release Management](/release-management) and it is supported for React Native and Expo apps. For more information about CodePush, check out the official guides: [CodePush](/release-management/codepush/about-codepush). ::: #### Deploying a cross-platform app to bitrise.io The **Deploy to bitrise.io** Step uploads all the artifacts related to your build into the [**Artifacts**](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) tab on your Build’s page. You can share the generated binary file (APK for Android or an IPA file for iOS) with your team members using the public install page. The public install page is a URL you can share with others who can install the generated app binary on their device. You can also notify user groups or individual users that your APK or IPA file has been built. :::important[Publishing to expo.io] The **Deploy to Bitrise.io** Step does not use Expo commands and doesn’t publish to [expo.io](https://docs.expo.dev/workflow/publishing/). This Step publishes artifacts to Bitrise and is not specific to a particular platform. If you need to publish to [expo.io](https://docs.expo.dev/workflow/publishing/), set the **Run expo publish after eject?** input of the **Expo Eject** Step to `yes`. Be aware that in that case you have to provide your username and password for your Expo account to publish to [expo.io.](http://expo.io/) ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Make sure you have the **Deploy to bitrise.io** Step in your Workflow. 1. In the **Notify: User Roles**, add the role so that only those get notified who have been granted with this role. Or fill out the **Notify: Emails** field with email addresses of the users you want to notify. Make sure you set those email addresses as [Secrets](/bitrise-ci/configure-builds/secrets)! These details can be also modified under **Notifications** if you click the **eye** icon next to your generated binary in the **Artifacts** tab. 1. If you want the Step to generate a public install page for you, set the **Enable public page for the App?** input to `true`. #### Deploying the app to App Store Connect Keep in mind that every time you want to push an app to App Store Connect, it must have a unique build and version number: [increment either or both](/bitrise-ci/run-and-analyze-builds/build-numbering-and-app-versioning) before deploying. 1. Make sure you have a working [connection to your Apple Developer account](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Generate an IPA file on your own machine at least once. 1. [Upload all necessary code signing files](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) to Bitrise. To deploy an app to App Store Connect, you need a Distribution type certificate and an App Store type provisioning profile. 1. Make sure the **Xcode Archive & Export for iOS** Step is in your Workflow. 1. Set the **Automatic code signing** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t use automatic code signing, or if you exclusively use Step inputs for Apple service authentication. - `api-key` if you use [API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` if you use [Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Set the **Distribution method** input of the Step to `app-store`. The Step will store the path of the exported .ipa file in the $BITRISE_IPA_PATH Environment Variable. 1. Add the **Deploy to App Store Connect** Step to your Workflow. 1. Fill the required inputs. - Either the app’s Apple ID or its Bundle ID is a required input. One of the two must be provided. - If you set the **Submit for Review** to `yes`, the Step will wait for your submission to be processed on App Store Connect and then submit the given version of the app for review. - The default value of the **Skip App Version Update** input is `No`. Change it only if you incremented the app version number in another way. - If you use an App Store Connect account that is linked to multiple teams, provide either a Team ID or a Team name! 1. Start a build. If all goes well, your app will be submitted to App Store and you can distribute it via Testflight or via the App Store! #### Deploying your Android project to Google Play You can use the **Deploy to Google Play** Step in your Workflow to upload your digitally signed AAB/APK to the Google Play Store. 1. Make sure your Workflow includes the **Android Build** Step and that it runs before the **Android Sign** Step. 1. [Configure code signing](/bitrise-ci/getting-started/quick-start-guides/getting-started-with-react-native-projects#signing-your-android-project) for your app. 1. [Configure Google Play access.](/bitrise-ci/deploying/android-deployment/generating-and-deploying-android-app-bundles#setting-up-google-play-deployment-for-the-first-time) You only need to do this for your very first Google Play deployment of the app. 1. Make sure you have the **Deploy to Google Play** Step after the **Android Sign** Step in your Workflow. 1. Fill out the required input fields as follows: - **Service Account JSON key file path**: This field can accept a remote URL so you have to provide the Env Var which contains your uploaded service account JSON key. For example: `$BITRISEIO_SERVICE_ACCOUNT_JSON_KEY_URL`. - **Package name**: The package name of your Android app. - **Track**: The track where you want to deploy your APK (for example, alpha/beta/rollout/production or any custom track you set). --- ## Getting started with web CI Bitrise is a mobile-focused DevOps platform. However, that doesn't mean you can't build non-mobile projects on Bitrise. We support non-mobile project types with integrations, default Workflows and Pipelines, and dedicated caching solutions. Using Bitrise for web CI allow you to consolidate all projects, mobile and others, on Bitrise. As Bitrise excels in mobile CI/CD, a complex area, consolidating simplifies operations as it's easier to adopt Bitrise for web than a generic CI for mobile. ### Adding a web CI project Add your project the same way as any other: see [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project) for the full walkthrough of the wizard. This section covers what's specific to non-mobile projects. #### How the scanner detects your project type The project scanner checks your repository for the file that identifies each supported language: - Node.js: a `package.json` file. - Ruby: a `Gemfile`. - Python: a `requirements.txt`, `pyproject.toml`, `Pipfile`, or `setup.py` file. - Java or Kotlin: a `gradlew` file for Gradle, or a `pom.xml` file for Maven. For Node.js, Ruby, and Python, it also reads version files such as `.nvmrc`, `.ruby-version`, or `.python-version` (or the `engines`/`requires-python` field in your project's manifest) to pick the right language version for your Workflow. See [Database configuration for Ruby projects](#database-configuration-for-ruby-projects) and [Package manager detection for Python](#package-manager-detection-for-python) for more detail on those two scanners. #### What you can configure During the **CI configuration** stage, the wizard shows a **Project directory** option for each detected project, plus a package manager selector where one applies. If the scanner can't detect your package manager from a lockfile, choose it manually and Bitrise generates a matching configuration. ### Database configuration for Ruby projects When adding a Ruby project, our project scanner detects database gems: `pg`, `mysql2`, `redis`, `mongoid/mongo`, and `sqlite3`. For each detected database gem, the scanner generates the appropriate service container: Postgres, MySQL, Redis, or MongoDB. Each container has the correct image, port mapping, and health checks so the container is fully ready before your tests try to connect. The scanner also parses your `config/database.yml` for relational databases and the `config/mongoid.yml` for MongoDB, to extract connection details. It resolves ERB expressions: if your `database.yml` contains something like `ENV.fetch("DB_HOST", "localhost")`, the scanner picks up both the environment variable name and its default value. These are then set as app-level environment variables in your Bitrise configuration, which means your test Workflow connects to the service containers without any manual environment setup. The scanner prefers the `test` environment section in your `database.yml`, falling back to default if a test block isn't present — which is exactly the lookup order Rails itself uses. ### Managing dependencies Bitrise supports several dependency managers with dedicated Steps that make it easy to handle dependencies. For web CI projects, the most important ones are: - [Run npm command](https://bitrise.io/integrations/steps/npm): Default Workflows for Node.js contain the **npm** Step that runs `npm install`. This command installs all necessary packages defined in your `package.json` file. You can specify flags to configure the installation procedure to suit your requirements. Set up the command in the **The npm command with arguments to run** input. The default input value is **install**. In the configuration YAML file, look for the `command` input: ```yaml - npm: inputs: - command: install -g ``` - [Run yarn command](https://bitrise.io/integrations/steps/yarn): Yarn, like npm, looks for your dependencies in the `package.json` file. The Step allows you to specify the `yarn` command you want to run, as well as any additional arguments. Add your command to **The yarn command to run** input. In your configuration YAML file, the input is called `command`. Leave it empty to install dependencies. ```yaml - yarn: inputs: - command: ``` Specify your yarn command arguments in the **Arguments for running yarn commands** input. In your configuration YAML file, the input is called `args`. You can add multiple arguments separated by a space character. ```yaml - yarn: inputs: - args: "-dev" ``` - [Gradle Runner](https://bitrise.io/integrations/steps/gradle-runner): If your project is built with Gradle, you can use this Step to install your dependencies during the process. To do this, you need: - A Gradle Wrapper. - A Gradle task that is configured correctly. - Dependencies declared in your build script. The Step requires two inputs: the **Gradle task to run** input defines the Gradle task that will run during the build. The **Gradle Wrapper path** input defines the path to the `gradlew` file in your project. In your configuration YAML file, these inputs are called `gradle_task` and `gradlew_path`. ```yaml - gradle-runner: inputs: - gradlew_path: ./cool_project/ - gradle_task: install ``` #### Package manager detection for Python For a Python project, Bitrise creates a dependency management configuration after checking package manager sources in the following order: 1. `uv.lock` for the `uv` package manager. 1. `poetry.lock` for `poetry`. 1. `requirements.txt` for `pip`. If none of these are found, the package manager is left undetected. The user picks one during setup, and a configuration is generated for every choice. ### Running tests All Bitrise projects have a default testing Workflow called `run_tests`. The contents of the Workflow depends on the exact project type. #### Testing with Gradle for Java and Kotlin For Java and Kotlin projects built with Gradle, testing revolves around the `test` Gradle task. Bitrise has a dedicated Step for this: **Run Gradle Tests** which is part of the default Workflow. - The Step needs a [Gradle Wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) in your project. The wrapper must contain at least one correctly configured test task. - Use **Test task** input to set the Gradle task you want to run. By default, the Step executes the `test` task but you can configure any Gradle task for it. - Use the **Additional flags** input to further customize your gradlew command. For example, you can set a flag to run a specific test class. #### Testing with Maven for Java For Java projects built with Maven, your tests are run using a Script Step which runs the [Maven Wrapper's](https://maven.apache.org/tools/wrapper/) test command: `./mvnw test`. Script Steps are fully customizable: you can create whatever Maven configuration you need. You can freely modify the default configuration at any time to suit your purposes. For more information about running tests with Maven, check out [Surefire](https://maven.apache.org/surefire/index.html). #### Linting and testing Node.js projects For Node.js projects, the default `run_tests` Workflow does two things by default — it installs Node.js and runs lint, not a test suite: - Installs Node.js via a **Script** Step: As it's a Script Step, you can fully modify and customize the configuration to suit your own needs. The default solution simply installs Node.js with `asdf`: :::tip Bitrise stacks come with [asdf](https://github.com/asdf-vm/asdf-nodejs) pre-installed to help auto-switch between various software versions `asdf` looks for the Node.js version in these files: `.tool-versions`, `.nvmrc`, `.node-version` so it should work out-of-the-box even if the project uses another Node.js manager. ::: ```bash set -euxo pipefail export ASDF_NODEJS_LEGACY_FILE_DYNAMIC_STRATEGY=latest_installed envman add --key ASDF_NODEJS_LEGACY_FILE_DYNAMIC_STRATEGY --value latest_installed pushd "${NODEJS_PROJECT_DIR:-.}" > /dev/null asdf install nodejs popd > /dev/null ``` - Runs `npm run lint` with [the npm Step](https://bitrise.io/integrations/steps/npm): The lint command will analyze your code for potential errors. The **npm** Step allows you to run tests as well: you can run the `test` command to run the tests defined in the `package.json` file. #### Testing Ruby projects For Ruby projects, we automatically generate a testing Workflow with the right testing command. When adding a Ruby project, the scanner looks for testing frameworks and picks the right testing command based on what it finds: - RSpec: `bundle exec rspec` (optional in each test command, used only if Bundler is detected.) - Minitest in a Rails project: `bundle exec rails test` - Minitest with a Rakefile (non-Rails): `bundle exec rake test` - Minitest without Rails or Rakefile: `bundle exec ruby -Itest test/**/*_test.rb` - No test framework but a Rakefile exists: `bundle exec rake test`. ### Caching Bitrise offers two distinct caching solutions: - [The Bitrise Build Cache](/bitrise-build-cache): If you build your project with Bazel or Gradle, the Bitrise Build Cache caches build and test outputs to minimize how much work is done in subsequent builds. It's compatible with any CI tool and accelerates the build cycle without requiring you to manage a caching infrastructure. - [Key-based caching](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching): Key-based caching works by associating cache archives with a key. A Workflow can restore a cache archive by referring to the key; at the end of the Workflow, the build files can be saved into the cache archive that the key indicates. This overwrites the cache archive. #### Bitrise Build Cache Adding a new connection to the Bitrise Build Cache consists of: - Selecting a CI provider: you can use either Bitrise or another CI provider. - Selecting a build tool: currently, Bazel, Gradle, and Xcode are supported. - If you use Bitrise as your CI provider, selecting a Bitrise project. - If you use a different CI provider, adding [a personal access token](/bitrise-platform/accounts/personal-access-tokens#creating-a-personal-access-token) to allow the Bitrise Build Cache access to your CI. - Adding the cache activation scripts to your CI process. On Bitrise, we have dedicated [Steps](/bitrise-ci/workflows-and-pipelines/steps/steps-overview) for this. #### Key-based caching To use key-based caching, you have two main options: - Using our dedicated caching Steps. These require no configuration as they automatically set up the cache keys needed for your dependencies. Dedicated Steps include Steps for caching npm, Yarn, and Gradle dependencies: [Dedicated caching Steps for dependency managers](/bitrise-ci/dependencies-and-caching/key-based-caching/dedicated-caching-steps-for-dependency-managers). - Using **Script** Steps to configure keys for your cache archives. This gives you full control over your caching setup: [Using key-based caching](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching). ### Docker container support You can use Docker containers in your Bitrise Workflows and Pipelines. Container support also enables background services. Running builds in a container grants full control over your build environment, and you don't need to install dependencies during a build. #### Building a Docker image To use containers, you need a Docker image. You can build and push your own Docker image using the [Docker Build & Push](https://bitrise.io/integrations/steps/docker-build-push) Step. The Step requires a list of image tags to be applied to the built image. You can also specify: - A build context. - A Dockerfile path. The **Docker Build & Push** Step offers built-in support for [key-based caching](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching). It means the Step automatically caches your built Docker image, using preset cache keys. For more information, check out [Building your own Docker image](/bitrise-platform/infrastructure/docker-containers-on-bitrise/building-your-own-docker-image). #### Using containers To use containers in a build, you need to: - Define your containers. It requires a container ID and the name and version of the Docker image. - Refer to the container by its ID within a Workflow or Pipeline. Different parts of the same Workflow can run in different containers. You can also define service containers that allow running Docker containers as services for advanced integration testing. For details, check out [About Docker containers on Bitrise](/bitrise-platform/infrastructure/docker-containers-on-bitrise/about-docker-containers-on-bitrise). ### Deploying Deploy your web CI project in one of three ways: - The **[Deploy to Bitrise.io](https://bitrise.io/integrations/steps/deploy-to-bitrise-io)** Step: It deploys your files on Bitrise. Set the path to the files you want to deploy in the **Deploy directory or file path** input of the Step. After a successful build, you can find them on the **Artifacts** tab of [the build page](/bitrise-ci/run-and-analyze-builds/finding-a-specific-build). You can download the files from here. For more information, check out [Build artifacts online](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online). - A customized [Script Step](https://bitrise.io/integrations/steps/script): Deploy your project using your own custom script. The Step supports all the popular scripting languages. The Step also allows you to create and export your own Environment Variables which can be accessed by subsequent Steps. With Script Steps, everything is fully in your control. - A dedicated deploy Step: These Steps deploy your web project to a specific service. For example, the [Amazon S3 Bucket Sync Step](https://bitrise.io/integrations/steps/amazon-s3-upload) uploads the contents of a local folder to an Amazon S3 bucket; the [Heroku Deploy](https://bitrise.io/integrations/steps/heroku-deploy) Step deploys your app to Heroku with the Heroku Toolbelt. We'll be actively adding new deployment Steps in the future to cover as many use cases as possible. --- ## The Bitrise dashboard Your first stop when logging in to Bitrise is the dashboard. It allows you to navigate the Bitrise products across your current workspace. You can navigate to: - Your projects. - Your [CI builds](/bitrise-ci/run-and-analyze-builds/finding-a-specific-build) on your workspace's CI dashboard. - The [Bitrise Build Cache](/bitrise-build-cache). - [Release Management](/release-management). ![dashboard-overview.png](/img/_paligo/uuid-c88d4641-9945-2d84-dd14-ef30fdd68fc4.png) You can also find [Insights](/insights) data for the workspace. ### Checking project details Your projects are listed on the left side of the dashboard. To see more data about them, click the downward arrow. The details display basic information about all Bitrise products associated with the project: - The last Bitrise CI build and its status on the project's default branch. The dashboard doesn't show build information from other branches. - The last time the Build Cache was used. - The number of connected apps the project has in Release Management. ![project-card-dashboard.png](/img/_paligo/uuid-2c2a82f9-5bea-aa62-cd49-339aa061c265.png) You can access each of these products from the details section of the project card. ### Adding a new project from the dashboard On the top right corner of the dashboard, you can find the **New project** button. You can use this to [add a new project with a CI configuration](/bitrise-ci/getting-started/adding-a-new-project). :::note[Projects without CI] You can create projects without a CI configuration: add a new app to Release Management and select the option to create a new project. ::: Any CI project added this way will also be visible on the dashboard. You can also access [Release Management](/release-management) to add an app and link it to the project. ### Workspace insights In the **Insights for workspace** section, you can see some basic aggregated data for your workspace's projects: - **Successful build time**: The average Bitrise CI build time for successful builds across the workspace's projects. - **Build failure rate**: The percentage of failed Bitrise CI builds across the workspace's projects. - **Cache hit rate (P50)**: The percentage of data requests that were successfully served by the Bitrise Build Cache. - **Command error rate**: The percentage of failed commands. ![workspace-insights.png](/img/_paligo/uuid-b15d9482-748d-bb6a-1aaa-c1153ed8392b.png) Explore [Insights](/insights) to see more metrics, providing data-driven visibility. --- ## Unity on Bitrise Bitrise offers full support for using [Unity](https://unity.com/) software on our build machines: convenient license management, up to 40 GB of disk space, and a mobile-focused build environment that allows users to easily create both iOS- and Android versions of their Unity projects. To be able to build a Unity app on Bitrise, you need to: - [Add your project as a Bitrise app](/bitrise-ci/getting-started/unity-on-bitrise#adding-a-unity-project-as-a-bitrise-app). - [Download and install Unity on the virtual machine running your build](/bitrise-ci/getting-started/unity-on-bitrise#downloading-and-installing-unity-software-on-bitrise). - [Add your licenses to Bitrise and activate it during the build](/bitrise-ci/getting-started/unity-on-bitrise#setting-up-unity-licenses-on-bitrise). - [Build your project](/bitrise-ci/getting-started/unity-on-bitrise#running-a-build-using-unity-software). ### Adding a Unity project as a Bitrise app Add your Unity project [as a new app](/bitrise-ci/getting-started/adding-a-new-project). The project scanner doesn't support Unity software so it won't detect your project as a Unity project so you can skip automatic configuration and register the project as **Other**. We recommend using an Xcode stack: these contain the most important Android tools, too. You can build both iOS and Android versions of your Unity apps on our Xcode stacks. ### Downloading and installing Unity software on Bitrise To be able to build a Unity project on Bitrise, you'll need to install Unity software on the virtual machine at the start of your build. This is the standard practice of running Unity software in the cloud and it only takes a few minutes. :::note[Xcode stacks] Make sure you use an Xcode stack to run Unity builds: the instructions on this page are valid for installing Unity on our Xcode stacks. ::: 1. Look up the Unity software version you want to download on the [Unity download archive](https://unity.com/releases/editor/archive). 1. Find the Unity Editor of the version you need, and copy its download link. The link will look something like this: https://download.unity3d.com/download_unity/b16b3b16c7a0/MacEditorInstallerArm64/Unity.pkg. 1. You will also need the download links for the two platform support packages (iOS and Android). You can find these on the [LTS Releases page](https://unity.com/releases/editor/qa/lts-releases). 1. Add a **Script** Step to the start of your Workflow. 1. In the **Content** input, add the curl commands to download the necessary Unity packages. For example: ```bash #workaround for .NET issue https://github.com/dotnet/runtime/issues/64103 export COMPlus_ReadyToRun=0 envman add --key COMPlus_ReadyToRun --value 0 #download unity pkg for Apple Silicon curl -o ./unity.pkg http://download.unity3d.com/download_unity/8af3c3e441b1/MacEditorInstallerArm64/Unity-2021.3.12f1.pkg #download android support platform curl -o ./android.pkg http://download.unity3d.com/download_unity/8af3c3e441b1/MacEditorTargetInstaller/UnitySetup-Android-Support-for-Editor-2021.3.12f1.pkg #download iOS support platform curl -o ./ios.pkg http://download.unity3d.com/download_unity/8af3c3e441b1/MacEditorTargetInstaller/UnitySetup-iOS-Support-for-Editor-2021.3.12f1.pkg ``` Replace the download links with the links for the versions you need. 1. Optionally, you can install a Unity software version for Apple silicon that supports [Rosetta](https://developer.apple.com/documentation/apple-silicon/about-the-rosetta-translation-environment): ```bash #download unity pkg for Apple Silicon with Rosetta support curl -o ./unity.pkg http://download.unity3d.com/download_unity/8af3c3e441b1/MacEditorInstaller/Unity-2021.3.12f1.pkg ``` If successful, you should be able to find Unity software at `/Applications/Unity/Unity.app/Contents/MacOS/Unity`. ### Setting up Unity licenses on Bitrise In alignment with Unity's policy, only paid plans are supporting command line… which means you need to add Unity license pools on Bitrise to be able to build a Unity project. Our build machines will be able to find the licence for your Workflow but you need to activate it by providing your Unity email address and password. :::important[Multiple licenses required] To run multiple builds concurrently, you need separate license keys for each build. For example, if you want to run three builds of a Unity app at the same time, you need at least three separate Unity licenses. ::: #### Adding Unity license pools 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Integrations**. 1. Click the **License pools** card. 1. Click **Add license pool**. ![license_pools.png](/img/_paligo/uuid-260b6d8c-c6ae-d008-a72a-8b0552a1e348.png) 1. Fill out the fields. You must set: - A name: that's how you can find your pool in the Workflow Editor. - An [Environment Variable](/bitrise-ci/configure-builds/environment-variables) key: this is how you can use the license in a build script. - The license keys themselves. A license key can't have a space or any special character other than underscore in it. 1. Click **Save**. 1. Open the Workflow Editor for the app you need and go to the **Licenses** tab. 1. Select a license pool for each Workflow where you need them. ![license-wfe.png](/img/_paligo/uuid-bfc830a8-c22d-2fc3-1dab-16fba07460fa.png) #### Activating a Unity license When trying to run a build, you need to activate your Unity license first. This requires providing your Unity email address and password. We recommend using [Secrets](/bitrise-ci/configure-builds/secrets) to store these. :::note[Deactivating a license] Once your build is finished, we strongly recommend deactivating the Unity license so you can reuse it: ```bash /Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchmode -logFile -returnlicense ``` ::: 1. Create two Secrets to store your email address and password. We recommend using the following keys: - UNITY_EMAIL, with your email address as the value. - UNITY_PW, with your Unity password as a value. 1. Add the following code to a **Script** Step that comes after [the Step installing Unity software](/bitrise-ci/getting-started/unity-on-bitrise#downloading-and-installing-unity-software-on-bitrise) in the Workflow: ```bash /Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchmode -serial "$UNITY_SERIAL" -username "$UNITY_EMAIL" -password "$UNITY_PW" -logfile ``` :::tip[Use a Utility Workflow] A best practice is to create a [utility Workflow](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#utility-workflows) that contains this Step, and [run it before each Workflow](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#chaining-workflows-together) that requires Unity. ::: ### Running a build using Unity software Once everything is set up, you can run a build using Unity software on Bitrise. You can build both an Android and an iOS version of your app, even in the same Workflow. To run a build using Unity software on Bitrise: 1. [Add Unity license pools to Bitrise](/bitrise-ci/getting-started/unity-on-bitrise#setting-up-unity-licenses-on-bitrise). 1. [Activate your Unity license in the build](/bitrise-ci/getting-started/unity-on-bitrise#setting-up-unity-licenses-on-bitrise). 1. [Download and install Unity on the virtual machine](/bitrise-ci/getting-started/unity-on-bitrise#downloading-and-installing-unity-software-on-bitrise). 1. To build the Android version of your app, add a **Script** Step and in the **Content** input, add the following: ```bash /Applications/Unity/Unity.app/Contents/MacOS/Unity -nographics -quit -batchmode -logFile -projectPath "$BITRISE_SOURCE_DIR" -executeMethod BitriseUnity.Build -androidSdkPath "$ANDROID_HOME" -buildOutput "$BITRISE_DEPLOY_DIR/mygame.apk" -buildPlatform android ``` 1. To create an Xcode project for the iOS version of your app, add the following to the **Script** Step: ```bash /Applications/Unity/Unity.app/Contents/MacOS/Unity -nographics -quit -batchmode -logFile -projectPath "$BITRISE_SOURCE_DIR" -executeMethod BitriseUnity.Build -buildOutput "$BITRISE_SOURCE_DIR/xcodebuild" -buildPlatform ios ``` 1. [Create and export an IPA from the Xcode project](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). 1. When you are done, deactivate your license: ```bash /Applications/Unity/Unity.app/Contents/MacOS/Unity -quit -batchmode -logFile -returnlicense ``` --- ## Bitrise CI --- ## Available environment variables [Environment Variables](/bitrise-ci/configure-builds/environment-variables) (Env Vars) consist of a key and a value. They can also include optional attributes. They can be defined on the level of apps, Workflows or Steps. You can set your own Env Vars but there is a selection of Env Vars that are exposed automatically by either the Bitrise CLI or [bitrise.io](https://www.bitrise.io). - [Env Vars exposed by the Bitrise CLI](#env-vars-exposed-by-the-bitrise-cli) are available everywhere, even if you run the build on your own computer. - [Env Vars exposed by bitrise.io](#env-vars-exposed-by-bitriseio) are available for builds running on [bitrise.io](https://www.bitrise.io) virtual machines. - [Pipeline Env Vars exposed by bitrise.io](#pipeline-env-vars-exposed-by-bitriseio) are only available for Pipeline builds running on [bitrise.io](https://www.bitrise.io) virtual machines. In addition, plenty of Bitrise Steps export output variables. These variables are available to subsequent Steps during a build. You can find them in the Step configuration of each Step: - In the Workflow Editor, you can check them in the **Output properties** section of a Step. - In the `step.yml` of a Step, you can find them under `outputs`. Release Management also passes a number of Env Vars to Bitrise builds: [Release Management Env Vars](#release-management-env-vars). Environment Variables have a set availability order. This is the order in which they are made available as a build progresses: [Availability order of Environment Variables](/bitrise-ci/configure-builds/environment-variables#availability-order-of-environment-variables). :::tip[Step outputs exposed as Env Vars] Steps can also expose Step outputs as Env Vars. For example, a Step that builds a binary can expose that binary to other Steps as an Env Var. As basically any Bitrise Step can expose outputs this way, we won't list them all but you can find all Environment Variables related to the git cloning process: [Git clone Env Vars](#git-clone-env-vars). ::: ### Env Vars exposed by the Bitrise CLI {#env-vars-exposed-by-the-bitrise-cli} | Env Var | Description | | --- | --- | | $BITRISE_TRIGGERED_WORKFLOW_ID | The ID of the Workflow that was triggered. This Env Var is exposed regardless of whether the Workflow was triggered manually or automatically. | | $BITRISE_TRIGGERED_WORKFLOW_TITLE | The title of the Workflow that was triggered. This Env Var is exposed regardless of whether the Workflow was triggered manually or automatically. | | $BITRISE_BUILD_STATUS | The current status of the build. The available options are: - 0: Successful. - 1: Failed. A successful current status means that none of the previous Steps in the build failed. | | $BITRISE_SOURCE_DIR | Path to the base working directory. By default, it’s the directory where Bitrise runs, unless you provide a different value. This can be overwritten during the build, which will change the working directory for subsequent Steps in the build. | | $BITRISE_DEPLOY_DIR | Path to the directory that stores artifacts and files for deployment. It’s a temporary directory created by the Bitrise CLI by default, and can be overwritten before starting the Bitrise CLI. The [**Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step looks for your build artifacts - such as an IPA or APK of the app -, test results, and other files in this directory. | | $BITRISE_TEST_DEPLOY_DIR | Root directory for all test results created by the Bitrise CLI. Test results placed in this directory can be viewed alongside all other test results: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). | | $BITRISE_TEST_RESULT_DIR | Each Step has its own value of this variable. It provides a unique subdirectory, under $BITRISE_TEST_DEPLOY_DIR for each Step to save its test results. | | $BITRISE_FAILED_STEP_TITLE | The title of the Step that first fails in a build. In other words, the Step that sets the build status to **Failed**. | | $BITRISE_FAILED_STEP_ERROR_MESSAGE | The error message of the Step that first fails in a build. | | $CI | Indicates whether the Bitrise CLI is running in Continuous Integration mode. The possible values are: - `true` - `false` | | $PR | Indicates whether the Bitrise CLI is running in PR (Pull Request) mode. Running in Pull Request mode means that Bitrise builds your code in the state as if the Pull Request was already merged. The possible values are: - `true` - `false` | ### Env Vars exposed by bitrise.io {#env-vars-exposed-by-bitriseio} | Env Var | Description | | --- | --- | | $BITRISE_BUILD_NUMBER | Build number of the build on [bitrise.io](https://www.bitrise.io). | | $BITRISE_APP_TITLE | The title of your project on [bitrise.io](https://www.bitrise.io). You can change it any time on the **Project settings** page of the project. | | $BITRISE_APP_URL | The URL or your project on [bitrise.io](https://www.bitrise.io). This is not the same as the Git repository URL! A project URL has the following format: `app.bitrise.io/app/APP-SLUG` For example: https://app.bitrise.io/app/31e481ce08e0xfd9. | | $BITRISE_APP_SLUG | The slug that uniquely identifies your project on [bitrise.io](https://www.bitrise.io). It’s part of the project URL, too. | | $BITRISE_BUILD_URL | The URL of the build on [bitrise.io](https://www.bitrise.io). | | $BITRISE_BUILD_SLUG | The slug that uniquely identifies a build on [bitrise.io](https://www.bitrise.io). It’s part of the build URL, too. For example, let’s take a look at this build URL: https://app.bitrise.io/app/31e481ce08e0xfd9/build/d75abbebxfc9ca4e. The build slug is `d75abbebxfc9ca4e` in this example. | | $BITRISE_BUILD_TRIGGER_TIMESTAMP | The date and time when the build was triggered. | | $GIT_REPOSITORY_URL | The URL of the Git repository that hosts your project. This can be changed in the **Repository** section of the **Project settings** page. It can be in either SSH or HTTPS format. | | $BITRISE_GIT_BRANCH | The git branch that is built by Bitrise. For example, `main`. | | $BITRISEIO_GIT_BRANCH_DEST | Used only with builds triggered by pull requests: the destination/target branch of the pull request that triggered the build. For example, a pull request wants to merge the content of a branch into the branch `main`. In this case, this Env Var’s value is `main`. For a pull request in a [GitHub stack](https://docs.github.com/en/pull-requests/get-started/about-stacked-prs), the value is the base branch of the stack rather than the branch the pull request targets directly. | | $BITRISE_GIT_TAG | If a build is triggered by a Git Tag, this Env Var stores the tag used. | | $BITRISE_GIT_COMMIT | The commit hash of the Git commit that triggered the build, when applicable. | | $BITRISE_GIT_MESSAGE | The commit message, pull request title, or the message you specified if you triggered the build manually. | | $BITRISEIO_GIT_REPOSITORY_OWNER | The owner of the Git repository of the project. | | $BITRISEIO_GIT_REPOSITORY_SLUG | The slug of the Git repository of the project. | | $BITRISE_PULL_REQUEST | The ID of the pull request that triggered a build. | | $BITRISEIO_PULL_REQUEST_REPOSITORY_URL | The URL of the repository from where the pull request that triggered a build has been sent. | | $BITRISEIO_PULL_REQUEST_MERGE_BRANCH | The pre-merge branch - if the Git hosting provider supports and provides the pre-merged state of a pull request on a special merge branch. | | $BITRISEIO_PULL_REQUEST_HEAD_BRANCH | The pull request head branch, if the Git hosting provider system supports and provides this. This special git ref should point to the source of the pull request. | | $GITHUB_PR_IS_DRAFT | For projects hosted on GitHub only: it is set to `true` if the build is triggered by [a draft pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests). | | $BITRISE_PROVISION_URL | The URL of the Apple provisioning profiles uploaded to [bitrise.io](https://www.bitrise.io). If there is more than one provisioning profile uploaded for your project, a pipe character (`|`) separates the URLs in the list. This is only relevant for iOS projects and for cross-platform projects with iOS versions. | | $BITRISE_CERTIFICATE_URL | The URL of the Apple certificates uploaded to [bitrise.io](https://www.bitrise.io). If there is more than one certificate uploaded for your project, a pipe character (`|`) separates the URLs in the list. This is only relevant for iOS projects and for cross-platform projects with iOS versions. | | $BITRISE_CERTIFICATE_PASSPHRASE | The passphrase you set for the uploaded Apple certificates on the project’s **Code signing** tab. If there is more than one certificate with a passphrase, a pipe character (`|`) separates the phrases in the list. This is only relevant for iOS projects and for cross-platform projects with iOS versions. | | $BITRISE_IO | Indicates that the build is running in a bitrise.io environment. Value is set to true by Bitrise when it starts a build. | | `$BITRISE_TRIGGER_BY` | Identifies the entity that triggered the build. The value can be: - The Git user's name when the build is [triggered by a Git provider](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers). - The Bitrise user's name if the build is triggered manually from the Bitrise web UI. - The value specified in the `triggered_by` build parameter if the build is triggered any other way (such as [scheduled builds](/bitrise-ci/run-and-analyze-builds/starting-builds/scheduling-builds) or builds triggered by the [API](/bitrise-ci/api/api-overview)). | | `$BITRISE_TRIGGER_METHOD` | The method by which the build was triggered. - `schedule`: When the build is triggered by a scheduler. - `webhook`: When the build is triggered automatically by a webhook at a Git provider. - `manual`: When the build is triggered by any other trigger, including the API. | | `$BITRISE_GIT_PULL_REQUEST_COMMENT` | The comment message and its corresponding ID from a pull request (or merge request in the case of GitLab). Only available when the build is triggered by a PR comment: the build trigger must have a `pr_comment` value. | | `$BITRISE_GIT_PULL_REQUEST_COMMENT_ID` | The comment ID from a pull request. Only available when the build is triggered by a PR comment. | | `$BITRISE_GIT_PULL_REQUEST_LABELS` | A multiline list of new labels added to the pull request along with existing labels. Only available when the build is triggered by adding a label to a pull request or by a PR event with existing labels. Only supported for GitHub and GitLab. | | `$BITRISE_GIT_CHANGED_FILES` | Lists file paths changed by a code push or pull request. Contains max 3000 files per event. It's available when: - A push event triggers a build. Only supported for GitHub and GitLab. - A PR event triggers a build and the trigger has a `changed_files` or `commit_message` condition. Supported for all three main Git providers. Note: this env var can become really large in some builds. If you build custom scripts that parse this env var, please see the env var size limitations section below. | | `$BITRISE_GIT_COMMIT_MESSAGES` | The commit messages of a code push or pull request. Contains max the first 2048 commits, and at most 1000 characters in each message. It's available when: - A push event triggers the build. Only supported for GitHub and GitLab. - A PR event triggers a build and the trigger has a `commit_message` condition. Supported for all three main Git providers. Note: this env var can become really large in some builds. If you build custom scripts that parse this env var, please see the env var size limitations section below. | | $BITRISE_WORKSPACE_ID | The [workspace slug](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs) of the workspace that owns the project. | :::note[GitHub stacked pull requests and diffs] For a pull request in a GitHub stack, `$BITRISEIO_GIT_BRANCH_DEST` holds the base branch of the stack. A script that diffs against it — `git diff origin/$BITRISEIO_GIT_BRANCH_DEST...HEAD`, for example — returns the changes of the whole stack up to and including this pull request, not the changes of this pull request alone. ::: :::warning[Env Var size limitations] Some of the above environment variables can become really large in some builds (for example, if a git commit has a really long commit message or a pull request modifies thousands of files). If the total size of all env vars would hit OS limits, Bitrise removes some env vars from the runtime environment and writes the full value to a file on disk. If you have custom scripts that rely on env vars that could grow large in some builds, you should read the value from this env file instead. The env var is located at $BITRISEIO_ENVFILE_PATH on both macOS and Linux stacks. It has the following format: ```yaml envs: # Every env var from the build trigger and git event. BITRISE_GIT_CHANGED_FILES: ... BITRISE_GIT_COMMIT_MESSAGES: ... CI: true PR: true [...] # List of env var KEYS that had to be erased. You should read the original value from the map above, this is just for debugging. erased_envs: - BITRISE_GIT_CHANGED_FILES ``` ::: ### Pipeline Env Vars exposed by bitrise.io {#pipeline-env-vars-exposed-by-bitriseio} | Env Var | Description | | --- | --- | | $BITRISEIO_PIPELINE_ID | The ID of the running Pipeline build. This Env Var is exposed regardless of whether the Pipeline was triggered manually or automatically. | | $BITRISEIO_PIPELINE_TITLE | The name of the running Pipeline build. This Env Var is exposed regardless of whether the Pipeline was triggered manually or automatically. | | $BITRISEIO_FINISHED_STAGES | The status of previously finished Stages and Workflows in a build. Please note that the value of this Env Var may change in the future! | | $BITRISEIO_PIPELINE_BUILD_STATUS | The current status of the Pipeline build. The value of this Env Var can be: `succeeded`, `succeeded_with_abort`, `failed`, and `aborted`. While the Pipeline is running, the Env Var's status is based on the previously finished Stages. | | $BITRISEIO_PIPELINE_BUILD_URL | The URL of the Pipeline build. | ### Release Management Env Vars {#release-management-env-vars} | Env Var | Description | | --- | --- | | $RM_RELEASE_ID | The unique identifier of your release on bitrise.io. It’s part of the release URLs, too. | | $RM_RELEASE_VERSION | The release name (for Google Play releases) or version (for App Store releases) in Release Management. | | $RM_RELEASE_CANDIDATE_VERSION | The version of the binary (APK/AAB or IPA file) generated by the release candidate build. | | $RM_RELEASE_CANDIDATE_DOWNLOAD_URL | The download URL of the binary (APK/AAB or IPA file) generated by the release candidate build. | | $RM_RELEASE_CANDIDATE_SLUG | Unique identifier of the binary (APK/AAB or IPA file) generated by the release candidate build. | | $RM_RELEASE_CANDIDATE_BUILD_SLUG | The build slug of the build that was selected as a release candidate for the release. | | $RM_CONNECTED_APP_ID | The unique identifier of your connected app on bitrise.io. | | $RM_PROJECT_ID | The unique identifier of your project on bitrise.io. It’s part of the project URL, too. | | $RM_WORKSPACE_ID | The unique identifier of your workspace on bitrise.io. | | $RM_EVENT_ID | Identifies the trigger which starts the Bitrise CI workflows. See the list of events and their IDs on the [Configuring release automation](/release-management/releases/configuring-a-release/release-automation#automation-events) page. | ### Git clone Env Vars {#git-clone-env-vars} | Env Var | Description | | --- | --- | | $GIT_CLONE_COMMIT_HASH | The hash of the commit that the build uses (the cloned commit). | | $GIT_CLONE_COMMIT_MESSAGE_SUBJECT | The subject of the commit message of the cloned commit. | | $GIT_CLONE_COMMIT_MESSAGE_BODY | The body (content) of the commit message of the cloned commit. | | $GIT_CLONE_COMMIT_COUNT | The commit count of the cloned commit. This Env Var is influenced by the `clone_depth` Step input. For more information, check out the [Git Clone Step description](https://github.com/bitrise-steplib/steps-git-clone). | | $GIT_CLONE_COMMIT_AUTHOR_NAME | The name of the author of the cloned commit. | | $GIT_CLONE_COMMIT_AUTHOR_EMAIL | The email of the author of the cloned commit. | | $GIT_CLONE_COMMIT_COMMITTER_NAME | The name of the committer of the cloned commit. | | $GIT_CLONE_COMMIT_COMMITTER_EMAIL | The email of the committer of the cloned commit. | --- ## Bitrise tools Here is a list of our open source tools maintained by the Bitrise team. | Name | Type | Description | Link | | --- | --- | --- | --- | | **Bitrise CLI** | CLI | The Bitrise CLI which is used on [bitrise.io](https://www.bitrise.io) to run builds. You can use it to run builds locally. | [https://github.com/bitrise-io/bitrise](https://github.com/bitrise-io/bitrise) | | **stepman** | CLI tool | The Step Collection Manager used for managing the Step Library. | [https://github.com/bitrise-io/stepman](https://github.com/bitrise-io/stepman) | | **envman** | CLI tool | The Environment Variable Manager used by the Bitrise CLI to isolate and manage [Environment Variables](/bitrise-ci/configure-builds/environment-variables) during the build. It can also be used independently of the Bitrise CLI. | [https://github.com/bitrise-io/envman](https://github.com/bitrise-io/envman) | | **init** | CLI core plugin | Use this plugin so that our project scanner can detect the type of your project locally and generate a Bitrise configuration. | [https://github.com/bitrise-io/bitrise-plugins-init.git](https://github.com/bitrise-io/bitrise-plugins-init.git) | | **step** | CLI core plugin | Use this plugin to list, retrieve Step information or create Steps. | [https://github.com/bitrise-io/bitrise-plugins-step](https://github.com/bitrise-io/bitrise-plugins-step) | | **workflow-editor** | CLI core plugin | Use this plugin to configure your builds’ `bitrise.yml` config locally with the offline Workflow Editor. | [https://github.com/bitrise-io/bitrise-workflow-editor.git](https://github.com/bitrise-io/bitrise-workflow-editor.git) | | **bitrise-plugin-io** | CLI core plugin | Use this plugin to manage your apps on [bitrise.io](https://www.bitrise.io) right from the Terminal / command line. | [https://github.com/bitrise-io/bitrise-plugins-io](https://github.com/bitrise-io/bitrise-plugins-io) | | **bitrise webhooks** | Webhook processor | This [Bitrise Webhooks processor](https://github.com/bitrise-io/bitrise-webhooks) transforms various incoming webhooks (for example, from GitHub, Bitbucket, or Slack) to [bitrise.io](https://www.bitrise.io)’s Build Trigger API format, and calls it to start a build. | [https://github.com/bitrise-io/bitrise-webhooks](https://github.com/bitrise-io/bitrise-webhooks) | --- ## Configuration YAML reference This document lists the configuration options for the configuration YAML file where you define your CI/CD configuration on Bitrise. - Check out our overview for the basic principles of the configuration YAML file: [Configuration YAML overview](/bitrise-ci/configure-builds/configuration-yaml/configuration-yaml-overview). - Read more about where to store the configuration YAML file: [Managing a project's configuration YAML file](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml). - Create advanced modular configurations: [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration). ### Project level properties #### `format_version` **Required**: A configuration YAML file is invalid without it. The version of the Bitrise configuration format. The Bitrise CLI checks it to ensure compatibility between the configuration file and the CLI version. This is relevant for locally run builds: on the Bitrise website, the CLI is always up to date, so the `format_version` property doesn't have an effect on builds triggered. **Example of `format_version`** ```yaml format_version: '25' ``` #### `default_step_lib_source` The default Step library for the Steps used in your configuration. Bitrise uses this source if no specific source is provided for a given Step. The default value is https://github.com/bitrise-io/bitrise-steplib.git. You can use your own fork of this repository as a Step source, or you can refer to Steps by including their exact source repository: [Step reference/ID format](/bitrise-ci/references/steps-reference/step-reference-id-format). **Example of `default_step_lib_source`** ```yaml default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git ``` #### `project_type` The type of your Bitrise project, such as `ios`, `android`, `flutter`, and so on. The project type can be modified at any point but after the initial setup, it has no relevance. **Example of `project_type`** ```yaml project_type: flutter ``` #### `title` The title of the Bitrise configuration. **Example of `title`** ```yaml title: My Bitrise project ``` #### `summary` A short summary of the Bitrise configuration. **Example of `summary`** ```yaml summary: This project runs tests for my app. ``` #### `description` A detailed description of the Bitrise configuration. **Example of `description`** ```yaml description: This project runs unit and UI tests when a pull request is opened to the dev branch. ``` #### `services` Docker container definitions used by Steps as service containers on Linux hosts. :::note[Linux only] This is only supported on Linux stacks: the property doesn't work on macOS stacks! ::: One or more service can be configured for a group of Steps, allowing running Docker containers as services for advanced integration testing. These are tied to the lifecycle of a `with` group and will run alongside it in the background. When all Steps within the groups finish, they are cleaned up. You need to define: - The ID of the service which is used to refer to the service in a with group. - The image name of the service. - The image version of the service. Read more: [Service containers](/bitrise-platform/infrastructure/docker-containers-on-bitrise/service-containers). **Example of `services`** ```yaml services: postgres: image: postgres:16 envs: - POSTGRES_USER: postgres - POSTGRES_DB: bitrise ports: - 5432:5432 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 redis: image: redis:7 ports: - 6379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 ``` #### `containers` Docker container definitions used by Steps as execution containers. Docker containers can be defined for any Bitrise project in the configuration YAML file. You define the container in the top level of the configuration file and then refer to it in a `with` group in the Workflow configuration. You need to define: - The ID of the containers. It will be used to reference this container. - The name of the Docker image you want to use. - The version of the image. `containers reference`: [Docker container properties](/bitrise-ci/references/configuration-yaml-reference#docker-container-properties). Read more: [Execution containers](/bitrise-platform/infrastructure/docker-containers-on-bitrise/execution-containers). **Example of `containers`** ```yaml containers: node-21: image: node:21.6 ``` #### `app` This property contains project-level configuration information, such as [Environment Variables](/bitrise-ci/configure-builds/environment-variables). Meta information such as the build stack doesn't belong here but to the `meta` property. **Example of `app`** ```yaml app: envs: - TEST: '' opts: is_expand: false ``` #### `meta` Stores project metadata key-value pairs related to the Bitrise configuration. Most importantly, it defines the default stack and the build machine type for the project. Read more: [Setting the stack in the bitrise.yml file](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds#setting-the-stack-in-the-configuration-yaml). **Example of `meta`** ```yaml meta: bitrise.io: stack: linux-docker-android-22.04 machine_type_id: g2.linux.2medium ``` #### `trigger_map` Defines the build triggers on a project level. This is the legacy method of configuring triggers: we recommend using target-based triggers defined within a Pipeline or a Workflow instead. Read more: [Legacy project-based triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/legacy-project-based-triggers). **Example of `trigger_map`** ```yaml trigger_map: - pull_request_source_branch: "*" type: pull_request workflow: primary ``` #### `pipelines` Define Pipelines in your project's configuration. Pipelines can be used to organize the entire CI/CD process and to set up advanced configurations with multiple different tasks running parallel and/or sequentially. `pipelines` reference: [Pipeline level properties](/bitrise-ci/references/configuration-yaml-reference#pipeline-level-properties). Read more: [About Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/about-pipelines). **Example of `pipelines`** ```yaml pipelines: test: title: Test Pipeline summary: This Pipeline runs unit tests. workflows: primary: {} ``` #### `workflows` The Workflows included in your configuration. A Workflow is a collection of Steps: reusable, configurable units of work. Steps are executed sequentially within a Workflow. `workflows` reference: [Workflow level properties](/bitrise-ci/references/configuration-yaml-reference#workflow-level-properties). **Example of `workflows`** ```yaml workflows: primary: steps: - script: {} ``` #### `step_bundles` Step bundles allow you to group multiple Steps into a single unit. With Step bundles, you can reuse Steps and sequences of Steps. You can insert Step bundles into any Workflow. Unlike utility Workflows and Workflow chaining, Step Bundles can be placed anywhere in a Workflow. `step_bundles` reference: [Step bundle properties](/bitrise-ci/references/configuration-yaml-reference#step-bundle-properties). Read more: [Step bundles](/bitrise-ci/workflows-and-pipelines/steps/step-bundles). **Example of `step_bundles`** ```yaml step_bundles: primary: steps: - git-clone: {} - restore-cache: {} ``` #### `include` The `include` property allows you to use other configuration YAML files in your Bitrise configuration, to break down large, complex YAML files into smaller, modular components. A modular YAML configuration includes: - A `bitrise.yml` file in the root of your repository. - Other YAML files in the same or a different repository. To include a file from a different repository, the repository must belong to the same Git account or organization as the primary repository. - One or more `include` keywords in the bitrise.yml file. These point to other YAML files and bring their configuration into the main project configuration. Read more: [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration). **Example of `include`** ```yaml include: - path: path/to/config_module.yml ``` #### `tools` Tool version to set up. The version syntax supports: - Exact versions: for example, `'1.2.3'`. - Partial matches to the latest release: for example, `'22:latest'`. - Partial matches to installed versions: for example, `'1.2:installed'`. - Special aliases `'latest'` and `'installed'` to select the latest or the highest installed version. Read more: [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions). **Example of `tools`** ```yaml tools: nodejs: 22:installed ruby: 3.3:latest ``` ### Pipeline level properties #### `pipelines::title` The title of the Pipeline. This is not the same as the ID of the Pipeline: you set the ID when creating the Pipeline. Unlike the ID, the title does not have to be unique. It appears on the Workflow Editor UI in the **Pipelines** section: if you open the Pipeline selector dropdown menu. **Example of `pipelines::title`** ```yaml pipelines: test: title: Test pipeline ``` #### `pipelines::summary` A short summary of the Pipeline. Optional. **Example of `pipelines::summary`** ```yaml pipelines: test: summary: This Pipeline runs unit tests. ``` #### `pipelines::description` A detailed description of the Pipeline. Optional. **Example of `pipelines::description`** ```yaml pipelines: test: description: 'This Pipeline runs unit tests in parallel, using test sharding.' ``` #### `pipelines::triggers` Target-based triggers defined for the Pipeline: if a code event matches the condition defined in a trigger, Bitrise will trigger a build with the Pipeline. For the detailed syntax of the `triggers` property and its available options, check out: Read more: [YAML syntax for build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers). **Example of `pipelines::triggers`** In this example, any commit pushed to the `main` branch triggers a build of the Pipeline. ```yaml pipelines: test: triggers: push: - branch: main ``` #### `pipelines::status_report_name` The name that will appear on the status report sent to connected services (like GitHub, GitLab, Bitbucket, and so on) after the build is finished. It can have both static and dynamic values, as well as combine the two types. **Supported characters and variables**: - `A-Za-z,.():/-_0-9 []|<>` - ``: The unique identifier of your project. - ``: Optional title of your project. - ``: The ID of the triggered Workflow or Pipeline. - ``: The code event that triggered the build: `PR/push/tag`. The maximum length is 100 characters. **Example of `pipelines::status_report_name`** ```yaml pipelines: test: status_report_name: ci/bitrise/510526/push ``` #### `pipelines::workflows` The Workflows that are part of the Pipeline configuration. You can create dependencies between Workflows with the `depends_on` property. **Example of `pipelines::workflows`** ```yaml pipelines: test: workflows: primary: ``` #### `pipelines::priority` The priority setting determines the position of the Pipeline build in the build queue: the higher the priority, the sooner the Pipeline build will run. **Supported values:** - An integer between -100 and 100. **Read more:** - [Pipeline priority](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#pipeline-priority) - [Build priority](/bitrise-ci/configure-builds/configuring-build-settings/build-priority) **Example of `pipelines::priority`** ```yaml pipelines: test: priority: 10 ``` ### Properties of Workflows in Pipelines #### `workflows:depends_on` This property defines the Workflows that this Workflow depends on. If any of the Workflows in the list fails, this Workflow won't run. You can use both types of YAML array syntax to list dependant Workflows: block sequence and flow sequence. Any Workflow appearing in the dependency list must be part of the same Pipeline. :::caution[No circle or loop configuration] The dependency graph resulting from your configuration can't contain a circle or loop. You can't start builds with an invalid Pipeline configuration. ::: **Supported values**: Workflow names with YAML array syntax. Read more: [Configuring a Bitrise Pipeline](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline). **Example of `workflows:depends_on`** Block sequence array syntax: ```yaml pipelines: example: workflows: A: {} B: depends_on: - A C: depends_on: - A D: depends_on: - B - C ``` Flow sequence array syntax: ```yaml D: depends_on: [B, C] ``` #### `workflows:abort_on_fail` When this property is `true`, the Pipeline and any other running Workflows are aborted if this Workflow fails. **Supported values**: boolean Read more: [Configuring a Bitrise Pipeline](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline). **Example of `workflows:abort_on_fail`** In this example, both A and B are running in parallel. If B fails, the entire Pipeline, including Workflow A, is immediately aborted. ```yaml pipelines: example: workflows: A: {} B: abort_on_fail: true ``` #### `workflows:should_always_run` This property defines whether a Workflow should run if a previous Workflow failed. Be aware of transitive dependency: if a Workflow that is set to always run has a parent Workflow that fails, it will still run. However, Workflows that depend on it will not. For example, let's say we have Workflow C that depends on Workflow B. Workflow B depends on Workflow A. Of the three Workflows, only B is set to always run: - If A fails, B will run but regardless of its result, C won't run because by depending on B, it also depends on A. - C only runs if both A and B are successful. **Supported values:** - `off`: If a parent Workflow fails, the Workflow will not run. This is the default value. - `workflow`: If a parent Workflow fails, the Workflow will run anyway. Read more: [Configuring a Bitrise Pipeline](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline) **Example of `workflows:should_always_run`** ```yaml pipelines: example: workflows: A: {} B: depends_on: [ A ] should_always_run: workflow C: depends_on: [ B ] D: depends_on: [ C ] should_always_run: workflow ``` #### `workflows:run_if` A Go template expression that defines the conditions for running the Workflow. The property needs an `expression` field that contains a Go template, with three helper functions: - `getenv`: Accesses an Environment Variable's value. - `enveq`: Compares an Environment Variable to a given value. - `envcontain`: Checks whether an Environment Variable contains a given string. The Bitrise CLI evaluates the expression during runtime. If a Workflow is skipped because of a `run_if` expression, it will be counted as a successful Workflow so its dependent Workflows will run. Read more: [Examples of run_if expressions](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally#examples-of-run_if-expressions). **Example of `workflows:run_if`** In this example, B will only run if the EXAMPLE_KEY Environment Variable has the value example value. ```yaml pipelines: example: workflows: A: {} B: run_if: expression: {{ enveq "EXAMPLE_KEY" "example value" }} depends_on: [A] ``` #### `workflows:parallel` The `parallel` property allows you to run copies of the same Workflow in parallel, in a single instruction. This is particularly useful for test sharding. The property determines the number of copies running in parallel. Each copy receives two new environment variables: - $BITRISE_IO_PARALLEL_INDEX: a zero based index for each copy of the Workflow. - $BITRISE_IO_PARALLEL_TOTAL: the total number of copies. **Supported values**: An integer between 1 and 200. Read more: [Parallelism in Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow). ### Workflow level properties #### `workflows::title` The title of the Workflow. It appears on the UI of the Workflow Editor. **Example of `workflows::title`** ```yaml workflows: primary: title: Primary Workflow ``` #### `workflows::summary` A short summary of the Workflow. **Example of `workflows::summary`** ```yaml workflows: primary: summary: This Workflow runs unit tests. ``` #### `workflows::description` A detailed description of the Workflow. **Example of `workflows::description`** ```yaml workflows: primary: description: This Workflow runs unit tests with test sharding, and exports the test results to the test reports page. ``` #### `workflows::triggers` Target-based triggers defined for the Workflow: if a code event matches the condition defined in a trigger, Bitrise will trigger a build with the Workflow. Each trigger defines a code event and at least one condition. If you define multiple conditions in a single trigger, all of them must match to trigger a build. For the detailed syntax of the `triggers` property and its available options, check out: Read more: [YAML syntax for build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers). **Example of `workflows::triggers`** In this example, a build is triggered if: - A commit is pushed to the `main` branch. - A pull request is opened from any branch. ```yaml workflows: primary: triggers: push: - branch: main pull_request: - source_branch: "*" ``` #### `workflows::status_report_name` The name that will appear on the status report sent to connected services (like GitHub, GitLab, Bitbucket, and so on) after the build is finished. It can have both static and dynamic values, as well as combine the two types. **Supported characters and variables**: - `A-Za-z,.():/-_0-9 []|<>` - ``: The unique identifier of your project. - ``: Optional title of your project. - ``: The ID of the triggered Workflow or Pipeline. - ``: The code event that triggered the build: `PR/push/tag`. The maximum length is 100 characters. **Example of `workflows::status_report_name`** ```yaml workflows: test: status_report_name: ci/bitrise/510526/push ``` #### `workflows::before_run` :::tip[Step bundles] This is a legacy feature. We recommend using Step bundles instead: [Step bundles](/bitrise-ci/workflows-and-pipelines/steps/step-bundles). ::: The Workflows that will run before this Workflow starts. Use this property and `after_run` to create chains of Workflows. Read more: [Chaining Workflows together](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#chaining-workflows-together). **Example of `workflows::before_run`** In this example, we're creating a configuration in which the `test` Workflow runs before the `deploy` Workflow: ```yaml workflows: test: steps: # test Steps deploy: before_run: - test steps: # deploy Steps ``` #### `workflows::after_run` :::tip[Step bundles] This is a legacy feature. We recommend using Step bundles instead: [Step bundles](/bitrise-ci/workflows-and-pipelines/steps/step-bundles). ::: The Workflows that will run after this Workflow is successfully finished. Use this property and `before_run` to create chains of Workflows. Read more: [Chaining Workflows together](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#chaining-workflows-together). **Example of `workflows::after_run`** In this example, we're creating a configuration in which the `deploy` Workflow runs after the `ci` Workflow: ```yaml workflows: deploy: steps: # deploy Steps ci: after_run: - deploy steps: # CI Steps ``` #### `workflows::envs` Environment Variables defined for the Workflow. Each Environment Variable is a key-value pair. Environment Variables can use other Environment Variables as values: [Using Env Vars in the value of an Env Var](/bitrise-ci/configure-builds/environment-variables#using-env-vars-in-the-value-of-an-env-var). These variables are only available for the selected Workflow. Other Workflows defined in the same configuration YAML file can't access them. Project-level Environment variables have a higher priority: [Availability order of Environment Variables](/bitrise-ci/configure-builds/environment-variables#availability-order-of-environment-variables). Read more: [Environment Variables](/bitrise-ci/configure-builds/environment-variables). **Example of `workflows::envs`** ```yaml workflows: primary: envs: - TEST: test - ENV_LABEL: dev opts: is_expand: false ``` #### `workflows::steps` The list of Steps in the Workflow. The basic syntax of a Step reference is: `::@:`. The Step ID is always required; the source and the version are optional. - If you don't set a source, `default_step_lib_source` will be used: [Project level properties](/bitrise-ci/references/configuration-yaml-reference#project-level-properties). - If you don't set a version, the latest version will be used. Read more: - [Step reference/ID format](/bitrise-ci/references/steps-reference/step-reference-id-format) - [Step versions](/bitrise-ci/workflows-and-pipelines/steps/step-versions) **Examples of `workflows::steps`** In this example, we don't specify an exact source and we use the latest version of major version 1: ```yaml workflows: steps: - script: {} ``` In this example we're providing a source for the Step: ```yaml workflows: steps: - https://github.com/bitrise-io/bitrise-steplib.git::script@1: {} ``` #### `workflows::priority` The priority setting determines the position of the Workflow build in the build queue: the higher the priority, the sooner the Workflow build will run. **Supported values**: An integer between -100 and 100. Read more: [Build priority](/bitrise-ci/configure-builds/configuring-build-settings/build-priority). **Example of `workflows::priority`** ```yaml workflows: primary: priority: 10 ``` #### `workflows::tools` Declarative configuration for tool versions used in the build. You can define tool versions for specific Workflows. Instead of defining the tools property at the top level of the configuration, you nest it under one or more Workflows. The version syntax supports: - Exact versions: for example, `'1.2.3'`. - Partial matches to the latest release: for example, `'22:latest'`. - Partial matches to installed versions: for example, `'1.2:installed'`. - Special aliases `'latest'` and `'installed'` to select the latest or the highest installed version. Read more: [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions). **Example of `workflows::tools`** ```yaml workflows: primary: tools: nodejs: 22:installed ``` #### `workflows::meta` Stores project metadata key-value pairs. Most importantly, it defines the stack and the machine type for the Workflow. Read more: [Setting the stack in the bitrise.yml file](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds#setting-the-stack-in-the-configuration-yaml). **Example of `workflows::meta`** ```yaml workflows: deploy: meta: bitrise.io: stack: linux-docker-android-22.04 machine_type_id: g2.linux.2medium ``` ### Step bundle properties #### `step_bundles::title` The title of the Step bundle. It is an optional property as the Step bundle ID uniquely identifies the bundle. **Example of `step_bundles::title`** ```yaml step_bundles: test: title: Test bundle ``` #### `step_bundles::summary` A short summary of the Step bundle. Optional. **Example of `step_bundles::summary`** ```yaml step_bundles: test: summary: "It's a bundle to test Step bundles." ``` #### `step_bundles::description` A detailed description of the Step bundle. **Example of `step_bundles::description`** ```yaml step_bundles: test: description: "This Step bundle allows users to try out Step bundles on Bitrise. It includes a Git Clone Repository Step and a Script Step." ``` #### `step_bundles::envs` The Environment Variables that are only available for the Step bundle. Steps outside the bundle can't access the variables defined here! As all Env Vars, it takes a key and a value. **Example of `step_bundles::envs`** ```yaml step_bundles: test: envs: - MY_ENV: "value" ``` #### `step_bundles::inputs` Inputs defined for the Step bundle: these are values that can be set when the Step bundle is added to a Workflow. Read more: [Step bundles](/bitrise-ci/workflows-and-pipelines/steps/step-bundles). **Example of `step_bundles::inputs`** ```yaml step_bundles: test: inputs: - my_input: my_value ``` #### `step_bundles::execution_container` The default execution container for all Steps in this bundle. Can be overridden at the call-site or by individual Steps. Read more: [About Docker containers on Bitrise](/bitrise-platform/infrastructure/docker-containers-on-bitrise/about-docker-containers-on-bitrise). **Example of `step_bundles::execution_container`** ```yaml step_bundles: test: execution_container: test-container: {} ``` #### `step_bundles::service_containers` The default service containers for all Steps in this bundle. Can be overridden at the call-site. **Supported values**: Read more: [Service containers](/bitrise-platform/infrastructure/docker-containers-on-bitrise/service-containers). **Example of `step_bundles::service_containers`** ```yaml step_bundles: test: service_containers: test-container: {} ``` #### `step_bundles::steps` The Steps included in the Step bundle. **Example of `step_bundles::steps`** ```yaml step_bundles: test: steps: - git-clone: {} - script: {} ``` ### Step level properties #### `steps::title` The title of the Step. This appears on the Workflow Editor, replacing the Step ID. **Example of `steps::title`** ```yaml workflows: steps: - script@1: title: Test sharding script ``` #### `steps::summary` A short summary of the Step. **Example of `steps::summary`** ```yaml workflows: steps: - script@1: summary: Custom script for sharding. ``` #### `steps::description` A detailed description of the Step. **Example of `steps::description`** ```yaml workflows: steps: - script@1: summary: A custom script for setting up test sharding for Flutter unit tests. ``` #### `steps::is_always_run` If this property is true, the Step will always run, even if a previous Step in the Workflow failed. By default, if a previous Step fails in the Workflow, subsequent Steps will not run. A Step will only run if this property is set to `true`. **Supported values**: boolean Read more: [Skipping Steps](/bitrise-ci/workflows-and-pipelines/steps/skipping-steps). **Example of `steps::is_always_run`** ```yaml workflows: primary: steps: - script: is_always_run: true ``` #### `steps::is_skippable` If this property is true, the build won't fail even if this Step fails. By default if a Step fails, subsequent Steps are not executed. If the first failing step has this property set to `true`, it won't make the build fail. Subsequent Steps will still run and the build can finish successfully. **Supported values**: boolean **Example of `steps::is_skippable`** ```yaml workflows: primary: steps: - script: is_skippable: true ``` #### `steps::run_if` This property sets conditions for running a Step. It requires a valid Go template expression. A `run_if` can be any valid Go template, as long as it evaluates to true or false (or any of the String representation, for example `True`, `t`, `yes` or `y` are all considered to be true). If the template evaluates to `true`, the Step will run, otherwise it won’t. Read more: - [Enabling or disabling a Step conditionally](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally). - [Examples of run_if expressions](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally#examples-of-run_if-expressions). **Example of `steps::run_if`** In this example, the build skips the Step if the value of CUSTOM_ENV_VAR_KEY is not `test value to test against`. ```yaml run_if: |- {{enveq "CUSTOM_ENV_VAR_KEY" "test value to test against"}} ``` #### `steps::timeout` This property defines a time limit for a Step: if the Step runs longer than the defined time, the Step fails. Define the limit in seconds. This is useful if, for example, your builds hang for not immediately obvious reasons - you can set timeouts for the Step or Steps which are suspected to have caused the problem. Read more: [Setting a time limit for Steps](/bitrise-ci/workflows-and-pipelines/steps/setting-a-time-limit-for-steps). **Example of `steps::timeout`** ```yaml - xcode-test: timeout: 120 ``` #### `steps::no_output_timeout` This property defines a time limit for steps: if a Steps runs longer than the defined time without producing an output, the Step fails. Define the limit in seconds. Read more: [Detecting and aborting hanging Steps](/bitrise-ci/workflows-and-pipelines/steps/detecting-and-aborting-hanging-steps). **Example of `steps::no_output_timeout`** ```yaml output_slows_down: steps: - script: no_output_timeout: 12 ``` #### `steps::inputs` Inputs defined for the Step: these are values that can be set when the Step is added to a Workflow. Step input syntax consists of a `KEY: value` pair. Read more: [Step inputs reference](/bitrise-ci/references/steps-reference/step-inputs-reference). **Example of `steps::inputs`** ```yaml inputs: - my_key_for_the_env: "default value" ``` #### `steps::outputs` Outputs defined for the Step: these are values that the Step can set during its execution, which can be used by other Steps in the Workflow. You can check out the default outputs of a Step in the Workflow Editor on bitrise.io or in the `step.yml` file of the Step. Step outputs can be defined in the `step.yml` file of the project by setting the `outputs` attribute. Step out syntax consists of two main parts: a `KEY: value` pair and an `opts` field. The key and the value are required, the `opts` field is optional. Read more: [Step outputs reference](/bitrise-ci/references/steps-reference/step-outputs-reference). **Example of `steps::outputs`** ```yaml workflows: primary: steps: - gradle-runner: outputs: - BITRISE_APK_PATH: ALIAS_APK_PATH ``` ### Trigger properties #### `triggers:enabled` The property determines whether a defined trigger is active. The default value is `true`. If you want to disable the trigger, set it to `false`. **Supported values**: boolean **Example of `triggers:enabled`** In this example, the trigger is disabled. ```yaml workflows: primary: triggers: enabled: false ``` #### `triggers:priority` Sets a priority for an individual trigger condition, overriding the priority of the Workflow or Pipeline it triggers. **Supported values**: An integer between -100 and 100. The higher the value, the higher the priority. The default value is 0. Read more: [Build priority](/bitrise-ci/configure-builds/configuring-build-settings/build-priority). **Example of `triggers:priority`** ```yaml workflows: primary: triggers: push: - branch: main priority: 10 ``` #### `triggers:push` Code push triggers define the conditions for triggering a Bitrise build when code is pushed to the project's repository. For example, a commit to the specified branch of the project's repository triggers a build. **Example of `triggers:push`** In this example, a code push to the `main` branch triggers a build. ```yaml workflows: primary: triggers: push: - branch: main ``` ##### `triggers:push:branch` Triggers a build when code is pushed to the specified branch. **Supported values**: - A string. - The `pattern` property which allows simple text matching within all types of triggers. - The `regex` property which allows using regular expressions as a trigger condition. :::important[One type only] Use exactly one out of a string, a pattern, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:push:branch`** ```yaml workflows: primary: triggers: push: - branch: main ``` ###### `triggers:push:commit_message` Triggers a build when code is pushed with the specified commit message. **Supported values**: - A string. - The `pattern` property which allows simple text matching within all types of triggers. - The `regex` property which allows using regular expressions as a trigger condition. - The `last_commit` property that defines whether Bitrise should evaluate every commit message or changed file in a code push or only those belonging to the most recent commit. Its default value is `false`. :::important[One type only] Use exactly one out of a string, a pattern, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:push:commit_message`** In this example, a commit message that contains the string `[workflow: deploy]` triggers a build: ```yaml primary triggers: push: - commit_message: regex: '.*\[workflow: deploy\].*' ``` ###### `triggers:push:changed_files` Triggers a build when a code push results in changes to the specified file or files. You can specify files or a folders. **Supported values**: - A string. - The `pattern` property which allows simple text matching within all types of triggers. - The `regex` property which allows using regular expressions as a trigger condition. - The `last_commit` property that defines whether Bitrise should evaluate every commit message or changed file in a code push or only those belonging to the most recent commit. Its default value is `false`. :::important[One type only] Use exactly one out of a string, a pattern, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:push:changed_files`** ```yaml primary triggers: push: - changed_files: pattern: "myfile.txt" ``` #### `triggers:pull_request` Pull request triggers: they define the conditions for triggering a Bitrise build when a pull request is opened in the project's repository. **Example of `triggers:pull_request`** ```yaml primary triggers: pull_request: - source_branch: * ``` ##### `triggers:pull_request:source_branch` The branch from which the pull request is opened. **Supported values**: - A string. - The `regex` property which allows using regular expressions as a trigger condition. :::important[One type only] Use exactly one out of a string, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:pull_request:source_branch`** ```yaml primary triggers: pull_request: - source_branch: main ``` ##### `triggers:pull_request:target_branch` The branch which is the merge target of the pull request. For a pull request in a GitHub stack, Bitrise matches this against the base branch of the stack. **Supported values**: - A string. - The `regex` property which allows using regular expressions as a trigger condition. :::important[One type only] Use exactly one out of a string, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:pull_request:target_branch`** ```yaml primary triggers: pull_request: - target_branch: main ``` ##### `triggers:pull_request:label` The pull request label. A build is triggered when the label is added and when code is pushed to an open pull request that has this label. **Supported values**: - A string. - The `regex` property which allows using regular expressions as a trigger condition. :::important[One type only] Use exactly one out of a string, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:pull_request:label`** ```yaml primary triggers: pull_request: - label: bugfix ``` ##### `triggers:pull_request:draft_enabled` The property defines if draft pull requests trigger builds. **Supported values**: A boolean. Read more: [Disabling builds from a draft PR](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers#disabling-builds-from-a-draft-pr). **Example of `triggers:pull_request:draft_enabled`** ```yaml primary triggers: pull_request: - draft_enabled: false ``` ##### `triggers:pull_request:comment` A comment posted on a pull request. **Supported values**: - A string. - The `regex` property which allows using regular expressions as a trigger condition. :::important[One type only] Use exactly one out of a string, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:pull_request:comment`** ```yaml primary triggers: pull_request: - comment: approved ``` ##### `triggers:pull_request:commit_message` A specific commit message in pushes to a pull request. **Supported values**: - A string. - The `regex` property which allows using regular expressions as a trigger condition. :::important[One type only] Use exactly one out of a string, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:pull_request:commit_message`** ```yaml primary triggers: pull_request: - commit_message: "fix for issue" ``` ##### `triggers:pull_request:changed_files` Specific files that are modified in a pull request. **Supported values**: - A string. - The `regex` property which allows using regular expressions as a trigger condition. :::important[One type only] Use exactly one out of a string, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:pull_request:changed_files`** ```yaml primary triggers: pull_request: - changed_files: ./path/to/file ``` #### `triggers:tag` Git tag triggers define the conditions for triggering a Bitrise build when a Git tag is pushed to the project's repository. **Example of `triggers:tag`** ```yaml primary triggers: tag: - name: * ``` ##### `triggers:tag:name` The value of the tag that should trigger a build. **Supported values**: - A string. - The `regex` property which allows using regular expressions as a trigger condition. :::important[One type only] Use exactly one out of a string, or a regex. You can't use more than one in the same trigger! ::: **Example of `triggers:tag:name`** ```yaml primary triggers: tag: - name: 1.0 ``` ### Docker container properties #### `containers::type` The type of the container. **Supported values**: - `execution`: Containers that run a Step or a Step bundle. - `service`: Containers that run alongside a Step or Step bundle, running background services, such as `postgres`. Read more: [About Docker containers on Bitrise](/bitrise-platform/infrastructure/docker-containers-on-bitrise/about-docker-containers-on-bitrise). **Example of `containers::type`** ```yaml containers: node-18: type: execution ``` #### `containers::image` This property defines the Docker image used for the container, in a `name:tag` format. You can use any public image from Docker Hub. **Example of `containers::image`** ```yaml containers: node-18: image: node:18 ``` #### `containers::credentials` The credentials allow you to control the parameters supplied for the `docker login` command. Check your registries documentation on how to use docker login. The following properties are supported: - `username` - `password` - `server` **Example of `containers::credentials`** ```yaml containers: node-18: credentials: username: user password: pass ``` ##### `containers::credentials:username` The username that will be used with the `docker login` command. **Example of `containers::credentials:username`** ```yaml containers: node-18: credentials: username: _json_key_base64 ``` ##### `containers::credentials:password` The password that will be used with the `docker login` command. **Example of `containers::credentials:password`** ```yaml containers: node-18: credentials: password: $GCP_SERVICE_ACCOUNT ``` ##### `containers::credentials:server` Fully qualified registry server URL for the `docker login` command. This is optional if the server is already part of the image reference. **Example of `containers::credentials:server`** ```yaml containers: node-18: credentials: server: ghcr.io ``` #### `containers::ports` This property defines an array of ports which are used to access the service. Define ports in the format of `[HostPort]:[ContainerPort]`. **Example of `containers::ports`** ```yaml containers: ports: - 3000:3000 - 2000:2000 ``` #### `containers::envs` Define an array of Environment Variables for the Docker container. For each Env Var, define a key and a value. Read more: [Environment Variables](/bitrise-ci/configure-builds/environment-variables). **Example of `containers::envs`** ```yaml containers: node-18: envs: - VARIABLE_KEY: variable_value ``` #### `containers::options` Define additional Docker container resource options. These are parameters that will be passed to the `docker create` command. Read more about the possible options: [docker service create](https://docs.docker.com/reference/cli/docker/service/create/). :::important[Not supported options] `--network`, `--volume (-v)`, and `--entrypoint` are not supported. ::: **Example of `containers::options`** ```yaml containers: node-18: options: "--privileged --health-interval 1s" ``` --- ## Glossary ### Project {#project} A Bitrise project is the container for the entire Mobile DevOps process of your development work. Each workspace can own multiple projects. A project allows you to create a CI configuration and set up Release Management to distribute your mobile app to testers and to online stores. ### Configuration YAML {#configuration-yaml} The configuration YAML file stores your entire build configuration for a project. It specifies your stack and the build triggers, and defines the Workflows of the app. When you make changes on the graphical UI of our Workflow Editor, you actually modify your configuration YAML. ### bitrise.yml {#bitriseyml} The configuration YAML file stores your entire build configuration for a project. It specifies your stack and the build triggers, and defines the Workflows of the app. When you make changes on the graphical UI of our Workflow Editor, you actually modify your configuration YAML. ### Pipeline {#pipeline} A Bitrise Pipeline is the top level of the Bitrise CI/CD configuration. Pipelines can be used to organize the entire CI/CD process and to set up advanced configurations with multiple different tasks running parallel and/or sequentially. ### Project scanner {#project-scanner} The project scanner is a tool that identifies the given project's type and generates a basic Bitrise configuration. Each supported project type has its own scanner: these scanners are stored as separate packages. ### Secret {#secret} A Secret is a specific type of [Environment Variable](/bitrise-ci/configure-builds/environment-variables): they hide their information in an encrypted format and their value is not exposed in the build logs nor in the `bitrise.yml` configuration. You can store confidential information, such as passwords or API keys as Secrets. ### Stack {#stack} A build stack indicates the full configuration of the virtual machine that Bitrise uses to run your build. Each stack includes an operating system, and a large number of pre-installed software and tools. For example, our Xcode stacks run on macOS operating systems and contain, among many other tools, the Xcode version that is indicated in the name of the stack. ### Step {#step} A Step is a block of script execution that encapsulates a build task on Bitrise: the code to perform that task, the inputs and parameters you can define for the task, and the outputs the task generates. ### step.yml {#stepyml} The interface definition of a Bitrise Step. It defines the Step inputs and the generated outputs, as well as any other Step property such as the category and the description of the Step. It also points to the Step's source code. ### Trigger {#trigger} A trigger or build trigger is a configuration for automatically launching a Bitrise build when a specified event happens. Triggers require a webhook set up at your Git hosting provider. ### Workflow {#workflow} A Workflow is a collection of Steps, Environment Variables, and other configurations. When Bitrise starts a build, it runs one or more Workflows according to the configuration defined in the `bitrise.yml` file. ### Workflow Editor {#workflow-editor} The Bitrise Workflow Editor allows you to edit your Workflows, configure Steps, upload files (including code signing files) and manage your app's triggers and stacks on a graphical user interface. It is available both online and [offline](/bitrise-ci/bitrise-cli/installing-and-upgrading-the-offline-workflow-editor). ### Workspace {#workspace} A Workspace is an environment that allows you to manage your Bitrise apps and the team members working on the apps. You can create multiple Workspaces, and you can be invited to Workspaces by other Bitrise users. To be able to add apps and run builds, you either need to be part of a Workspace, or you have to be an outside contributor on an app's team. ### Remote Dev Environment {#remote-dev-environment} A Remote Dev Environment (RDE) is an on-demand cloud development machine — macOS or Linux — that runs on Bitrise infrastructure, using the same stacks and caches as Bitrise CI. You create a session, connect to it from a terminal, IDE, or AI agent, and archive or restore it later. ### Session {#session} A session is a single Remote Dev Environment instance: a running (or restorable) cloud machine created from a template or directly from a stack and machine type. Terminating a session preserves its persistent disk so you can restore it later. ### Template {#template} A template is a reusable Remote Dev Environment configuration — stack, machine type, warmup and startup scripts, inputs, and IDE folder links — that you create sessions from. ### Saved input {#saved-input} A saved input is a reusable, user-scoped value or credential (such as an SSH public key or an API token) that you can map into Remote Dev Environment sessions. Secret values are encrypted at rest. --- ## About Step code A Step encapsulates a build task: the code to perform that task, the inputs and parameters you can define for the task, and the outputs the task generates. For example the `Git Clone` Step performs a `git clone` of the specified repository, with the specified inputs, such as the branch or the commit to clone. From a technical perspective, a Step is a semver versioned repository which includes the code of the Step and the interface definition of the Step. The Step interface definition is defined in the `step.yml` file for every Step. It includes: - The dependencies of the Step. - The inputs and outputs of the Step. - The title and description of the Step. - Properties such as the issue tracker or support URL, or certain filter properties. To include Steps in your Workflow, you have to reference them in the configuration YAML file of your project. To do so, you will need the correct reference format for the Step. In the configuration file, you can also specify input values for the inputs defined in the Step's interface definition. --- ## Step data in the bitrise.yml file The Step data and information you specify in the `bitrise.yml` file are the parameters of the Step you want to change, compared to the Step’s default definition. To see the Step’s raw interface definition you can check it in the step library. The Step interface definitions can be found in the StepLib’s [steps directory](https://github.com/bitrise-io/bitrise-steplib/tree/master/steps). If you don’t specify any input or other Step property in the `bitrise.yml` configuration, only the Step (reference/ID), the Step will run with the default values as defined by the Step’s developer in the interface definition. Let’s see an example with a single [**Script**](https://github.com/bitrise-io/steps-script) Step, which will be executed when you run `bitrise run test`: ```yaml format_version: '26' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git workflows: test: steps: - script: ``` Specify inputs for the Step with the `inputs:` list property. An input consists of a *key* and a *value*: :::warning[Indentation] Indentation in the [YAML format](https://github.com/yaml/yaml-spec) is very important! You should use two- or four-space indentation, and you can’t use tabs to indent! ::: ```yaml format_version: '26' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git workflows: test: steps: - script: inputs: - content: "echo 'Hello World!'" ``` If the Step doesn’t have any required inputs you don’t have to specify an input. You can specify values for as many inputs as you want to. Step input values are always **string** / text values and they are passed to the Step as Environment Variables. The value can be multiline too, using the standard YAML multiline format: ```yaml format_version: '26' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git workflows: test: steps: - script@1.1.3: inputs: - content: | #!/bin/bash set -ex var_to_print='Hello World!' echo "${var_to_print}" ``` If you use a multiline value, like the one above, you have to indent the value with either two or four spaces, compared to the key! Force a Step to run even if a previous Step fails by setting the `is_always_run` property to `true`: ```yaml format_version: '26' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git workflows: test: steps: - script@1.1.3: is_always_run: true inputs: - content: "puts 'Hello Ruby!'" - runner_bin: ruby ``` Use the `title` property to add a descriptive title to your Step: ```yaml format_version: '26' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git workflows: test: steps: - script@1.1.3: title: Print Hello Ruby is_always_run: true inputs: - content: "puts 'Hello Ruby!'" - runner_bin: ruby ``` --- ## Step inputs reference Step inputs are environment items that tell the [Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli) how to run a given Step. The inputs of a Step are defined in the `step.yml` file of every Step by setting the `inputs` property.. Step inputs have the same syntax as every environment property. It consists of two main parts: a `KEY: value` pair and an `opts` field. ```yaml inputs: - my_key_for_the_env: "default value" opts: title: An example env var item is_dont_change_value: false category: example ``` - `my_key_for_the_env`: the key of the input (required). - `default value`: the default value of the input. You don’t always have to provide a default value. - `opts`: optional properties. ### Step input properties - `title`, `summary` and `description` : metadata, for comments, tools and GUI. :::tip[Meta properties as permanent comments] These meta properties can be used for permanent comments. Standard YML comments are not preserved when the YML is normalized, converted to JSON or otherwise generated or transformed. These meta properties are. ::: - `is_expand` : can be set to `true` or `false`. The default value is `true` so the Bitrise CLI expands Environment Variables (Env Vars) before passing it on to the Step. That means that if a Step input's value is an Env Var, the Bitrise CLI will pass the variable's value to the Step. If set to `false`, the CLI will pass the Env Var's key as a string. - `skip_if_empty` : can be set to `true` or `false`. If set to `true`, the input will not be used if its value is empty. - `category` : used to categorize the input. Inputs with the same `category` will appear grouped under one menu on the website UI, for the sake of convenience. - `value_options` : list of the available values. - `is_required` : can be set to `true` or `false`. If set to `true`, the step requires a non-empty value to be set for the input. - `is_dont_change_value` : can be set to `true` or `false`. If set to `true`, the value of the input should not be changed and/or should be hidden on UIs. Mainly used for debug inputs and for “**connection**” inputs (set to outputs of other Steps, to connect this Step with another one). - `is_template` : can be set to `true` or `false`. If set to `true` , the input’s value will be evaulated as a Go template. - `is_sensitive`: marking an input as sensitive means that it will only accept a Secret Environment Variable as its value. It is most frequently used for sensitive information such as passwords, API keys, tokens, but any input can be marked sensitive. ### Using template expressions for Step inputs If you need a Step to use a certain value only in certain circumstances, use template expressions as Step inputs. Template expressions are evaluated before the Step uses the input. They are written in [Go’s template language](https://golang.org/pkg/text/template/). Set the `is_template` property in the `step.yml` file of your project to use template expressions. 1. Open the `step.yml` file of your project. 1. Find the Step in which you wish to use a template expression. 1. Add an `opts` field to the `content` of the Step. 1. Add the `is_template` property to `opts` and set its value to `true`. 1. Add the template expression to the Step’s `content`. **Checking if the Bitrise CLI is in CI mode** ```yaml - script: title: Template example inputs: - content: |- {{if .IsCI}} echo "CI mode" {{else}} echo "not CI mode" {{end}} opts: is_template: true ``` --- ## Step outputs reference Step outputs are environment items that are the result of running a given Step. For example, the [**Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step generates five output envs by default: - $BITRISE_PUBLIC_INSTALL_PAGE_URL - BITRISE_PUBLIC_INSTALL_PAGE_URL_MAP - BITRISE_PERMANENT_DOWNLOAD_URL_MAP - BITRISE_ARTIFACT_DETAILS_PAGE_URL - BITRISE_ARTIFACT_DETAILS_PAGE_URL_MAP You can check out the default outputs of a Step in the Workflow Editor on [bitrise.io](https://www.bitrise.io) or in the `step.yml` file of the Step. Step outputs can be defined in the `step.yml` file of the project by setting the `outputs` attribute. They have the same syntax as every environment property. It consists of two main parts: a `KEY: value` pair and an `opts` field. The key and the value are required, the `opts` field is optional. ```yaml - MY_KEY_FOR_THE_ENV: my value for the env opts: title: An example env var item is_dont_change_value: false category: example ``` - `MY_KEY_FOR_THE_ENV`: The key of the environment item (required). - `my value for the env`: The value of the item (required). - `opts`: Optional attributes. The default outputs of a Step cannot be changed by the user in the `bitrise.yml` file of the project: they can only be changed in the `step.yml` file. However, you can export the output in a custom [Environment Variable](/bitrise-ci/configure-builds/environment-variables). This is useful, for example, if you have the same step twice in your Workflow and you wish to use the generated output of both steps: ```yaml workflows: primary: steps: - gradle-runner: outputs: - BITRISE_APK_PATH: ALIAS_APK_PATH ``` In this example, the value for the `BITRISE_APK_PATH` Environment Variable will be exported under the `ALIAS_APK_PATH` key. --- ## Step properties reference Step properties provide important data of a Step, such as its project type, its source code or the dependencies it requires. A Step’s inputs and outputs are also defined as Step properties. Let’s take a look at the properties! - `title`, `summary` and `description` : metadata, for comments, tools and GUI. :::tip[Meta properties as permanent comments] These meta properties can be used for permanent comments. Standard YML comments are not preserved when the YML is normalized, converted to JSON or otherwise generated or transformed. These meta properties are. ::: - `website` : official website of the Step / service. - `source_code_url` : the url where the Step’s source code can be viewed. - `support_url` : url to the Step’s support / issue tracker. - `published_at` : *auto-generated at share* - the StepLib publish date of the Step’s version - `source` : *auto-generated at share* git clone information. - `asset_urls` : *auto-generated at share* Step assets (StepLib specific), like icon image. - `host_os_tags` : supported operating systems. *Currently unused, reserved for future use.* - `project_type_tags` : project type tags if the Step is project type specific. Example: `ios` or `android`. Completely optional, and only used for search and filtering in Step lists. - `type_tags` : generic type tags related to the Step. Example: `utility`, `test` or `notification`. Similar to `project_type_tags`, this property is completely optional, and only used for search and filtering in Step lists. - `deps` : specifies the required dependencies of the Step. To declare a dependency, specify a package manager and then the dependency you wish to install. - `dependencies` : a newer, generic alternative to `deps`: specifies required dependencies as a list of `manager`/`name` pairs. - `toolkit` : specifies how the Step runs (for example, as a `bash` script or a `go` binary) and its entry point. - `inputs` : inputs (Environments) of the Step. - `outputs` : outputs (Environments) of the Step. --- ## Step reference/ID format A Step reference can contain three components: 1. The StepLib source: a library of Step repositories, such as the official [Bitrise Step Library](https://github.com/bitrise-steplib). 1. The Step ID: every Step must have an ID as part of its `step.yml` definition. 1. The Step version: the numerical version of the Step you want to include. Use the following syntax to reference a Step: ```yaml ::@: ``` From these three components only the Step ID is required. For example: ```yaml - script: ``` This could be written as: ```text https://github.com/bitrise-io/bitrise-steplib.git::script@1: ``` - If the version is not defined, the latest version of the step will be used. - If the StepLib source is not defined, the `default_step_lib_source` will be used. We recommend pinning the major version of a Step when referencing it. In the example above, `script@1` means major version 1 of the [**Script**](https://github.com/bitrise-io/steps-script) Step is pinned: the Step will run with the latest available minor and patch versions of the Step. For example, if the latest minor version is 1.2, and the latest patch version is 1.2.2 then pinning major version 1 means the Step will use version 1.2.2. ### Special Step sources There are two special Step sources: - `git::` - and `path::` When you use one of these sources, the Step won’t be identified through a Step Library but through the ID data you specify. #### The git:: source The `git::` source is the repository of the Step on your git hosting provider. The `script` Step’s GitHub source is: `https://github.com/bitrise-io/steps-script`. To reference the `script` Step directly through a git reference, you can use the `git::` source, the Step’s git clone URL, and the branch or tag in the repository. To reference the `1.1.3` version tag of the script Step’s repository: ```yaml - git::https://github.com/bitrise-io/steps-script.git@1.1.3: ``` In general, whenever you can use a Step version through a Step Library, you should do that, instead of using the `git::` source type. Features like local step caching, network caching, or alternative download URLs are only supported for Steps shared in a StepLib. But this type of referencing allows certain things you can’t get through a StepLib. For example, the `git::` source type can be used for not-yet-published or work-in-progress states of a Step. If you develop your own Step, you can use this `git::` source type to test your step before you publish it in a StepLib. To reference `soon-to-be-released` branch of your repository where you're developing a Step: ```yaml - git::https://github.com/bitrise-io/steps-script.git@soon-to-be-released: ``` #### The path:: source The `path::` source specifies a local path to a Step's repository, and it requires no version information. Both absolute and relative local paths are supported. A relative path is relative to the folder containing the `bitrise.yml` file. ```yaml - path::/path/to/my/step: - path::./relative/path: ``` This is useful for Step development. It can also be used if you want to include your build Steps in your project’s source code. --- ## Bitrise Desktop App for macOS The Bitrise Desktop App is a native macOS menu bar app that shows the live status of your builds for the branch you're working on, so you don't need to open a browser tab to check build status. :::note The Bitrise Desktop App is macOS only. ::: ### Installing the app The Bitrise Desktop App requires macOS 14.6 or later and a Bitrise account with access to at least one workspace and project. If you want to track a local folder, you also need a local checkout of the repository. 1. Download the `Bitrise.dmg` [file from GitHub](https://github.com/bitrise-io/bitrise-desktop-app/releases/latest/download/Bitrise.dmg). 1. Open the `.dmg` and drag Bitrise onto the **Applications** folder. 1. Launch Bitrise from **Applications**. The app appears as an icon in the menu bar on the top of your screen. On first launch, it shows an unconfigured state until you sign in. ### Launching at login In **Settings**, in the **General** pane, turn on **Launch at login** to have the app start automatically each time you log in to your Mac, so build status is in the menu bar without opening the app manually. ### Signing in 1. Click the Bitrise icon in the menu bar. 1. Click **Connect to Bitrise**. The app opens your browser to sign in. 1. Complete sign-in in the browser, then return to the app. After sign-in, the app stores your access token in the macOS Keychain and refreshes it automatically. Your signed-in handle appears in the build list header and in **Settings**. ### Choosing a workspace The selected workspace scopes everything the app shows, including builds, filters, and local-folder matching. - If you belong to one workspace, it's selected automatically. - If you belong to several, pick one from the workspace picker. - If you belong to none, the app points you to the Bitrise web UI to get access. You can switch workspace later from **Settings**, in the **Account** pane. ### Adding projects to watch The build list starts empty. You populate it by subscribing to one or more projects in Settings, in the Projects pane. There are two ways to add a project: - **Subscribing to a project directly**: This is a project-health watch. Use it to keep an eye on a project regardless of what you have checked out locally, for example, to confirm `main` stays green. - **Tracking a local folder**: The app matches each repository to its Bitrise project by the git remote URL, so you don't need to pick the project manually. It then tracks builds for the branch you currently have checked out, and stays in sync as you switch branches locally. **Subscribing directly** 1. Open **Settings** and go to the **Projects** pane. 1. Choose a project from your workspace to watch. **Tracking a local folder** 1. In the **Projects** pane, choose to add a local folder and browse to it. 1. The app scans the folder and its subfolders for git repositories and lists what it finds. 1. Select the repositories you want to track. :::note A branch with no builds in Bitrise shows an empty list. If you switch to a new branch that hasn't run any builds yet, that's expected. ::: ### Setting filters and notifications Each project you watch has its own settings, edited in its detail view in the **Projects** pane. - **Branches**: Choose which branches a project tracks. For local folders, this stays in sync with your checkout automatically. - **Notifications**: set each project to off, failures only, or every completion. A global **Allow notifications** switch in the Notifications pane turns all banners on or off. ### Grouping the build list In **Settings**, in the **Builds** pane, choose how the build list is organized: - **By project**: group builds under their project, one section per project. - **By date**: list every build newest-first across all projects, each one labeled with its project. A project can be **dual-tracked**: watched both because you subscribed to it directly and because you're tracking a local folder that matches the same repository. For dual-tracked projects, choose how to display them: - **Separate lists per source**: show two sections for the project, one per source, each labeled with an icon showing where it came from. - **Merged into one list**: combine builds from both sources into a single list for that project. ### Reading build status The menu bar icon mirrors the most recently started build across the projects you watch: - **Passed**: the most recent build passed. - **Failed**: the most recent build failed. - **Running**: a build is in progress. - **Aborted**: the most recent build was aborted. Click the icon to open the build list. Each build appears as a card showing its status and commit message, the branch or tag, the Workflow or Pipeline name, and the start time, duration, and build number. From a card, you can open the build, the pull request, or the commit on Bitrise in one click. For the full list of build statuses Bitrise tracks, see [Build statuses](/bitrise-ci/run-and-analyze-builds/build-statuses). ### Keeping the app updated The app checks for newer releases periodically, and on demand from **Settings**, in the **About** pane, using **Check Now**. When an update is available, you can download the new `.dmg`. Install it by dragging the app into **Applications**, the same way as the first install. ### Troubleshooting | What you see | What it means and what to do | | --- | --- | | Empty build list on a branch | That branch has no builds in Bitrise. Switch to a branch with build history, or trigger a build. | | Project not found for a folder | The folder's git remote doesn't match a project in the selected workspace. Confirm the remote and the workspace. | | Remote is outside this workspace | The repository belongs to a different workspace. Switch workspace in the Account pane. | | Detached HEAD or no remote | The app can't determine a branch to track. Check out a branch with an upstream remote. | | Sign-in error | Authentication failed or expired. Sign in again from the menu bar. | --- ## Build annotations Build Annotations allow you to add relevant build information directly on the Bitrise build details page, simplifying the process of accessing crucial data during build progression and debugging. The annotations are generated using Markdown styling. Some use cases include: - Detailed test results for custom tools. - Emphasizing warnings or error messages. - Security and vulnerability scan reports. - Static analysis reports. - Links to deployed artifacts. ### Annotating a build To use annotations: 1. Add a Step capable of running custom commands. For example, **Script** or **fastlane**. 1. Add a command to install the Bitrise Annotations plugin: ```bash bitrise plugin install https://github.com/bitrise-io/bitrise-plugins-annotations.git ``` 1. Use the `annotate` command of the plugin to create your annotations. The command works in the following format: `bitrise :annotations annotate [markdown] [flags]`. This is a basic Markdown annotation in the default style: ```bash bitrise :annotations annotate "**My Annotation**" ``` ### Styling and formatting your annotations Build annotations are a snippet of Markdown. The basic style of the snippet is determined by the `--style` flag of the annotation command. The possible values are: - `default`: - `warning`: - `error`: ![annotation-styles.png](/img/_paligo/uuid-913fb5c6-4636-158b-0e87-8458323e0987.png) The annotations accept Markdown syntax. In addition to simple formatting, it also supports code blocks, using the ~ character or four-space indentation: ```bash bitrise :annotations annotate " ~~~ This is a codeblock ~~~ " bitrise :annotations annotate " This is also a codeblock " ``` You can add expandable elements to your annotations: ![annotations-expand.gif](/img/_paligo/uuid-b72c807f-04d5-72e5-9c85-670efa9bb40a.gif) - Place your content in a details tag to collapse it by default. - If you want the card to be open by default, use details open. - Use a summary tag to let users know what is inside the section. - You can include headers, images, code blocks, and more inside a collapsed section. ```yaml
Example summary ### You can add a header You can add text within a collapsed section. You can add an image or a code block, too.
``` --- ## AI build fixer If you have a failed build, the AI build fixer corrects it right on the build’s details page without you having to switch to other tools and processes. The AI build fixer executes the suggested code changes and pushes a PR to your GitHub repository. You can check the changes through a link to the repo. Based on your configured build triggers, Bitrise kicks off a new CI build to validate the AI changes. This means less fragmented work and quicker debugging. :::note[AI build fixer credit consumption] Note that every run attempt of the AI build fixer costs two AI credits. ::: ### Configuring the AI build fixer To run the AI build fixer, you need to: - Turn on [AI build summary.](/bitrise-platform/ai/ai-features-on-bitrise#ai-build-summary) The AI build fixer builds on the outputs and suggestions of the build summary. - Enable the AI build fixer on the **Project settings** page. - Add your own trusted domains to the build fixer configuration. To do these: 1. From your workspace's **Dashboard**, click **Settings** on the left. 1. [Enable AI features](/bitrise-platform/ai/enabling-ai-features-on-bitrise). 1. On the **Project settings** page of your project, select **Bitrise AI**. 1. [Switch the toggle to enable AI build summary](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/ai-build-summary). Without enabling it, you won't be able to use the AI build fixer since it relies on the findings of the AI Build summary. 1. Switch the toggle next to the **AI Build fixer**. ![2026-01-20-ai-build-fixer.png](/img/_paligo/uuid-311c03e1-c104-9bed-9744-f751497444a1.png) 1. To set the domains Bitrise AI build fixer can use, select your preferred option in the **Configure agent internet access** dialogue which appears after you enabled the toggle. Here are the two options to choose from: - **Use Bitrise trusted domains**: You can start with a preset list of domains and can add more if you wish. Here is the list of preset domains: ``` alpinelinux.org anaconda.com apache.org apt.llvm.org archlinux.org azure.com bitbucket.org bower.io centos.org cocoapods.org continuum.io cpan.org crates.io debian.org docker.com docker.io dot.net dotnet.microsoft.com eclipse.org fedoraproject.org gcr.io ghcr.io github.com githubusercontent.com gitlab.com golang.org google.com goproxy.io gradle.org hashicorp.com haskell.org hex.pm java.com java.net jcenter.bintray.com json-schema.org json.schemastore.org k8s.io launchpad.net maven.org mcr.microsoft.com metacpan.org microsoft.com nodejs.org npmjs.com npmjs.org nuget.org oracle.com packagecloud.io packages.microsoft.com packagist.org pkg.go.dev ppa.launchpad.net pub.dev pypa.io pypi.org pypi.python.org pythonhosted.org quay.io ruby-lang.org rubyforge.org rubygems.org rubyonrails.org rustup.rsrvm.io sourceforge.netspring.io swift.orgubuntu.com visualstudio.com yarnpkg.com ``` - **Add domains manually:** You can add the domains (for example, a hosted git provider or a dependency store) you want our build fixer to access. Note that you must add your git provider here, otherwise our Build agent won’t be able to access it. ![configure-agent-internet-access-bitrise.png](/img/_paligo/uuid-f2b44f50-8b8a-8c8e-48dd-c12a800692d0.png) Once you enabled the Bitrise AI, the Bitrise Build fixer and set the domains, you can use the AI build fixer as well. :::note[Your code is safe with us] The Bitrise AI build fixer does not store any secrets or credentials while fixing your code or pushing the PR to your repo. For each fix attempt, it uses a one time only virtual machine which gets destroyed at the end of the run. ::: ### Running the AI build fixer Now you are all set to run the AI build fixer on your project: 1. Go to your projects **Builds** page and select a failed build. 1. On the **Build log** tab go to **Bitrise AI** and click **Show details**. 1. Under**Failure reasons** click **Fix with AI**. ![fix-with-ai.png](/img/_paligo/uuid-e3205cde-6fb9-f316-9666-a22617129183.png) 1. Click **Continue with fix**if you want Bitrise AI to start a build fixer agent and push changes to your current branch. ![fix-build-with-ai.png](/img/_paligo/uuid-49707b16-e6a3-6f4e-ea0a-869f23923758.png) 1. Once the AI build fixer has run, it produces links to the**Triggered build**, **Pushed changes to GitHub**and to the **Agent logs** for you to check changes and approve. You are ready to merge the PR into your project's repository. ![produced_links-ai-build-fixer.png](/img/_paligo/uuid-623c579f-869c-110a-da28-346d2a574ac0.png) --- ## AI build summary Our AI analyzer gives you a summary of why a CI build failed and suggests the fix right there on the build page. ![Bitrise AI panel with Failure details, Reason, and Suggested solution](/img/run-and-analyze-builds/2026-07-14-bitrise-ai-failure-details-panel.png) To enable the feature: :::note[Disabling AI] If you prefer not to use any AI features at all, you can disable all of them through the AI Settings menu in your Workspace settings page: [Enabling AI features on Bitrise](/bitrise-platform/ai/enabling-ai-features-on-bitrise) ::: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. Select **Bitrise AI** on the left. 1. Find **Summary** and toggle it on. --- ## Bitrise Checks on GitHub :::important[GitHub App integration] If you use the Bitrise GitHub App to connect a Bitrise Workspace to a GitHub account or organization, you don't need to do anything described in this section: GitHub Checks will automatically work for you to provide status updates. You can, however, continue to use the OAuth connection for your apps and use GitHub Checks with our GitHub App. ::: The Bitrise GitHub App provides, among other things, an extended version of the classic build status checks that Bitrise sends back to GitHub. This extended version includes a Bitrise build summary and a check status. You can view the checks if you click the **Details** link of a pull request on GitHub. It unfolds the detailed build summary and build status our GitHub app attaches to your pull request on the **Checks** tab of GitHub. ![Bitrise_Checks_on_GitHub_Checks.png](/img/_paligo/uuid-d3db0692-cdd1-86cb-615a-955fd97587e9.png) ![Bitrise_Checks_on_GitHub_Checks.jpg](/img/_paligo/uuid-0268c55e-cc52-4a65-4f01-f1db5f281a4e.jpg) There can be three different check statuses: - Success. - Failed. - Action required (in the case of manual pull request approval). To start using the Bitrise app to send status checks, you need to perform two separate actions: 1. [Install the Bitrise app](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/bitrise-checks-on-github#installing-the-bitrise-github-app-for-github-checks): This is only necessary for GitHub.com users. GitHub Enterprise Server users who [already set up the integration](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise) can proceed to enable the status checks with the app. 1. [Enable the Bitrise app](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/bitrise-checks-on-github#enabling-github-checks-on-bitrise): Turn on the feature on the Bitrise website and run a first build to be able to select the Bitrise app in your branch protection rules. ### Installing the Bitrise GitHub app for GitHub Checks To use Bitrise Checks as a GitHub.com user, you need to install it as a GitHub app. If the workspace that owns the Bitrise project has the Bitrise GitHub App connected and granted access to the Bitrise project's repository, you can skip the procedure described here and start using GitHub Checks. :::important[GitHub.com users only] If you are a GitHub Enterprise Server user, you don't need to do this procedure. To enable GitHub Checks, you need to: 1. [Install the GitHub Enterprise Server integration](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise). 1. [Enable GitHub Checks on Bitrise](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/bitrise-checks-on-github#enabling-github-checks-on-bitrise). ::: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Integrations** from the menu options. 1. Click the link under the toggle. Don’t toggle the switch just yet, since you first need to install the Bitrise app. This link will take you to GitHub's **Bitrise** installation page. ![github_checks_install.png](/img/_paligo/uuid-f07c26d9-ec9e-bcab-3f8e-184408ae7fc2.png) 1. Select the user or GitHub Organization you want to add the Bitrise app to. 1. Select an option to install the GitHub app to: - **All repositories**: Applies to all current and future repositories. - **Only select repositories**: Select the repositories that you need. With this, you authorize Bitrise to act on your behalf; for example, to check which repos you have access to, and use GitHub Checks to display check results. 1. Click **Install and authorize**. 1. In the GitHub prompt, provide your GitHub password. If all goes well, you land on the **Bitrise** page of GitHub. You should see a blue note at the top-left corner of the page that Bitrise has been successfully installed on your GitHub account. ### Enabling GitHub Checks on Bitrise Once [the Bitrise app is installed](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/bitrise-checks-on-github#installing-the-bitrise-github-app-for-github-checks) on GitHub, you need to enable GitHub Checks on the project settings page on [Bitrise](https://app.bitrise.io/ci). :::important[Enabling GitHub Checks is limited] Please note that only workspace owners and project admins can enable this toggle on the **Project settings** page of the project. ::: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Repository**. 1. Scroll down to the **Build reporting** section and toggle on the **GitHub Checks** switch. :::important[Can't toggle the switch?] If you can't toggle the switch, check out [Can't enable GitHub Checks](#cant-enable-github-checks). ::: 1. Trigger a build. You can do so either automatically or manually. If you trigger a build manually, provide a specific commit hash to build. This build is necessary to perform the first Bitrise check. Once there is a finished check, you can select Bitrise Checks in your branch protection rules. And you’re done! Now any pull request you open to your project on GitHub will be validated with Bitrise Checks and a build will get automatically started on Bitrise (if the [pull request trigger](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers) is properly set on Bitrise). #### Can't enable GitHub Checks There are two main reasons why you might not be able to toggle the switch to enable GitHub Checks: - You cannot toggle the switch unless you install the Bitrise GitHub app FIRST. Once it’s done, you can go ahead and toggle the switch to the right to enable it. - If you have renamed or moved the GitHub repository of an app which has already been added to Bitrise and you have installed Bitrise Checks on it. The repository’s GitHub URL has obviously changed. **GitHub Checks** switch can only work if the URL on Github and on Bitrise fully match (no redirect URL is allowed). So in this case, you have to [manually update the **Repository URL** of your app](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch). ### Disabling GitHub Checks To disable GitHub Checks for your project: if you toggle the **ENABLE GITHUB CHECKS** switch to the left on the **Settings** page of the project. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. Select **Repository** on the left. 1. Under **Build reporting**, disable the **GitHub Checks** toggle. ### GitHub Checks test summary If your project’s repository contains any UI or unit tests, you can run them by using the appropriate testing Steps in your Workflow. With the **Deploy to Bitrise.io** Step, your test results will be displayed in our **[test reports](/bitrise-ci/testing/deploying-and-viewing-test-results)** page and you can also see them on GitHub Checks, too. For example, if you have an Android app, you can use the **Virtual Unit Testing for Android** Step to be able to see all your test results on GitHub Checks. ![test_reports.png](/img/_paligo/uuid-6fb2370d-7bd0-a531-147b-deeb7a89c996.png) #### Step by Step error report If a CI build runs, GitHub Checks' test summary displays the Steps' successful and failed tests in separate tabs on the left sidebar. If you click on a Step, a more detailed report summary comes up where a number of tests are listed with actionable error report. The build summary is available on the Bitrise tab. Please note that GitHub Checks' test summary can only print detailed information of the following Steps: - **Xcode Test for iOS** - **Android Unit Test** - **iOS Device Testing** - **Virtual Device Testing for Android** - **Flutter Test** You can export test results generated by any other Step to the **Deploy to Bitrise.io** Step in two ways: - We strongly recommend using our **Export test results to the Test Reports** Step: this Step locates the test results based on your inputs. - You can configure your own custom **Script** Step that creates and exports the necessary files. #### Checking the test results of a failed Step If your build has some failed tests, here is how to access them in GitHub Checks: 1. Click the **Bitrise Checks** dropdown. 1. Click on a Step and view the error report of the specific Step. You can click on other Steps from here or the build summary. The **View more details on Bitrise Checks** link takes you to the build page on Bitrise. #### Re-running a build using GitHub checks :::important[Role requirement] To re-run a build using GitHub Checks, [your GitHub account must connected to Bitrise](/bitrise-platform/repository-access/repository-access-with-oauth#connecting-a-git-provider-with-oauth-from-the-account-settings-page), and you need to have at least Developer role in your app's team. If these conditions are not met, re-run checks will fail without an error. For a complete list of user roles and role cheatsheets, check [User roles on app teams](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). ::: If you would like to re-run a build using GitHub Checks: 1. Open the pull request on GitHub where you would like to re-run checks. 1. Open the **Checks** tab. 1. Click **Re-run all checks**. ![re_run_test.png](/img/_paligo/uuid-9f07fdaf-fccd-365f-c732-7e489e246580.png) --- ## Bitrise for Jira app The Bitrise for Jira app surfaces your Bitrise build and pipeline statuses directly on Jira issues, so your team can see where work stands without leaving Jira. :::important[Jira Cloud only] The Bitrise for Jira app works with Jira Cloud only: it doesn't support self-hosted Jira (Jira Data Center or Jira Server). ::: Build information appears on a Jira issue in two places: - A dedicated **Bitrise builds** section, where you can also re-run or abort a build. ![Bitrise builds section on a Jira issue, showing a pipeline and a build](/img/2026-08-10-jira-app-new-bitrise-section-pipeline-build.png) - The **Builds** tab of Jira's standard development panel. ![Builds tab of Jira's development panel, showing build status](/img/2026-08-10-jira-app-generic-development-section-builds-tab.png) :::important[Issue key required] Build information only appears on a Jira issue when the issue key (for example, `PROJ-123`) is present in at least one of the following: - The branch name. - A Git tag. - The pull request title. - The pull request description. - A commit message. ::: Setting up the app has two sides: - **On Jira**: a Jira admin installs the app and completes the connection. - **On Bitrise**: a user who can create the token and has Platform Engineer (or Admin) access on the relevant projects decides which projects to connect. See [Creating a token](#creating-a-token) for why that access level is required. This page walks through both sides from start to finish. Each section names who's responsible. ### Setup at a glance | Task | Done on | |---|---| | Installing the app in Jira | Jira, by a Jira admin | | Creating a token | Bitrise, by whoever creates the token | | Connecting Bitrise projects | Bitrise, then Jira | | Verifying the connection | Jira, by a Jira admin | ### Installing the app in Jira You need permission to install and configure apps on the Jira site. 1. In Jira, go to **Apps > Explore more apps** and search for **Bitrise for Jira**. 1. Select the app and click **Get it now** to install it. :::note If you're not a Jira admin, use **Request to install** to send an approval request to your admin instead. ::: ### Creating a token The app authenticates to Bitrise with an API token, either a workspace API token or a Personal access token. Who can create one, and what access it needs, depends on the type: | | Workspace API token | Personal access token | |---|---|---| | Belongs to | The workspace | An individual user | | Scope | A single workspace; can be limited to specific projects | Everything the user can access, across all their workspaces | | Who can create it | A workspace owner, or a member with the Manager workspace role | Any user, for their own account | | Needed on each connected project | Platform Engineer as the token's Bitrise CI product-access role | Platform Engineer (or higher) as the token owner's own project role | | Survives people leaving | Yes | No — the connection breaks if the user loses access | | Recommended for | Most setups | Connecting apps that span more than one Workspace | :::tip[Recommendation] Use a Workspace API token. It's tied to the Workspace rather than a person, can be scoped to just the Bitrise projects you want to connect to the app, and doesn't break when someone leaves the team. Choose a Personal access token only if you need to connect projects from more than one Workspace. ::: :::note[Why Platform Engineer] On each connected project, the app registers an outgoing webhook (needs the `change_settings` permission) and re-runs or aborts builds (needs `run_builds`). Platform Engineer is the lowest Bitrise CI role that covers both: Admin and Owner also work, but Developer and Tester/QA don't have enough access. - For a Personal access token, this is the token owner's own role on the project. - For a Workspace API token, this is the Bitrise CI product access role you set on the token. The Workspace role (Viewer, Contributor, Manager) is separate: it only controls who can manage the token, not what the app can do on connected projects. ::: **Workspace API token** 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Security**. 1. Click **Create token** and follow [Creating a Workspace API token](/bitrise-platform/workspaces/workspace-api-token), with these settings: - Set the **Workspace role** to **Manager** (this controls who can manage the token, not what the app can do). - Under **Configure access to products**, toggle **Bitrise CI** on and set its role to **Platform Engineer**: this is the access the app actually uses on connected projects. - Choose whether the token applies to all projects or only selected ones. **Personal access token** 1. [Create a personal access token](/bitrise-platform/accounts/personal-access-tokens). 1. Make sure your own account has at least Platform Engineer role on every project you want to connect. :::important[Save the token] You can only view a token's value at the moment you create it. Copy it and store it securely before leaving the **Save token** step. ::: :::tip You can set the token to never expire. If you set an expiry, the Jira connection stops working when the token expires: [Maintaining the connection](#maintaining-the-connection). ::: ### Connecting Bitrise projects To connect Bitrise projects to Jira, you need the API token and a list of the projects you want to connect. The connection is completed on the Jira side, so a Jira admin must do that part. 1. **On Bitrise:** Decide which Bitrise projects should send updates to Jira. Make a list of the specific projects, or decide to connect all of them. 1. Share the API token and the project list with the Jira admin through a secure channel, such as a password manager or secrets tool, not over plain email or chat. 1. **On Jira:** Go to **Apps > Manage your apps > Bitrise for Jira** and open its configuration page. 1. Under **Bitrise API Token**, paste the token you received and click **Save**. 1. Under **Connected Bitrise Projects**, select the projects you were given and click **Save**. :::note An outgoing webhook is created automatically in Bitrise for each connected project. You don't need to configure webhooks manually. ::: ### Verifying the connection You can verify the connection with a Jira admin. 1. Open a Jira issue whose key appears in the branch name, a Git tag, the pull request title, the pull request description, or a commit message of work in a connected Bitrise project. 1. Confirm that Bitrise build status appears in the **Bitrise builds** section of the issue and in the **Builds** tab of the development panel. If nothing appears, see [Troubleshooting](#troubleshooting). ### Maintaining the connection - **Token expiry or change:** If the API token expires, is regenerated, or is replaced, the connection stops working. Update the token on the app's configuration page and re-check your connected projects. - **New Bitrise projects:** When you add a new project in Bitrise that you want to appear in Jira, return to the app's configuration page and add it under **Connected Bitrise Projects**. ### Troubleshooting - **No build status on issues:** Confirm the issue key is present in the branch name, a Git tag, the pull request title, the pull request description, or a commit message. Then check that the token is still valid and that the relevant project is selected under **Connected Bitrise Projects**. - **A project is missing from the list:** The token can't access it. Check that the token (or the project role of its owner, for a Personal access token) includes that project, or ask whoever created the token to update it. - **Build status that used to work stops appearing:** The usual cause is someone unchecking **Attach Bitrise OIDC token** on the connected project's outgoing webhook, in Bitrise. Check the **Activity** section on the app's Jira configuration page for rejected deliveries. ### Related pages - [Workspace API token](/bitrise-platform/workspaces/workspace-api-token) - [Personal access tokens](/bitrise-platform/accounts/personal-access-tokens) --- ## Build logs Build logs allow users to analyze their builds and find out what went wrong - and what went right! On Bitrise, build logs are easily accessible: they can be viewed on the website in their entirety or they can be downloaded to view them on your own device. :::note[Build retention for 200 days] On the **Builds** page of your app, we only show builds from the last 200 days. The same limit applies if you are [searching for specific builds](/bitrise-ci/run-and-analyze-builds/finding-a-specific-build) on the page. This limitation also applies to most API calls: the `GET/apps/{app-slug}/builds` endpoint and related endpoints can only return builds from the last 200 days. However, there are two methods to get a build that is older than 200 days: - If you know the exact build URL, you can access the build. - You can use the `GET/apps/{app-slug}/archived-builds` API endpoint: [Listing the archived builds of an app](/bitrise-ci/api/managing-an-app-s-builds#listing-the-archived-builds-of-an-app). ::: ### Finding a build log When you run a build, a build log is generated automatically. Every build has its own log, with its own unique build log URL. The build log URL contains the build slug: a hexadecimal identifier for a specific build. :::note[Assisting Bitrise Support] When Bitrise Support asks for your build logs, the best thing to do is send the build URL. ::: 1. Open the [Bitrise CI](https://app.bitrise.io/ci) page and select your project from the project list. 1. Select the build you want to check out. 1. Make sure you have the **Log** tab selected. 1. On the **Log** tab, you can see the Steps of the Workflow and their status. By default, all failed Steps are expanded. ![Build log tab showing Steps and their status](/img/run-and-analyze-builds/2026-07-14-build-log-step-list.png) 1. Expand any Step's info by clicking the downward arrow on the right to the Step. This will show the relevant part of the build log. ### The build log page The build log page shows all Steps that were part of the build, and their status. By default, failed Steps are expanded, with the error message highlighted for convenient troubleshooting. Expanding a Step also allows you to see: :::note The **Duration** field in the header of the log might not be equal to the sum of the duration of all Steps. There are two possible reasons for such a discrepancy: - The duration value includes one-off initialization time for the Workflow/Pipeline as well as the sum of Step duration. - When using [remote access](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/remote-access), the VM stays open a full 10 minutes after the steps are all complete to allow review/download of logs ::: - The start time of the Step's run. - The Step ID. This is how the `bitrise.yml` configuration file identifies the Step. For more information, see [Step reference/ID format](/bitrise-ci/references/steps-reference/step-reference-id-format). - The current version of the Step. Underneath the version number, you can check the release notes for the Step. If the build didn't run with the latest version of the Step, you can also click **Update** to open the Workflow Editor and update the Step to a different version. - Under **Step resources**, you can check out the Step's documentation on our [Integrations](http://bitrise.io/integrations) page, as well as its source code and issue tracker on GitHub. To view a build log's contents in full, in a single file, [download the log](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/build-logs#downloading-a-build-log). ### Following a build log live You can check the log of a build live - that is, while the build is running. What’s more, you can even follow the log as the build is happening. That means that as the build progresses, the log will automatically scroll to the new sections as they appear. To do so: 1. Start a build. 1. Go to the build’s page. 1. Scroll down to the log. 1. Click **Follow**. ![Follow button on a running build's log](/img/run-and-analyze-builds/2026-07-14-build-log-follow-button.png) To stop following, you just need to manually navigate anywhere within the log. You can restart following any time. ### Downloading a build log If you need to send your build logs to people who do not have access to the app on Bitrise, or you want to store your logs in your own archives, you can simply download the log file from Bitrise. :::important[Log security] Please note that your build log can contain sensitive information! Make sure to check its contents before downloading the log file and sending it out to anyone. We recommend using [Secrets](/bitrise-ci/configure-builds/environment-variables) to make sure nothing sensitive appears in build logs. ::: 1. Open the [Bitrise CI](https://app.bitrise.io/ci) page and select your project from the project list. 1. Select the build you want to check out. 1. Open the **Logs** dropdown menu and click the **Download logs** button. ### Deleting a build log If necessary, you can delete the logs of any build on Bitrise. It can be handy if, for example, you do not want new team members to see potentially sensitive information that is displayed in previous logs. Not all team members are authorized to delete logs: only those with either **Admin** or **Owner** role in the team can do it. :::warning[Deletion is final] Be aware that you cannot undo deleting a log. Once you delete it, there is no way to recover the log file. ::: 1. Open the [Bitrise CI](https://app.bitrise.io/ci) page and select your project from the project list. 1. Select the build you want to check out. 1. Open the **Logs** dropdown menu and click the **Delete Logs** button. ![Logs dropdown menu with Download logs and Delete logs options](/img/run-and-analyze-builds/2026-07-14-logs-dropdown-delete-logs.png) 1. In the pop-up window, click **Delete logs**. --- ## Checking build details You can find additional details about a specific build by accessing the build's **Details** tab. The details include when the build was triggered, when it started and finished, its infrastructure details (such as the agent version or the hostname), its parameters, and even the exact command that was used to launch it. To check the details: 1. 1. Open the [Bitrise CI](https://app.bitrise.io/ci) page and select your project from the project list. 1. Select the build you want to check out. 1. Select the **Details** tab. ![details-tab.png](/img/_paligo/uuid-6b6e5440-9a6c-5fec-0970-63b75c992d1a.png) Additionally, if you want more information about a build’s runtime behavior and some help in diagnosing performance-related failures, check the **VM monitoring** tab. VM monitoring shows CPU, memory, and disk usage over the build’s lifetime. It is time-aligned with the build timeline, so you can correlate resource spikes with specific steps, logs, or long-running operations. --- ## Debugging your build on your own machine If your build fails on Bitrise, we often recommend to try and run it locally, on your machine. To do this, do the following: - Do a full clean git clone of your project’s online repository. - Run the build on your machine with the Bitrise CLI. This helps to eliminate, among other things, a very common issue: that uncommitted or gitignored files are in your working directory but they haven’t been committed into your git repository online and therefore they are not available when Bitrise clones the repository for running the build. Other possible issues include: - Code signing files are present on your local machine but not uploaded to Bitrise. - A difference in the version of the tool(s) used for the build. ### Testing with a full clean git clone 1. Open your Terminal / Command Line interface on your machine. 1. Type in: `cd /tmp` 1. Clone your repository with: `git clone REPOURL ./quick-repo-test --branch BRANCH-YOU-WANT-TO-TEST`: ```bash git clone https://github.com/bitrise-io/bitrise.git ./quick-repo-test --branch master ``` 1. Type `cd ./quick-repo-test.` Run the commands you want to test, to build your project, or to open the project file from this directory. ### Testing with the Bitrise CLI After doing a full clean git clone, run a build locally, using the [Bitrise CLI](https://www.bitrise.io/cli). 1. [Install the Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli). 1. Download your app’s `bitrise.yml` file from [bitrise.io](https://www.bitrise.io/). 1. Run the build with: `bitrise run ` (for example, `bitrise run primary`). This should help reproducing the issues in most cases, and allows you to attempt to debug them on your own machine. If the build succeeds under these conditions but still fails on Bitrise, [contact our support!](https://www.bitrise.io/requests/new) :::tip[Android projects] If you still can’t reproduce the issue locally, you might also want to delete the `$HOME/.gradle` (hidden) directory, to clear your Gradle caches. (Quick Terminal / Command Line command: `rm -rf $HOME/.gradle`). ::: :::tip[Run docker from a clean git clone] If your project uses the Android/Linux environment, you can download and use the exact same environment as the one your build is running in on [bitrise.io](https://www.bitrise.io/). Ideally, you should first do a clean git clone and run `docker` from there, so that files which are in your `.gitignore` won’t affect the build, and the build can run the the same way as on [bitrise.io](https://www.bitrise.io/). ::: --- ## Rebuilding a failed build If a build fails, you can rebuild any time to quickly recover from any errors. You can rebuild either single Workflows or an entire Pipeline. A rebuild always uses the current configuration YAML file: if a build fails and then you modify your configuration and rebuild, the rebuild will run with the new configuration. ### Rerunning a failed Workflow build You can rebuild a failed Workflow at any time. Rebuilding means immediately launching a new build with the current configuration YAML file. 1. Open Bitrise CI and find your project's build page. 1. On the top right corner, click **Rebuild**. :::tip[Remote access] You can also rebuild with remote access: click the downward arrow to open the dropdown menu and click **Rebuild with Remote Access**. To find out more: [Remote access](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/remote-access) ::: ### Rebuilding a failed Pipeline You can rebuild an entire Pipeline or certain parts of it at any time. The Pipeline build page shows the status of every Workflow in your Pipeline when a build is running. If a Workflow fails, you can save time by re-running the failed Workflow instead of the whole Pipeline. :::important[Time limit for partial reruns] Partial pipeline reruns are available for 30 days after the original pipeline execution. Full reruns can be run at any time. ::: #### Rebuilding a failed Pipeline You can rebuild a Pipeline either in full or its unsuccessful Workflows with the click of a button: 1. Open Bitrise CI. 1. Click a finished Pipeline build for your project. 1. On the Pipeline summary screen, click **Rebuild** to bring up the rebuild dropdown menu. 1. Select an option: - **Rebuild unsuccessful Workflows**: This option only rebuilds the Workflows that failed. This option might not be available for variant Workflows using the `parallel` property: [Rebuilding Pipelines using different Workflow variants](#rebuilding-pipelines-using-different-workflow-variants). - **Rebuild the entire Pipeline**: This option rebuilds the entire Pipeline from start to finish. - **Rebuild unsuccessful Workflows with remote access**: Remote access allows you to access the build machine remotely while the build is running: [Remote access](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/remote-access). - **Rebuild entire Pipeline with remote access**: See above. #### Rebuilding a Pipeline from a failed Workflow You can rebuild a Pipeline from a specific failed Workflow. This will rebuild all Workflows that come after the failed Workflow in the Pipeline. This option might not be available for variant Workflows using the `parallel` property: [Rebuilding Pipelines using different Workflow variants](#rebuilding-pipelines-using-different-workflow-variants). 1. Open Bitrise CI. 1. Click a finished Pipeline build for your project. 1. Scroll down to the graph of the Pipeline. 1. Find the failed Workflow and hover over it on the right of the card. 1. Click the **Rebuild from here** button. #### Rebuilding Pipelines using different Workflow variants If your Pipelines [use different variants of the same Workflow(s)](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow) with the `parallel` property, the available rebuild options depend on the Environment Variable defining the number of parallel runs. - If the Workflow which sets the number of parallel runs has already finished during the failed build, you have to rebuild the whole Pipeline. - If the number hasn't been set yet during the build, you can use a partial rebuild: either rebuilding from a failed Workflow or rebuild all unsuccessful Workflows. This is because Bitrise only allows partial rebuilds if the rebuild runs with the same Pipeline configuration as the original build. Two Pipeline configurations are identical if they have the same number of Workflows and the Workflows have the same names. When the parallel count is set, Bitrise has no way of knowing if the number is going to be the same in the rebuild. If the number is different, the two Workflow configurations are also different so a full rebuild is the only option. --- ## Remote access Remote access allows users to connect to a running build machine for easier debugging. A failed build can be rebuilt with remote access enabled to make troubleshooting a lot easier - for example, if the build logs don’t provide enough information about the error. You can rebuild both standalone builds and [pipeline builds](/bitrise-ci/workflows-and-pipelines/build-pipelines/pipelines-with-stages/configuring-a-pipeline-with-stages) with remote access. :::important[Authorization] Users who have the **Testers/QA** roles on the app CANNOT use remote access. ::: There are three ways to use remote access: - [Visual Studio Code](#remote-access-with-visual-studio-code): connect the Bitrise build to your local VSCode app as a remote repository. - **SSH**: classic remote shell connection from your terminal. - **Screen share**: remote screen sharing with our VNC client of choice. Works with macOS builds only. With either method, you can access the build machine remotely during the build and for 10 minutes after the build is finished. If you would like to extend the availability of remote access, you can do so by adding a simple custom [Script](https://github.com/bitrise-io/steps-script) Step after the failed Step. Check out [Extending the availability of remote access](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/remote-access#extending-the-availability-of-remote-access) for more information. :::important[Build time] When using remote access, 10 minutes will be added to your overall build time. ::: ### Remote access with Visual Studio Code This remote access mechanism allows your local Visual Studio Code app to connect to the Bitrise build machine as a [remote repository](https://code.visualstudio.com/docs/remote/ssh). You can browse and edit files in real time, use the built-in terminal to execute commands, and even install a subset of VSCode extensions. 1. Open the project on Bitrise. 1. On the main page of the project, find the build you want to re-run with remote access and click it. 1. On the **Rebuild** button, click the downward arrow to open the dropdown menu. 1. Select **Rebuild with remote access**. This starts a new build that you can access remotely. ![Rebuild with remote access option in the Rebuild dropdown menu](/img/run-and-analyze-builds/2026-07-14-rebuild-with-remote-access-button.png) 1. On the build's page, select the **VSCode** tab. 1. Follow the on-screen instructions to install the Bitrise CLI, its remote access extension and the connection command. ![VSCode tab with Bitrise CLI, remote access plugin, and connection command](/img/run-and-analyze-builds/2026-07-14-remote-access-vscode-tab.png) ### Remote access with SSH To access a Bitrise build machine with SSH, you will need a command line interface and the correct command and password: 1. Open the project on Bitrise. 1. On the main page of the project, find the build you want to re-run with remote access and click it. 1. On the **Rebuild** button, click the downward arrow to open the dropdown menu. 1. Select **Rebuild with remote access**. This starts a new build that you can access remotely. ![Rebuild with remote access option in the Rebuild dropdown menu](/img/run-and-analyze-builds/2026-07-14-rebuild-with-remote-access-button.png) 1. On the build's page, select the **SSH** tab. 1. Find the **Command** and run it in a command line interface. ![SSH tab with the Command and Password fields](/img/run-and-analyze-builds/2026-07-14-remote-access-ssh-tab.png) And done! You should be able to access the virtual machine where your build is running. ### Remote access with screen share To access a Bitrise build machine with a screen share app, you will need the correct username, password, and URL, as well as a VNC screen share app: :::note[macOS only] Remote access with screen share is only available for Workflows that run on a macOS-based stack. If the Workflow's stack (or in absence of Workflow-specific stacks, the app's default stack) is a Linux-based one, you won't see the screen share instructions at all. ::: 1. Open the project on Bitrise. 1. On the main page of the project, find the build you want to re-run with remote access and click it. 1. On the **Rebuild** button, click the downward arrow to open the dropdown menu. 1. Select **Rebuild with remote access**. This starts a new build that you can access remotely. ![Rebuild with remote access option in the Rebuild dropdown menu](/img/run-and-analyze-builds/2026-07-14-rebuild-with-remote-access-button.png) 1. On the build's page, select the **Screen share** tab. 1. Find the required information: - URL - Username - Password ![Screen share tab with the URL, Username, and Password fields](/img/run-and-analyze-builds/2026-07-14-remote-access-screen-share-tab.png) 1. Open a VNC screen share application. The simplest option is using the default **Screen Sharing** application on macOS. 1. Fill out the required fields with the information from under the **Screen share** option. And done! You should now be able to access the virtual machine where your build is running. ### Finding your files on the VM Once you successfully logged in to the Bitrise virtual machine that ran your build, you can dive into the files themselves to see what’s happening in real time. After Bitrise finished cloning your app on to the VM, you can always access it at the following location: ```text /Users/vagrant/git ``` ### Extending the availability of remote access Remote access is available while the build is running and for 10 minutes after the build is finished. If this is not enough, there’s a simple workaround to make sure remote access is available for a longer time. **Workflow Editor** 1. Add a **Script** Step after the Step that causes the build to fail. 1. Toggle the **Run even if previous Step(s) failed** option on to ensure the **Script** Step always runs. 1. Add a command to let the build “sleep” for a time specified in seconds: `sleep 5400` This example lets the build run for 90 minutes. It should be no more than your build time limit, of course. **Configuration YAML** Add a `script` Step after the Step that causes the build to fail. Set `is_always_run` to `true` so the Step always runs, and add a command to let the build “sleep” for a time specified in seconds: ```yaml workflows: primary: steps: - script: is_always_run: true inputs: - content: sleep 5400 ``` This example lets the build run for 90 minutes. It should be no more than your build time limit, of course. That’s it. While the build is still running, you can look around on the virtual machine for the possible issues that caused it to fail. --- ## Reporting build problems in PR comments You can receive debugging information from Bitrise builds in Pull Request (PR) comments. This brings build insights directly into your PR timeline to accelerate problem resolutions and reduce context switching. :::note[Service Credential User and PR comments] Note that PR comments will be posted using a [service credential user account](/bitrise-platform/integrations/the-service-credential-user) or the [Bitrise GitHub App](/bitrise-platform/repository-access/github-app-integration) if that is in use, rather than your personal account. ::: ### Configuring PR comments in Bitrise Configure PR comments with just a few clicks: 1. Open your project on Bitrise with a user who has either the **Admin** role or the **Owner** role on the project. 1. On the main page of the project, click on the **Project settings** button. 1. Click **Repository** on the left. 1. Scroll down to **Build reporting** and enable the toggle for **PR comments**. ![Build reporting section with the PR Comments toggle](/img/run-and-analyze-builds/2026-07-14-build-reporting-pr-comments-toggle.png) 1. In the **Configure PR comments** window, all information blocks are unchecked by default. Select any that you want to include in PR comments. The information blocks are the following: - **Build summary**: Build overview at the top of the comment. With AI on, also shows why the build failed and what to check first. - **Step failures**: Shows failed Steps and error details. Hidden when all Steps succeed. - **Test failures**: Shows failed tests and error details. Hidden when all tests succeed. - **Flaky tests**: Shows flaky tests and rerun information. Hidden when there are no flaky tests. ![Configure PR comments dialog with information blocks and Comment mode options](/img/run-and-analyze-builds/2026-07-14-configure-pr-comments-dialog.png) 1. Under **Comment mode**, you can choose a comment mode to receive either a single comment or multiple comments. - **Single comment**: Each build on the PR replaces any existing comments from a previous build, so the PR displays only the comment from the most recent build. - **Multiple comments**: Each build on the PR adds a new comment, preserving a running history in the PR timeline. :::note[More on Comment mode] One PR build means one comment. However, multiple different Workflows on the same PR means multiple comments regardless of the **Comment mode** you choose. If the same Workflow is re-triggered, it adds new comments or updates the existing ones on the PR based on the chosen **Comment mode**. ::: 1. When ready, click **Save changes**. ### Receiving comments only for failed builds If you have checked all the information blocks, you will receive a comment for both successful and failed builds. In this case, comments from successful builds will include a summary of the build. See examples below: ![reportingbuildproblemsfirstpic.png](/img/_paligo/uuid-91fa95b8-0325-7201-68ee-ddb01087718a.png) ![reportingbuildproblemssecondpic.png](/img/_paligo/uuid-33093867-a2c4-50e5-79ca-cf8fba179e41.png) To prevent receiving comments on your successful builds from Bitrise, uncheck the “Build Summary” block and select the other boxes as needed. This way, you’ll only receive comments like below when there’s a problem in your build. ![reportingbuildproblemsthirdpic.png](/img/_paligo/uuid-74995bb5-af37-b70b-03e0-218fc8e978f7.png) ### FAQ about embedding debug information in PR commits **Who is the author of these PR comments?** This depends on the type of authentication. The [Service Credential User](/bitrise-platform/integrations/the-service-credential-user) account posts comments if you [authenticate with the OAuth method](/bitrise-platform/repository-access/repository-access-with-oauth). This applies for all Git providers, for example, Github, Gitlab, Bitbucket. If you use the [Bitrise GitHub app](/bitrise-platform/repository-access/github-app-integration), the associated Bitrise bot will post the comment. **Which Git providers are supported?** All major Git providers—GitHub, GitLab, and Bitbucket — are supported. **Will these comments appear for every PRs?** It's an opt-in feature per project. Comments will only be posted if you have opted into this for the project. **Will PR comments include full logs?** No. Comments include concise error snippets and links back to the full build and Step logs on Bitrise. Use the link to open the Bitrise dashboard for the full context. **What if it’s a pipeline build with many workflows? Will the comment show which Workflow the failing Step or test belongs to?** If enabled, you will get one PR comment for the pipeline build. Information will be grouped per Workflow. **Can I change settings per Workflow/Pipeline?** No. It is a project-level setting and is not customizable per Workflow/Pipeline. **What if I trigger multiple builds from the same PR? Will there be one comment or multiple comments?** If you trigger multiple builds that are distinct (for example, a PR triggered three distinct pipelines A, B, and C), you will receive multiple comments. If you trigger multiple builds that are the same (for example, a PR triggered the same pipeline twice, one after the other), then you will receive one comment if you selected **Single comment** mode, or multiple comments if you selected **Multiple comments** mode. --- ## Viewing HTML reports If you generate some form of rich HTML content (for example, code coverage reports or performance reports) during your Bitrise build, you do not have to download and view the report in a separate tool: you can view the content directly on the Bitrise UI. You don't have to embed everything in the HTML file either: Bitrise will parse all images, CSS files and Javascript files to display the full content as intended. ![after.gif](/img/_paligo/uuid-ab2808a9-e648-a309-8e76-6aa126e8047c.gif) To view an HTML report on Bitrise: 1. Generate your HTML report during a build. 1. Create a subfolder of the BITRISE_HTML_REPORT_DIR directory with a descriptive name. The name of the folder will be the title of your report on the UI. BITRISE_HTML_REPORT_DIR is an Environment Variable pointing to the directory where Bitrise is looking for the HTML reports. 1. Make sure your generated report is deployed to your subfolder. :::tip[Multiple reports] You can generate multiple reports in multiple subfolders. Each report must have an `index.html` file. ::: 1. Run a build. 1. Once the build is finished, go to the build's page and select the **Artifacts** tab. You can find your report under the **HTML reports** section. :::note[Seven day limit] Each HTML report is available for seven days. ::: ![image1.png](/img/_paligo/uuid-712cfa80-b11d-3b99-d09a-158ea80f051b.png) --- ## Build numbering and app versioning All Bitrise builds have a build number. The first build of your project is, by default, number 1, and the build number gets incremented with each build. You can get a build’s Bitrise build number on the website, as well as via the `$BITRISE_BUILD_NUMBER` Environment Variable. This variable can be used in any Step or script where you need the Bitrise build number for any reason. You can change the build number manually on the web UI. For details, see: [Changing the build number on the web UI](/bitrise-ci/run-and-analyze-builds/build-numbering-and-app-versioning#changing-the-build-number-on-the-web-ui). Bitrise also helps you taking care of your mobile app’s versioning automatically, using Bitrise. We have two Steps to do it for you, one for iOS and one for Android. For details, see: [Setting up app versioning automatically on Bitrise](/bitrise-ci/run-and-analyze-builds/build-numbering-and-app-versioning#setting-up-app-versioning-automatically-on-bitrise). ### Changing the build number on the web UI The build number is automatically incremented whenever you run a build, but you can set it manually on the **Project settings** page of your Bitrise project. :::note[Negative build numbers] The build number must be a positive integer. Zero or negative numbers are not accepted. You can, however, set any number you have already used. ::: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Builds**. 1. Find **Next build number** and click **Edit**. ![Next build number section on the Builds page of Project settings](/img/run-and-analyze-builds/2026-07-13-next-build-number-project-settings.png) 1. Add the desired build number then click **Save**. ### Setting up app versioning automatically on Bitrise Track the version of your mobile app in its Git repository by modifying the file containing the essential information about the app (for example, the `Info.plist` file for iOS apps and either the `build.gradle` file or the `AndroidManifest.xml` file for Android apps). Bitrise has two Steps to do this for you. These two Steps can insert the Bitrise build number or some other specified number into their respective files: - **Change Android versionCode and versionName** for Android apps. - **Set Xcode Project Build Number** for iOS apps. Both Steps accept either numbers (integers and/or numeric strings) or environment variables in their relevant inputs. By default, both use the $BITRISE_BUILD_NUMBER Environment Variable as their default value for the build number. #### Setting the versionCode and the versionName of an Android app For an Android app, the setting is used as an internal version number, to determine if a build of the app is more recent than another build. The `versionName` setting is a string used as the version number shown to users. For in-depth information about Android versioning, please check out [the Android developer guide on the subject](https://developer.android.com/studio/publish/versioning). :::note[Version information in the manifest file] In this guide, we’re setting the version information in the `build.gradle` file. This is the recommended method: you can also set it directly in the `AndroidManifest.xml` file but be aware that any version info set in the manifest file before the build will be overwritten by the `build.gradle` file’s settings during the build. ::: To configure Android versioning: 1. Add the **[Change Android versionCode and versionName](https://bitrise.io/integrations/steps/change-android-versioncode-and-versionname)** Step to your Workflow. 1. Set the the path to your `build.gradle` file in the **Path to the build.gradle file** input. ![change-android-version.png](/img/_paligo/uuid-fb7fb260-5679-1832-9448-228a048e2b80.png) 1. Add a value in the **New versionCode** input. The default value is the $BITRISE_BUILD_NUMBER Environment Variable. 1. Add a value in the **New versionName** input. #### Setting the CFBundleVersion and CFBundleShortVersionString of an iOS app For an iOS app, the value of the `CFBundleVersion` key (“Bundle version” in Xcode) is the build number of the app while the value of the `CFBundleShortVersionString` key (“Bundle versions string, short” in Xcode) is the version number of the app. For in-depth information about iOS versioning, including the functions of the `CFBundleVersion` and the `CFBundleShortVersionString` keys, please check out [this Apple technical note](https://developer.apple.com/library/archive/technotes/tn2420/_index.html); you can also look up the [summary of most important keys](https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html). :::important[Setting up iOS versioning for apps using Xcode 13+] To set up iOS versioning on Bitrise using Xcode 13+, update the following in Xcode: - Set the **Generate Info.plist File** to `No`, under **PROJECT** and **TARGETS** on the **Build Settings** tab. - Make sure you have all the necessary keys defined in the `Info.plist` file. ::: 1. Add the **Set Xcode Project Build Number** Step to your Workflow. 1. Set the file path to the `Info.plist` file in the **Project path, scheme and Target** input. 1. Add a value in the **Build Number** input. This sets the `CFBundleVersion` key to the specified value in the `Info.plist` file. The default value is the $BITRISE_BUILD_NUMBER Environment Value. 1. Optionally, add a value in the **Version Number** input. This will set the `CFBundleShortVersionString` key to the specified value in the `Info.plist` file. This input is not required. ### Offsetting the build version You can offset your app’s build version numbers if you tracked versions differently before using Bitrise. For example, if your app already had six builds before you started using Bitrise, you can offset the version code so it continues from where you left off, instead of restarting from 1. **Android** 1. Add the **Change Android versionCode and versionName** Step to your Workflow. 1. In the **New versionCode** input, use `$BITRISE_BUILD_NUMBER` (this is the input's default value). 1. In the **versionCode Offset** input, set the value to add to the build number. This can be a fixed integer or an Environment Variable. :::tip[Offsetting an Android app's version example] Let’s say you're about to run your app's fifth build on Bitrise, and the app already had six builds before you started using Bitrise. To keep versionCode numbering continuous: - New versionCode: `$BITRISE_BUILD_NUMBER` - versionCode Offset: `6` - New versionName: `1.0.5` `$BITRISE_BUILD_NUMBER` (5, in this example) is added to the versionCode Offset (6), so versionCode is set to 11. versionName isn't affected by the offset and stays 1.0.5 — so this build is versionName 1.0.5, versionCode 11 (the 11th build of version 1.0.5). ::: **iOS** 1. Add the **Set Xcode Project Build Number** Step to your Workflow. 1. In the **Build Number** input, use `$BITRISE_BUILD_NUMBER` (this is the input's default value). 1. In the **Build Number Offset** input, set the value to add to the build number. This can be a fixed integer or an Environment Variable. :::tip[Offsetting an iOS app's version example] Let’s say you're about to run your app's fifth build on Bitrise, and the app already had six builds before you started using Bitrise. To keep the build number continuous: - Build Number: `$BITRISE_BUILD_NUMBER` - Build Number Offset: `6` - Version Number: `1.1` `$BITRISE_BUILD_NUMBER` (5, in this example) is added to the Build Number Offset (6), so CFBundleVersion is set to 11. CFBundleShortVersionString isn't affected by the offset and stays 1.1 — so this build is version 1.1, build 11. ::: --- ## Build statuses On the **Builds** page of a project, you can track the current status of all your builds. There are six different build statuses: - **On hold**: There are more builds started than what your current plan allows. In most cases, this is only relevant for legacy, concurrency-based plans: it means you don't have enough concurrency to start another build. :::note[Time limit] All builds on hold are aborted after 30 days to ensure no build gets permanently stuck. ::: - **Starting**: When a build is triggered, Bitrise creates a virtual machine to run it. If computing resources aren’t immediately available, the build is placed in a queue. Once a worker is available, the worker assigned to create the virtual machine is processing the build request. - **Running**: Once a virtual machine is ready to go, the build starts running. This means that Bitrise is executing all the Steps defined in your Workflow. - **Aborted**: A build can be aborted manually by the user, or automatically either by the [Rolling builds feature](/bitrise-ci/configure-builds/configuring-build-settings/rolling-builds) or because your build time has run out. :::note[Aborted with success] There is a specific status called Aborted with success: this means the build has been aborted by the API but it is reported as a success to your git hosting provider. Use the abort_with_success parameter with [a Bitrise API call to abort a build](/bitrise-ci/api/triggering-and-aborting-builds#aborting-a-build) but still count it as a successful one. ::: - **Failed**: In most cases, a build fails if any of the Steps fails. There are exceptions, such as the [caching Steps](/bitrise-ci/dependencies-and-caching/key-based-caching/using-key-based-caching), and you can [mark Steps as skippable](https://support.bitrise.io/hc/en-us/articles/4405252562577) which means even if they fail, the build will keep running. - **Success**: If Bitrise successfully executes all Steps that aren’t marked as skippable, the build is marked as successful. You can always check your build status on the **Builds** page of the project, and you can send status reports: [Reporting the build status to your Git hosting provider](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider) --- ## About build triggers Use build triggers to start one or more Bitrise builds automatically. A trigger's definition contains a code event and one or more conditions that the event must match in order to trigger a build. You can define triggers within a Workflow or a Pipeline. They allow a single code event to trigger multiple different Workflows or Pipelines so you can run all the relevant parts of your CI process together based on the scope of code change, without bundling everything into a single Workflow or Pipeline. Each build will run independently and deliver individual results. For the detailed syntax of triggers and the exact trigger conditions, see [YAML syntax for build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers). ### Code events You can use three types of code events to trigger builds: - **Code push**: Trigger a build automatically whenever you push code using commits that match your trigger conditions. For example, a commit to the specified branch of the project's repository triggers a build. - **Pull request**: Trigger a build automatically whenever a pull request matches your trigger conditions. For example, you can specify source and/or destination branches where any pull request will trigger a build. :::important[Initial PR event] A pull request only triggers a build once, at its initial event. In most cases, that initial event is the creation of the pull request. For example, converting a PR to a draft PR will never trigger another build. To trigger builds for updates to a pull request, configure code push triggers for the new commits. ::: - [**Git Tag**](https://github.com/Itelios/bitrise-steps-git-tag): Trigger a build automatically whenever a commit with a specific tag triggers a build. ### Conditions A trigger condition is a filter for code events: instead of triggering a build on every pull request, you can configure triggers for pull requests targeting a specific branch. Different Git providers support different conditions. For the full table, see [Supported trigger conditions](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers#supported-trigger-conditions). Trigger conditions can be combined within a single trigger: for example, you can set up a pull request trigger that only triggers a build if the PR targets a specific branch AND contains a specific label. ### Trigger priority Triggers can be assigned a priority setting: this determines the priority of a build triggered by a specific trigger. The higher the priority, the higher the build is in the build queue. You can assign a priority either in the Workflow Editor or in the configuration YAML file of your project. The priority is always an integer between -100 and 100: the higher the number, the higher the priority. The default priority is 0. For more information about build priority, and the order of precedence between different types of priorities, check out [Build priority](/bitrise-ci/configure-builds/configuring-build-settings/build-priority). ### Trigger variables A number of Environment Variables related to build triggers are available during an automatically triggered build. These variables can give detailed context about build triggers and pull request attributes. Use these trigger variables to: - Use pull request data, such as comments, labels, and changed files, to automate complex workflows and decision-making processes. - Understand who and how your builds are triggered and use that to better debug your workflows - Implement precise build conditions to reduce unnecessary runs, saving time and resources. You can find all trigger variables and their definition in our reference table: [Available environment variables](/bitrise-ci/references/available-environment-variables). Trigger variables are only available if the requirements are met. For example, the BITRISE_GIT_PULL_REQUEST_COMMENT variable is only available if the build is triggered by a PR comment; in other words, the build trigger has a `pr_comment` condition. You can find the exact conditions in [Available environment variables](/bitrise-ci/references/available-environment-variables). #### Use cases for trigger variables Here are some example use cases for trigger variables. These are merely suggestions: you can experiment with variables to find what suits your needs best. **Reporting back to the PR comment** BITRISE_GIT_PULL_REQUEST_COMMENT_ID: Use the pull request comment ID to post a status update directly to the original comment on the pull request. This can include details such as success, failure, logs, or any other relevant information. **Conditional test execution** BITRISE_GIT_CHANGED_FILES : Identify modified parts of the codebase and based on these changes, trigger specific test suites, such as running frontend tests for UI changes and backend tests for API modifications. **Deploying to different environments based on commit messages or labels** Use BITRISE_GIT_COMMIT_MESSAGES and BITRISE_GIT_PULL_REQUEST_LABELS to determine the deployment environment. For instance, if a commit message includes "[staging]" or a label "ready-for-staging" is present, deploy the code to the staging environment. ### Merge queue support GitHub Merge Queues allow multiple pull requests (PRs) to be merged automatically into a branch. You can verify the changes in each PR with a Bitrise build by setting up a trigger with `gh-readonly-queue/*` as the branch filter. You can read more about this prefix in the [GitHub documentation](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue#triggering-merge-group-checks-with-third-party-ci-providers). The merge queue will only function correctly if your builds, triggered for the queue, report the same status names as the PR builds. For example, with the configuration below, all branches that are merged from a merge queue, trigger a build with the `ci-pipeline` Pipeline: ```yaml pipelines: ci-pipeline: triggers: push: - branch: "gh-readonly-queue/*" status_report_name: ci/bitrise//pr ``` ### GitHub stacked pull requests A [GitHub stack](https://docs.github.com/en/pull-requests/get-started/about-stacked-prs) splits a large change into a series of smaller, ordered pull requests. Each pull request in the stack targets the branch of the pull request below it, and the whole stack lands on a single base branch. For example, a stack of three pull requests could look like this: - `feature/part-1` targets `main`. - `feature/part-2` targets `feature/part-1`. - `feature/part-3` targets `feature/part-2`. All three pull requests ultimately land on `main`. - Triggers match the target branch condition against the base branch of the stack (`main` in the example above), not against the branch a pull request targets directly. Set `target_branch: main` in your pull request trigger, not `feature/part-1` or `feature/part-2`. - `$BITRISEIO_GIT_BRANCH_DEST` holds the base branch of the stack (`main`) for every pull request in the stack. --- ## Configuring build triggers :::important[Existing trigger configurations] This page details information about target-based build triggers, defined within a Workflow or a Pipeline. We recommend this approach for all new users as it offers a more granular and flexible build trigger system. Existing configurations might use legacy, project-based triggers. Read more about them: [Legacy project-based triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/legacy-project-based-triggers). ::: ### Creating build triggers You create build triggers directly in a Workflow or Pipeline. Such triggers allow a single code event to trigger multiple Workflows or Pipelines. You can create triggers via the UI or in the configuration YAML file. To create triggers: **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Select a Workflow. 1. Select the **Triggers** tab on the Workflow's page. ![trigger-in-workflow.png](/img/_paligo/uuid-fcb0bba9-a8a5-e874-c5ba-a5e0f08d8a80.png) 1. Select the trigger type and click the **Add trigger** button. 1. Configure your trigger in the dialog. Click the regex pattern button to turn on regular expressions when defining a value for the trigger condition. ![regex-button.png](/img/_paligo/uuid-2106af45-7e79-2a1c-5974-9a8f0bb78ffe.png) 1. When done, click **Add trigger**. **Configuration YAML** 1. Open your configuration YAML file. 1. Find the Workflow. 1. In the Workflow, add a `triggers` property. ```yaml my-workflow: triggers: ``` 1. Create your triggers. You can find the exact syntax for the different trigger types here: [YAML syntax for build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers). For example, this trigger starts a build with the Workflow called `my-workflow`: ```yaml my-workflow: triggers: push: - commit_message: your_message ``` You can use two properties for pattern matching: - `pattern` allows you to use simple wildcard matching. - `regex` allows you to use complex pattern matching with regular expressions. ```yaml my_awesome_workflow triggers: push: - branch: main - commit_message: pattern: "hello" last_commit: true pull_request: - source_branch: "*" ``` 1. Save the configuration. #### Adding a new target-based trigger on the Triggers page You can quickly add new target-based triggers without leaving the **Triggers** page. For example, after reviewing your active triggers, you can immediately add another one without switching context, speeding up your setup process. 1. Go to your project's **Triggers** page. 1. If you don't have triggers yet, you’ll see a new **Add Trigger** button in the middle on the **Triggers** page. Click **Add trigger** and fill out the dialog. ![addnewtrigger.png](/img/_paligo/uuid-2d246b3d-6d4f-d215-8ee7-7d628492f7aa.png) 1. If you already have target-based triggers, the **add trigger** button is above the triggers in the top-right corner. Click **add trigger** and fill out the dialog. ![addanothertrigger.png](/img/_paligo/uuid-8a1664ba-48bd-f04b-5453-60cd9641e2ca.png) Adding a trigger here creates a specific workflow, which then appears under that workflow’s **Triggers** tab on the **Workflows** page for easy management. ### Disabling a trigger You can temporarily disable any build trigger. A disabled trigger doesn't trigger builds but retains all configuration information. You can reactivate a disabled trigger at any time. To disable a build trigger: **Workflow Editor** 1. Open the Workflow Editor on Bitrise. 1. Select a Workflow or Pipeline. 1. On the Workflow page, select the **Triggers** tab. ![workflow-properties.png](/img/_paligo/uuid-7755ec1f-eb8f-5036-05b3-be1b330f2143.png) 1. Find the trigger you need and click the options menu (⋮) next to its name. ![workflow-properties-ellipsis.png](/img/_paligo/uuid-3ab9024b-207a-0b06-c099-714f8c053ecd.png) 1. Select **Disable trigger**. **Configuration YAML** 1. Open your configuration YAML file. 1. Find the Workflow or Pipeline and its `triggers` property. 1. Add `enabled: false` to the trigger you want to disable. ```yaml triggers: push: - branch: main enabled: false ``` ### Creating a trigger for the most recent Git commit By default, when using the **Commit message** or **File change** condition in a code push trigger, Bitrise evaluates all commit messages and all changed files included in a single code push. However, you can configure your triggers to evaluate only the last commit in a push. If a push contains multiple commits, only the most recent one will be evaluated. **Workflow Editor** 1. [Create a new push trigger](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers#creating-build-triggers). 1. Select either the **Commit message** or the **File change** condition. ![last-commit.png](/img/_paligo/uuid-31ba9329-7c53-4411-103e-df47df050799.png) 1. Under the condition, enable **Last commit only**. **Configuration YAML** 1. Open your configuration YAML file and go to a Workflow. 1. Add a new push trigger. In the example, we're using the `commit_message` condition. ```yaml my-workflow: triggers: push: - commit_message: your_message ``` 1. Add the `last_commit` property and set it to `true`. ```yaml my-workflow: triggers: push: - commit_message: your_message last_commit: true ``` ### Triggering builds from draft PRs GitHub and GitLab offers a feature called [draft pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests) (or merge request in the case of GitLab): when you create a pull request (PR), you can choose to create a pull request that is ready for review or a draft pull request. Draft pull requests cannot be merged, and code owners are not automatically requested to review draft pull requests. :::important[Git provider limitations] This feature is only supported for GitHub and GitLab repositories. ::: By default, opening a draft PR triggers builds. You can disable this at any time. If opening a draft PR triggers a build, submitting it for review (converting it to "full" PR, in other words) will not trigger another. You can check out the exact code events that trigger builds depending on the draft PR trigger settings: [Build trigger behavior for draft PRs](#build-trigger-behavior-for-draft-prs). Each separate trigger has its own toggle: you can configure your app so that certain triggers start a build from draft PRs while other triggers don't. #### Disabling builds from a draft PR :::tip[Skipping Steps if a build is triggered by a draft PR] This guide tells you how to disable triggering builds from a draft PR altogether. You can, however, also skip certain Steps in a build that is triggered by a draft pull request. You just need to use a `run_if` condition and the GITHUB_PR_IS_DRAFT Environment Variable: for more information, see [Enabling or disabling a Step conditionally](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally). ::: **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Open your Workflow and select the **Triggers** tab. If you have a Pipeline, you can only disable the setting in the configuration YAML file. 1. Find the trigger you need and click the options menu (⋮) next to its name. 1. Select **Edit trigger** from the menu. ![edit-trigger.png](/img/_paligo/uuid-7e1fea02-d6ed-650a-043c-d8bb81c5f98e.png) 1. Uncheck the **Include draft pull requests** option and click **Apply changes**. **Configuration YAML** 1. Open your configuration YAML file. 1. Find the `triggers` element in all Workflows or Pipelines you want to modify. 1. Add `draft_enabled: false` to the trigger entries you need. ```yaml triggers: pull_request: - target_branch: "develop" draft_enabled: false - target_branch: "main" draft_enabled: false - comment: 'run Bitrise' ``` This will start workflows for non-draft PRs against the develop branch and the main branch, or anytime `run Bitrise` is commented on any PR. #### Build trigger behavior for draft PRs The table shows whether a build is triggered when a specific action is performed regarding draft PRs, depending on the draft PR trigger settings. For example, converting a draft PR to a PR doesn't trigger a build if the draft PR trigger is enabled but it does trigger a build when it's disabled. | Action | Draft PR trigger is enabled | Draft PR trigger is disabled | | --- | --- | --- | | Open a draft PR | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Push a commit to a draft PR | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Convert a draft PR to PR | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Convert PR to draft PR | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ### Supported trigger conditions Not all trigger conditions are available for all Git providers. As a general rule, all our trigger conditions are available for the cloud service of the three most frequently used Git providers: GitHub, GitLab, and Bitbucket. For other providers, or self-hosted Git repositories, check out the detailed table for both push triggers and pull request triggers. #### Push trigger conditions | Git provider | Branch | Commit message | Files changed | | --- | --- | --- | --- | | GitHub (cloud and self-hosted) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | GitLab (cloud and self-hosted) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Bitbucket (cloud and self-hosted) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Assembla | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Deveo (Perforce) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Gogs | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Azure DevOps | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | #### Pull request trigger conditions | Git provider | Source branch | Target branch | Labels | Comments | Commit message | Changed files | | --- | --- | --- | --- | --- | --- | --- | | GitHub (cloud and self-hosted) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | GitLab (cloud and self-hosted) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Bitbucket (cloud and self-hosted) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | N/A | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Assembla | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | N/A | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Deveo (Perforce) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Gogs | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Azure DevOps | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | :::note[No pull request triggers for Assembla, Deveo, and Gogs] Assembla, Deveo (Perforce), and Gogs only support push-based triggers. Pull request triggers aren't available for these providers. ::: :::important[GitHub stacked pull requests] For a pull request in a [GitHub stack](https://docs.github.com/en/pull-requests/get-started/about-stacked-prs), Bitrise matches the target branch condition against the base branch of the stack, not against the branch the pull request targets directly. Take a stack where `feature/part-2` targets `feature/part-1`, and the whole stack lands on `main`. A `target_branch: main` condition matches every pull request in the stack. A condition set to `feature/part-1` matches none of them. ::: --- ## Legacy project-based triggers :::important[Legacy triggers] This page is about legacy triggers that are defined on a project level. For new users, we strongly recommend using the target-based build triggers which are defined on the level of Workflows and Pipelines as they allow more flexibility in designing your triggers: [Configuring build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers). ::: Legacy or project-based triggers are defined on the project level: that is, the top level of your configuration YAML file. The trigger defines which Workflow or Pipeline should run when a given code event happens. A single code event can only trigger a single build. ### Creating project-based triggers Project-based triggers are defined on the project level: that is, the top level of your configuration YAML file. The trigger defines which Workflow or Pipeline should run when a given code event happens. A single code event can only trigger a single build. **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Triggers**. 1. Find the **Legacy triggers** section. ![Legacy triggers section on the Triggers page](/img/run-and-analyze-builds/2026-07-14-legacy-triggers-section.png) 1. Select the trigger type and click the **Add trigger** button. For example, if you want to set up a trigger for pull request events, select the Pull Request tab and click the **Add pull request trigger** button. 1. Configure your trigger in the dialog. When setting multiple conditions, all conditions must be fulfilled for a build to start. You can use regular expressions for any of the condition types. You can find the full list of supported trigger conditions here: [Supported trigger conditions](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers#supported-trigger-conditions). 1. When done, click **Add trigger**. **Configuration YAML** 1. Open your configuration YAML file. 1. In the Workflow, find the `trigger_map` property and set up your trigger under it. You need: - A `type` property to define the type of the code event. - A trigger condition. For example, `commit_message`. - The Workflow or Pipeline you want to trigger. ```yaml trigger_map: - type: push commit_message: your_message workflow: my-workflow ``` You can find the exact syntax for the different trigger types here: [YAML syntax for build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers). 1. Save the configuration. ### Disabling a project-based trigger To disable a project-based build trigger: **Workflow Editor** 1. Open the Workflow Editor on Bitrise. 1. On the left, select **Triggers**. 1. Select the appropriate tab, depending on the trigger you want to deactivate. ![Legacy triggers tab with the Active checkbox on a trigger row](/img/run-and-analyze-builds/2026-07-14-legacy-triggers-active-checkbox.png) 1. Uncheck the **Active** checkbox to disable the trigger. **Configuration YAML** 1. Open your configuration YAML file. 1. Find the `trigger_map` property and the trigger you want to disable. 1. Add `enabled: false` to it. ```yaml trigger_map: - type: push push_branch: main workflow: primary enabled: false ``` ### Project-based trigger syntax A project-based trigger has three main elements in its YAML syntax: - The type of the trigger: `push`, `pull_request`, or `tag`. - The trigger condition. For example, the source branch of a pull request. - The Workflow or Pipeline to be triggered. One trigger means one build: a single project-based trigger can only trigger a single Workflow or Pipeline. You can [chain Workflows together](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#chaining-workflows-together) run several Workflows in succession from a single trigger. Below is a single trigger that triggers a build with the `primary` Workflow when a pull request is opened from any branch. ```yaml trigger_map: - pull_request_source_branch: "*" type: pull_request workflow: primary ``` #### Multiple matching triggers For project-based triggers, the first trigger with matching conditions triggers a build. This means the order of the triggers is important: ```yaml trigger_map: - type: push push_branch: main workflow: primary - type: push commit_message: deploy workflow: deploy ``` The first trigger triggers the `primary` Workflow if code is pushed to the `main` branch of the app's repository. The second trigger triggers the `deploy` Workflow if a commit with the commit message `deploy` is pushed to any branch of the repository. What happens when a commit is pushed to the `main` branch with the commit message `deploy`? The commit matches all conditions of the first trigger so the `primary` Workflow is triggered. In this scenario, the `deploy` Workflow is NOT triggered, even though the commit matches all conditions of that trigger, too. #### Multiple trigger conditions If you define multiple trigger conditions in a single project-based trigger then all conditions have to match in order to trigger a build. For example: ```yaml trigger_map: - pull_request_target_branch: "main" pull_request_source_branch: "develop" type: pull_request workflow: primary ``` This will only select the `primary` workflow if the pull request’s source branch is `develop` AND the target branch is `main`. ### Project-based trigger components The components listed on this page are valid for legacy, project-based triggers. | Component | Description | Accepted values | Default value | | --- | --- | --- | --- | | `type` | Defines the type of a project-based trigger. A trigger with a given type only accepts trigger conditions belonging to that type. | - `push` - `pull_request` - `tag` | N/A | | `enabled` | A boolean property that defines if the trigger is currently active. | - `true` - `false` | `true` | | `workflow` or `pipeline` | The Workflow or Pipeline that is triggered. You can't set both. | The exact name of the Workflow or Pipeline. | N/A | | Component | Description | Default value | | --- | --- | --- | | `push_branch` | The branch of the repository where code is pushed to trigger a build. | `*` | | `commit_message` | The commit message to trigger a build. | `*` | | `changed_files` | The path to a file or folder where changes should trigger a build. | `*` | | Component | Description | Default value | | --- | --- | --- | | `pull_request_source_branch` | The branch of from which the pull request is opened. | `*` | | `pull_request_target_branch` | The branch which is the merge target of the pull request. For a pull request in a GitHub stack, Bitrise matches this against the base branch of the stack. | `*` | | `pull_request_label` | The pull request label. | `*` | | `draft_pull_request_enabled` | A boolean property that defines if draft pull requests trigger builds. | `true` | | `pull_request_comment` | A comment posted on a pull request. | `*` | | `commit_message` | A specific commit message in pushes to a pull request. | `*` | | `changed_files` | Specific files that are modified in a pull request. | `*` | | Component | Description | Default value | | --- | --- | --- | | `tag` | The value of the tag. Accepts a string value or a `regex` property. | `*` | --- ## Skipping a given commit or pull request Depending on your settings, every code change in your repository can trigger Bitrise builds. However, if you need to, you can skip a specific commit or pull request. Skipping means, in this context, that a code change will NOT trigger a build on Bitrise, even if the triggers are set up to do so. :::caution[Skipped builds and required checks] Skipping a build means Bitrise reports no status to your Git provider. If you have a required status check in your branch protection rules, a skipped build leaves that check pending and the pull request can't be merged. To pass a required check on pull requests that shouldn't trigger a build, such as documentation-only changes, route them to a Pipeline that reports the required check without running a build. For details, see [Passing a required check on documentation-only pull requests](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider#passing-a-required-check-on-documentation-only-pull-requests). ::: ### Preventing a commit from triggering a build To make sure a specific commit does not trigger a build, include either `[skip ci]` or `[ci skip]` in the commit message: ```text This is not important, please [skip ci] ``` Or: ```text I just changed the README [ci skip] ``` :::warning[Only the head/last commit message is checked!] If you push more than one commit, only the last (head) commit’s message will be checked for the `skip ci` pattern! ::: If you do want to start a build after all, you have two choices: - Rebase the commit (change the commit message). - Push another commit. :::tip[Pushing an empty commit] Git allows to create and push empty commits. If you want to build a skipped build you can do `git commit --allow-empty -m "I decided to run this"` on the related branch and push the commit. ::: ### Preventing a pull request from triggering a build Pull requests are treated as (virtual) commits themselves, where the commit message is the title + description of the pull request. It is *not* the commit messages of the individual commits that make up the pull request. To skip a pull request include the `[skip ci]` pattern in the pull request’s title or its description. :::important[Individual commit messages are not checked] Putting the `[skip ci]` pattern in the commit message of individual commits that make up the pull request will not work: the pull request will trigger a build if the appropriate trigger is set up. ::: Once you decide to not to skip the pull request, you can simply remove the `[skip ci]` pattern from the pull request’s title or description. This should automatically trigger a new build with the latest commit, and all future commits of the pull request will be built too (unless you add a `[skip ci]` pattern again). ### Skipping Steps triggered by a draft PR When you use the [draft PR function of GitHub](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests), Bitrise inserts an Environment Variable called `GITHUB_PR_IS_DRAFT` into the build Environment Variable list. If this Env Var is available in your build Env Var list, its value is always set to `true`. You can use the `GITHUB_PR_IS_DRAFT` Env Var in your build as part of a conditional: for example, you can skip certain Steps in builds that are triggered by draft PRs: ```yaml workflow1: steps: - script: run_if: '{{enveq "GITHUB_PR_IS_DRAFT" ""}}' inputs: - content: |- #!/usr/bin/env bash # fail if any commands fails set -e # debug log set -x ``` In this example, the `run_if` condition means that the Step will only run if the build is NOT triggered by a draft PR. Yo recommend that you insert below `run_if` command to each Step in your Workflow to skip the Steps. :::note[Starting a new build after a draft PR] Clicking the **Ready for review** button on GitHub only triggers a new build on Bitrise if builds from draft pull requests are disabled. If draft pull requests are enabled to trigger builds and a specific draft pull request already triggered a build, submitting it for review won't trigger a new build. Any previous builds will also contain the draft PR related Env Vars. In this case, we recommend you manually start a brand new build from the website or trigger the CI with a new commit. ::: ### Skipping Bitrise CI If you manage multi-vendor or multi-platform CI workflows, you might want to skip builds on multiple systems or just on Bitrise. To skip builds on multiple vendors, use the `skip ci` or `ci skip` keywords. To skip builds on Bitrise only, use the `skip bitrise` or the `bitrise skip` keywords in your commit messages to prevent Bitrise builds from triggering. With these Bitrise-specific skip keywords, you get finer granularity and avoid unintentionally skipping builds on other parts of your CI pipeline. ### Skipping a comment PR comments can trigger builds but if you want to prevent that, you can skip a build by adding `[skip ci]` / `[ci skip]` or `[skip bitrise]` /`[bitrise skip]` in the build's PR comments. If you use tools that automatically comment on PRs and that starts a build, configure your tool to include a skip command in its comments. --- ## Starting parallel builds with a single trigger :::tip[Using Build Pipelines to start parallel builds with a single trigger] If you have a credit-based account and you are planning on running multiple tasks parallel with a single trigger, we recommend using Build Pipelines. For more information, check out [Build Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/pipelines-with-stages/configuring-a-pipeline-with-stages). ::: If you have more than one concurrency or you have a credit-based account, you can run more than one build simultaneously. And since we want to make life as easy for you as possible, these builds can be started automatically, with a single trigger. Let’s go through how it works! In the example, we have three Workflows of a single app set up to run at the same time. Let’s call these Workflows **Trigger**, **Building** and **Testing**. The workflow called **Trigger** will be triggered by a pull request, and then the workflow will trigger **Building** and **Testing** which will run simultaneously. All workflows run on separate, clean Virtual Machines. They can also run on different types of stacks: to choose the stack for any Workflow, go to the Workflow Editor of the app and select the **Stack** tab. If any of the builds fail, the build will be considered a failed build. If the build is triggered by a webhook, Bitrise will send [a summarized build result](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider) to your Git provider. If any of the parallel builds fail, a failed status will be reported. :::important[No reports for "child" builds] Bitrise will send a Git status report only for the original "parent" build, the one that triggered all the other builds. The "child" builds will not send back status reports to your Git provider! For example, if build A triggers builds B and C, a status report will be sent once A is finished. There will be no separate status reports for builds B and C, however. ::: What you need: - A Personal Access Token. - A Secret Environment Variable storing the token. - The **Bitrise Start Build** Step. - The **Bitrise Wait for Build** Step. :::important[Bitrise Start Build Step on the CI] Since the **Bitrise Build Start** Step heavily relies on the parameters of the currently running build (for example, the app slug, build slug and the build number) to call the [see topic](urn:resource:component:43135), you cannot use the **Bitrise Build Start** Step locally. ::: :::tip[bitrise.yml example] You can edit your `bitrise.yml` file on the **bitrise.yml** tab of the Workflow Editor, or you can edit the file locally. The example below focuses on the Bitrise UI, but if you prefer to use YAML format, [check out our example](#bitriseyml-example)! ::: 1. Create a **Personal Access Token** for your user. Go to **Profile Settings** and select the **Security** option on the left side. Click the **Generate new** button. ![Starting_parallel_builds_with_a_single_trigger.png](/img/_paligo/uuid-35a66242-8cc5-8b66-380d-a996c3012825.png) :::warning[Copying the token] Make sure the copy the token once it's generated: you won't be able to see it again! ::: 1. Create a Secret Environment Variable on the **Secrets** tab of the app’s Workflow Editor and add the token as its value. ![Starting_parallel_builds_with_a_single_trigger.png](/img/_paligo/uuid-d85ee7fd-2f40-5ae8-34ce-c79f638f3879.png) Feel free to use any key you wish for the secret. We recommend something simple like $ACCESS_TOKEN. 1. Add the **Bitrise Start Build** Step to the **Trigger** Workflow. Note that the **Bitrise Start Build** Step will set an Environment Variable to all builds it starts: $SOURCE_BITRISE_BUILD_NUMBER. Each build triggered by the Step will have their own build numbers but the source build number will be the same for all of them. 1. Add the secret env storing your personal access token to the **Bitrise Access Token** input of the Step: click the **Select secret variable** button and choose the key you created. ![Starting_parallel_builds_with_a_single_trigger.png](/img/_paligo/uuid-f9f9d575-5b1f-73c1-53ae-94ae13e0da3f.png) 1. Find the **Workflows** input of the Step, and add `Building` and `Testing` to it. ![Starting_parallel_builds_with_a_single_trigger.png](/img/_paligo/uuid-41d604b4-d929-893c-2ac9-aa44b3e01e85.png) 1. Add the **Bitrise Wait for Build** Step as the last Step of the **Trigger** Workflow. :::important[Checking build statuses] The Step checks statuses of the builds defined in the Step. The builds are defined in the **Build slugs** input: the slugs are the output of the **Bitrise Start Build** Step. As long as the builds defined by the slugs are running, the Step will hold the build it is running in. The build will fail if any of the builds included in the Step fail. ::: 1. Add the secret env storing your personal access token to the **Bitrise Access Token** input of the Step: click the **Select secret variable** button and choose the key you created. ![Starting_parallel_builds_with_a_single_trigger.png](/img/_paligo/uuid-ed66ae06-8ebc-cb93-e3e3-ce6c2e94b1de.png) And you are done! Once you trigger the **Trigger** workflow, the **Bitrise Start Build** Step of the Workflow will trigger two more builds running simultaneously. If those two builds are successful, the **Bitrise Wait for Build** Step lets the first build finish. A single status report is sent to the git hosting provider, regardless whether the build is successful or not. ### bitrise.yml example ```yaml Trigger: steps: - build-router-start@0: inputs: - workflows: |- Building Testing - access_token: "$BITRISE_API_KEY" - build-router-wait@0: inputs: - access_token: "$BITRISE_API_KEY" ``` --- ## Triggering builds by Slack commands You can trigger Bitrise builds from your Slack workspace by configuring [Slash Commands](https://api.slack.com/interactivity/slash-commands) in your Slack apps. Each Bitrise app needs its own Slash Command. 1. Register the Bitrise webhook URL to your Slack app. :::note[Slack app reinstall] Creating a new Slash Command might require a reinstall of your Slack app. ::: 1. Use the command by adding at least the two required parameters to it: `workflow` and `branch`. ```text /build-myapp workflow: run_tests|branch: main ``` You can set a number of different parameters in the command call, including a commit hash, and any [Environment Variables](/bitrise-ci/configure-builds/environment-variables) that you want to pass on to the build. For more information on the available parameters, check out [Available parameters for Slack commands](/bitrise-ci/run-and-analyze-builds/build-triggers/triggering-builds-by-slack-commands#available-parameters-for-your-slack-command). ### Available parameters for your Slack command To trigger builds via Slack, you need to amend your Slash Command with parameters in a `key:value|key:value` format. You must specify at least one parameter: - `b` or `branch`. For example, `branch: main` - `w` or `workflow`. For example, `workflow: run_tests` Without specifying either branch or Workflow in your command, the command will fail. The optional parameters allow further configuration of your build: - `t` or `tag`. For example, `branch: main|tag: v1.0` - `c` or `commit`. For example, `workflow: run_tests|commit: eee55509f16e7715bdb43308bb55e8736da4e21e` - `m` or `message`. For example, `branch: main|message: ship it!!` You can also send environment variables that will be available in your Workflow with the format: `env[KEY1]:value1|ENV[KEY2]:value2` **Slack command with all parameters included** The example includes all parameters, required and optional. It builds a specific commit and passes two Environment Variables to the build: - $DEVICE_NAME with the value of `iPhone 6S`. - $DEVICE_UDID with the value of `82667b4079914d4aabed9c216620da5dedab630a` ```text /build-myapp workflow: run_tests|b: main|tag: v1.0|commit:eee55509f16e7715bdb43308bb55e8736da4e21e|m: start my build!|ENV[DEVICE_NAME]:iPhone 6S|ENV[DEVICE_UDID]:82667b4079914d4aabed9c216620da5dedab630a ``` --- ## YAML syntax for build triggers :::important[Existing trigger configurations] This page details information about target-based build triggers, defined within a Workflow or a Pipeline. We recommend this approach for all new users as it offers a more granular and flexible build trigger system. Existing configurations might use legacy, project-based triggers. Read more about them: [Legacy project-based triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/legacy-project-based-triggers). ::: The configuration YAML files contain the definitions for build triggers. You can configure them directly in YAML without having to use the online Workflow Editor. ### Trigger syntax Triggers must be included in a `triggers` element within a Workflow or Pipeline. A valid trigger in the `triggers` element includes the type of the trigger and at least one trigger condition. For example, the below trigger launches a build when code is pushed to the `release` branch. ```yaml workflows: pipeline-tests: triggers: push: - branch: "release" ``` #### Multiple matching triggers We parse all triggers in a configuration YAML and start builds with all matching triggers. This means the order of the triggers doesn't matter. For example, if you have two Workflows with `push` triggers with the same `branch` condition, both will be triggered when a commit is pushed to that branch. In the configuration below, both triggers will launch a build if a commit is pushed to the `release` branch: - The `pipeline-tests` Workflow specifies the `release` branch. - The `pipeline-build` Workflow uses [a wildcard](#wildcards-and-regex) so any commit triggers a build with it. ```yaml workflows: pipeline-tests: triggers: push: - branch: "release" [...] pipeline-build: triggers: push: - branch: "*" ``` #### Multiple trigger conditions If you define multiple trigger conditions, all of them must match to trigger a build. In the example below, a build will be triggered if: - A commit is pushed to the `release` branch. - Certain files have changed in the commit. ```yaml workflows: pipeline-builds: triggers: push: - branch: release changed_files: path/to/library-a/.* ``` #### Wildcards and regex We support wildcards (`*`) for simple text matching within all types of triggers. Wildcards are a good choice when you don't need the advanced pattern matching capabilities of regular expressions. For example, a trigger based on commit messages starting with `fix` can be achieved using a wildcard. We recommend using the `pattern` property to achieve this: ```yaml my_awesome_workflow triggers: push: - branch: main - commit_message: pattern: "hello" ``` :::note[Alternative syntax] You can also add your wildcard pattern right next to the `commit_message` field: `commit_message: "hello"`. We’ll continue to support this syntax. ::: Wildcards are useful to match specific, fixed values appearing in the input. We recommend using regexes are needed when multiple alternative values, negation, capturing specific groups of characters or specific character types (for example, numbers only) are needed. To use regular expressions for a trigger condition, you need to add `regex:` to its value: ```yaml workflows: deploy: triggers: tag: - name: regex: '^\d\.\d\.\d$' pull_request: - comment: "[workflow: deploy]" commit_message: regex: '.*\[workflow: deploy\].*' ``` ### Trigger components | Component | Description | Accepted values | Default value | | --- | --- | --- | --- | | `pull request` `push` `tag` | Defines the type of a trigger. The trigger conditions of a target-based trigger are children of these elements. | N/A | N/A | | `enabled` | A boolean property that defines if the trigger is currently active. | - `true` - `false` | `true` | | Component | Description | Default value | | --- | --- | --- | | `branch` | The branch of the repository where code is pushed to trigger a build. | `*` | | `commit_message` | The commit message to trigger a build. | `*` | | `changed_files` | The path to a file or folder where changes should trigger a build. | `*` | | `last_commit` | A boolean property that defines whether Bitrise should evaluate every commit message or changed file in a code push or only those belonging to the most recent commit. | `false` | | Component | Description | Default value | | --- | --- | --- | | `source_branch` | The branch of from which the pull request is opened. | `*` | | `target_branch` | The branch which is the merge target of the pull request. | `*` | | `label` | The pull request label. | `*` | | `draft_enabled` | A boolean property that defines if draft pull requests trigger builds. | `true` | | `comment` | A comment posted on a pull request. | `*` | | `commit_message` | A specific commit message in pushes to a pull request. | `*` | | `changed_files` | Specific files that are modified in a pull request. | `*` | :::important[GitHub stacked pull requests] For a pull request in a [GitHub stack](https://docs.github.com/en/pull-requests/get-started/about-stacked-prs), Bitrise matches the target branch condition against the base branch of the stack, not against the branch the pull request targets directly. Take a stack where `feature/part-2` targets `feature/part-1`, and the whole stack lands on `main`. A `target_branch: main` condition matches every pull request in the stack. A condition set to `feature/part-1` matches none of them. ::: | Component | Description | Default value | | --- | --- | --- | | `name` | The value of the tag. Accepts a string value or a `regex` property. | `*` | --- ## Finding a specific build :::note[Build retention for 200 days] On the **Builds** page of your app, we only show builds from the last 200 days. The same limit applies if you are [searching for specific builds](/bitrise-ci/run-and-analyze-builds/finding-a-specific-build) on the page. This limitation also applies to most API calls: the `GET/apps/{app-slug}/builds` endpoint and related endpoints can only return builds from the last 200 days. However, there are two methods to get a build that is older than 200 days: - If you know the exact build URL, you can access the build. - You can use the `GET/apps/{app-slug}/archived-builds` API endpoint: [Listing the archived builds of an app](/bitrise-ci/api/managing-an-app-s-builds#listing-the-archived-builds-of-an-app). ::: If your project has multiple builds on [bitrise.io](https://www.bitrise.io) , you can search for a specific one by using a variety of options. To do so: 1. Open an project on Bitrise. 1. On the **Builds** page of the project, you can find the filter options and the search field above the list of builds. You have several options: - In the search field, enter either a build number or a commit message to find the build. ![builds-search.png](/img/_paligo/uuid-5447e1bd-56ac-3503-4473-18f9784a64bf.png) - Choose a filter from the date filter dropdown menu to find builds that ran within a specific date range. - Choose a filter from the branch filter dropdown menu to find builds that ran on a specific branch. - Choose a filter from the Workflow/Pipeline filter dropdown menu to find builds that ran with a specific Workflow or Pipeline. - Choose a filter from the status filter dropdown menu to find builds with a specific status. - Choose a filter from the triggers dropdown menu to find builds that were triggered by one of our trigger options: pushes, pull requests, or tags. - Choose a filter from the artifact type filter dropdown menu to find builds that produced a specific type of artifact. --- ## Artifact retention policy Bitrise stores both build artifacts and build logs for a limited amount of time. The retention period varies by artifact type to balance storage costs with typical usage patterns. You can download build artifacts via the Bitrise API in order to store them: [Managing build artifacts](/bitrise-ci/api/managing-build-artifacts). When artifacts are removed, they are permanently deleted with no way to recover them. :::note[Older artifacts] Artifacts created before 31 March 2026 will be subject to the old retention policy: 365 days for standards artifacts, installable artifacts, and pipeline intermediate files, and 7 days for HTML reports. ::: | Artifact Type | Retention Period | Custom retention period | | --- | --- | --- | | Builds and [build logs](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/build-logs) | 200 days Builds older than 200 days can still be accessed via the Bitrise API. | Unavailable | | [Test results and all non-installable artifacts](/bitrise-ci/testing/deploying-and-viewing-test-results) | 90 days | Available for Enterprise customers | | Installable artifacts (.ipa, .akp and .aab files) | 150 days | Available for Enterprise customers | | [HTML reports](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/viewing-html-reports) | 7 days | Unavailable | | Pipeline intermediate files | 7 days | Unavailable | | [CodePush](/release-management/codepush/about-codepush) packages | Retention limits are based upon size rather than age: your subscription plan determines the amount of storage you have. | Unavailable | ### Archiving artifacts to your own storage To keep artifacts beyond the retention period, archive them using the Bitrise API: 1. Generate a list of build artifacts to be archived: use `/apps/{app-slug}/builds` to generate a list of all the builds in one project. 1. For each build, list out all the artifacts for a given build using `/apps/{app-slug}/builds/{buildslug}/artifacts`. 1. For each artifact, get its download URL via `/apps/{app-slug}/builds/{buildslug}/artifacts/{artifact-slug}`. 1. Download each artifact using the list of download URLs. 1. Save all the artifacts in your storage of choice. ### Custom retention policies Custom retention policies are available for Enterprise customers. Contact your Customer Success Manager to discuss. - Shorter retention: Available at no additional cost (useful for reducing storage overhead). - Extended retention: Available for an additional fee. :::note[Standard and installable artifacts only] Custom retention periods only apply to standard artifacts and installable artifacts (not HTML reports or pipeline intermediate files). If you have multiple workspaces, you can apply your custom retention period across all of them, or request different retention periods for each one. ::: --- ## Build artifacts online Build artifacts are any files generated during a Bitrise build: test results, screenshots, executable binaries, and so on. You can view build artifacts at two places: - On the **Artifacts** tab of the build's page. Here you can view all artifacts. ![builds-artifacts-tab.png](/img/_paligo/uuid-447a76c6-96e0-a493-214d-484d92a36dc8.png) - The **Artifacts** page on the main page of the app. Here you can only see the installable binaries. ![installable-artifacts-2.png](/img/_paligo/uuid-ad094f49-47bd-4ee0-a1f3-899a5d2a61a4.png) There is no limitation on the number of files deployed to the **Artifacts** tab per build. There is a limitation, however, on the file size which is 2GB per file. ### The Installable artifacts page On the **Installable artifacts** page, you can: - View the installable binaries of past builds. - Download the installable artifacts. - Check the details page of these artifacts. This can include a [public install page](/bitrise-ci/deploying/ios-deployment/installing-an-ipa-file-from-the-public-install-page). To get to the page, log in to Bitrise, select the Workspace that owns the app, and open **Bitrise CI**. Select your app and you can see **Artifacts** on the left. You can filter your installable artifacts using several different filters: - Platform of your binary (iOS or Android). - The timeframe of the build that generated it. ![timeframe-artifacts.png](/img/_paligo/uuid-243b3111-76a9-8f92-b5aa-e345cf67e363.png) - The Workflow the build ran on. - The branch of the repository that was built. ### Artifact details You can check the details of any installable artifact (a binary, either an IPA or an APK/AAB file) generated by a Bitrise build. The details can potentially include: - The exact filename. - The version of the binary. - Metadata such as time of creation and file size. - A QR code for installation. - A link to the [public install page](/bitrise-ci/deploying/bitrise-ota-app-deployment#deploying-with-the-deploy-to-bitriseio-step) if it is enabled. To get to the details page, open the **Artifacts** page and select your file from the **Installable artifacts** list. ![CrossPlatform.png](/img/_paligo/uuid-3a873c33-52fb-926c-64d7-faeb23df7e64.png) On the details page itself, the most important thing you can do is install the app on a mobile device. This is particularly useful for testing purposes. You have two options: - A QR code: scan it to install the binary. - A link to the public install page. ![qr-code-install.png](/img/_paligo/uuid-6a389697-3c42-fd18-6bfb-c5c854e695d3.png) Note that if you're trying to install an iOS app on a device, the device must be registered for the app on the Apple Developer Portal. You can see the available devices in the **Who can install this app?** section. ### Deploying files into artifacts Artifacts are deployed into the **Artifacts** section in your build’s page with the help of the **Deploy to Bitrise.io** Step. It deploys all the files which have been generated during the build and stores them in the `$BITRISE_DEPLOY_DIR` directory. To deploy the artifacts, insert the **Deploy to Bitrise.io** Step AFTER the Step(s) that generate the artifacts or even better if the **Deploy to Bitrise.io** Step is at the very end of your Workflow. :::important[Put the Step in the right place] Add the **Deploy to Bitrise.io** Step in the right place. If you insert the Step before other Steps that generate files during the build, then **Deploy to Bitrise.io** will have nothing to deploy. ::: Note that the content of any sub-directories found in the deploy directory will not be displayed in the **Artifacts** section of your build. You can, however, compress your artifacts into a zip file if you modify the default `false` value to `true` in the **Compress the artifacts into one file** field in the **Deploy to Bitrise.io** Step. This will compress the whole directory along with its sub-directories and deploy to **Artifacts**. #### Modifying the target directory path You can modify the target directory path to another one but make sure you reference the same directory paths in other Steps of your Workflow to ensure that the generated files get collected to the same directory. #### Viewing artifacts if your build has failed With the **Run if previous Step failed** toggle enabled, you can access your build artifacts - only those that have been successfully generated - even if your build has failed. For example, you can detect bugs in your failed build by looking into the generated test report files. #### Who can access build artifacts? The artifacts at **Artifacts** are accessible for everyone who is the owner, admin, developer, tester/QA of the app. Besides these roles, if you keep the default config of the **Enable public page for the App** feature, then anyone who receives the URL, will be able to access your app and its artifacts. --- ## Uploading files for your builds If your build requires any files to make it work, you can upload them to Bitrise on the **Project settings** page. It accepts any file type, all you need to do is provide a unique ID and upload the file. Once a file is uploaded, it is stored [as an Environment Variable (Env Var)](/bitrise-ci/configure-builds/environment-variables). You can use this Env Var to access the file and use it in your builds. The file can also be: - Downloaded by anyone who has either [admin or owner role](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) on the app’s team on Bitrise. You can prevent this: [Protecting your uploaded files](#protecting-your-uploaded-files) - Exposed to pull request builds. :::important[File restrictions] There are certain restrictions on upload size and number of files: - You can't upload a file bigger than 5 MB. - You can only store a total of 100 different files at the same time. If you want to upload more, you need to delete one of the files in the storage. ::: To upload a file: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Files**. 1. Click **Add file**. 1. In the dialog box, enter a unique ID in the **File Storage ID** input field. The unique ID will be part of the generated download URL that Bitrise stores as an [Environment Variable](/bitrise-ci/configure-builds/environment-variables). ![Add file dialog on the Project settings Files page](/img/run-and-analyze-builds/2026-07-14-add-file-dialog.png) 1. Upload the file. You have two options: - Click anywhere in the **Select a file to upload** section and select the file from your computer. - Drag and drop a file into the **Select a file to upload** section. Remember that the file size cannot exceed 5 MB. ### Protecting your uploaded files Once you uploaded a file to Bitrise, you can set your uploaded files to Protected mode. This means that no one can download or reveal the file from your account but your builds can still use them. Bitrise will handle the Environment Variable attached to your uploaded files as a [Secret](/bitrise-ci/configure-builds/secrets). 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. ![project-settings-button.png](/img/_paligo/uuid-14defaa4-472c-2d09-84df-145dc3aef4f5.png) 1. On the left, select **Files**. 1. Click the horizontal ellipsis button next to the name of the file, and select **Make protected**. 1. Click **Make it protected** in the dialog box. --- ## Using encrypted files in your builds You can use encrypted files on Bitrise, easily and securely. All you need to do is encrypt the file on your computer, [upload it to the Generic File Storage](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds) and use the [**Decrypt file**](https://github.com/bitrise-steplib/bitrise-step-decrypt-file) Step or your own custom decrypting solution to decrypt it when you need it. :::note[GPG encryption] Please note that the [**Decrypt file**](https://github.com/bitrise-steplib/bitrise-step-decrypt-file) Step only decrypts files encrypted with GPG. If you use other encryption software, you will not be able to decrypt files using the Step. You can, of course, set up your own decryption solution in a [**Script**](https://github.com/bitrise-io/steps-script) Step. ::: ### Encrypting your files In this example, we’ll use the **pwgen** password generator tool and **GPG** as the encryption software to encrypt a file. 1. Open a Terminal/Command Line. 1. Create a 32 character passphrase for encryption. :::important[Keep the passphrase] You will need this passphrase to decrypt the file on Bitrise. ::: ```bash pwgen -s 32 1 ``` 1. Encrypt your file. In this example, the file is called `my_secret_file`. ```bash gpg -c my_secret_file ``` Optionally, you can encrypt your file(s) in a non-interactive way. ```bash gpg --batch --passphrase -c my_secret_file ``` ### Decrypting and downloading your files during a build After you successfully encrypted a file, you need to upload it to Bitrise and you need to be able to decrypt it during the build. In this procedure, we'll use the **Decrypt file** Step to decrypt the file. :::note[GPG encryption] Please note that the **Decrypt file** Step only decrypts files encrypted with GPG. If you use other encryption software, you will not be able to decrypt files using the Step. You can, of course, set up your own decryption solution in a **Script** Step. ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Go to the **Secrets** tab, and add your decryption passphrase as a [Secret](/bitrise-ci/configure-builds/secrets). 1. [Upload the file to Bitrise](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds) 1. Copy the Environment Variable (Env Var) under the name of the uploaded file. This Env Var stores the download URL for the file. 1. Go to the **Workflows** tab. 1. Open the Workflow Editor. 1. Add the **Decrypt file** Step to your Workflow. 1. Paste the Env Var of the file to the **Encrypted file path** input. 1. In the **Output file path** input, specify the path where you want to place the decrypted file. Subsequent Steps will be able to access the file at this path. :::tip[Using an Env Var as the input value] You can store the filepath in an App Env Var instead of specifying it directly for the input. That way you can refer to the file through the Env Var in other Steps, you won’t have to specify the path every time. For example, if you store the path in the `BITRISEIO_MY_FILE_LOCAL_PATH` Env Var, you can use it as the path for the input, and also use it to access the file in every subsequent Step. ::: **A bitrise.yml example for decrypting files** ```yaml --- format_version: '11' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: macos workflows: secret: steps: - activate-ssh-key@4: {} - git-clone@6: {} - decrypt-file@0: inputs: - encrypted_file_path: "./secret.txt.gpg" - output_file_path: "./secret/" - decrypt_passphrase: "$PASSWORD_FOR_ENCRYPT" - deploy-to-bitrise-io@2: {} ``` --- ## Using files in your builds There are multiple ways to use files in your Bitrise builds. - Most Steps that generate files store the filepath in an output Environment Variable (Env Var). Subsequent Steps in the same Workflow can re-use that Env Var to access the file. - You can [upload a file to the Generic File Storage](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds) and use the automatically generated Env Var as a Step input value in Steps that accept URLs as an input. - You can [upload a file to the Generic File Storage](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds) and use one of our Steps (for example, the [**File Downloader**](https://github.com/bitrise-steplib/steps-file-downloader) Step) to download the file for the build. This works with Steps that require local file paths and as such do not support URLs directly as the input value. ### Downloading a file using the File Downloader Step One of the ways to access a file in your build is by using the **File Downloader** Step. This Step is useful when you need to use a file in a Step input that only accepts local paths as a value. The Step downloads the file in a location you specify, and then every subsequent Step can access the file in that location. **Workflow Editor** 1. Open the Workflow Editor. 1. Add the **File Downloader** Step to your Workflow. 1. In the **Download source url** input, add the location where the file can be found. :::note[Finding the download URL for an uploaded file] If you [uploaded the file to Bitrise](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds), you can find its download URL in the **Files** section of the **App settings** page. ::: 1. In the **Download destination path** input, specify the path where you want to download the file. It should be a path relative to the root of the repository. :::tip[Using an Env Var as the input value] You can store the filepath in an App Env Var instead of specifying it directly for the input. That way you can refer to the file through the Env Var in other Steps, you won’t have to specify the path every time. For example, if you store the path in the `BITRISEIO_MY_FILE_LOCAL_PATH` Env Var, you can use it as the path for the input, and also use it to access the file in every subsequent Step. ::: 1. Click **Save changes** in the top right corner. **Configuration YAML** 1. Open the app's `bitrise.yml` file. 1. Add the `file-downloader` Step to your Workflow. ```yaml workflows: download: steps: - activate-ssh-key: {} - git-clone: {} - file-downloader: inputs: ``` 1. In the `source` input, add the location where the file can be found. ```yaml workflows: download: steps: - activate-ssh-key: {} - git-clone: {} - file-downloader: inputs: - source: "$BITRISEIO_BITRISE_TEST_URL" ``` 1. In the `destination` input, specify the path where you want to download the file. It should be a path relative to the root of the repository. ```yaml workflows: download: steps: - activate-ssh-key: {} - git-clone: {} - file-downloader: inputs: - destination: "/" - source: "$BITRISEIO_BITRISE_TEST_URL" - deploy-to-bitrise-io: {} ``` :::tip[Using an Env Var as the input value] You can store the filepath in an App Env Var instead of specifying it directly for the input. That way you can refer to the file through the Env Var in other Steps, you won’t have to specify the path every time. For example, if you store the path in the `BITRISEIO_MY_FILE_LOCAL_PATH` Env Var, you can use it as the path for the input, and also use it to access the file in every subsequent Step. ::: ### Downloading a file using a custom Script Step If you don't want to use the **File Downloader** Step to download and access an uploaded file in your build, you can use your own custom Script Step as well. All you need to do is to get the download URL and then download the file by specifying a full download path that exists on the build machine. **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add a **Script** Step to your Workflow. 1. Find the **Script content** input of the Step. 1. Add a script to download the file and store the destination path in an Env Var. :::tip[Uploading the file to Bitrise] If you [upload the file to Bitrise](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds), you can use the file's download URL in your script. ::: In the example below, the download URL is stored in the BITRISE_IO_MY_FILE_ID_URL Env Var. We're using envman to store the destination path in the BITRISEIO_MY_FILE_LOCAL_PATH Env Var. Subsequent Steps can use this Env Var to access the file. ```bash #!/bin/bash set -ex # specify local download path export file_local_path=download/path/to/my/file # download the file wget -O "$file_local_path" "$BITRISEIO_MY_FILE_ID_URL" echo "file downloaded to: $file_local_path" # OPTIONALLY: export the file's local path, to be able to use it in subsequent steps as an input value envman add --key BITRISEIO_MY_FILE_LOCAL_PATH --value "$file_local_path" ``` Alternatively, for example, you can set the location as an App Env Var and simply download it to that path instead of defining the path inside the Script Step. **Configuration YAML** 1. Open the `bitrise.yml` file of your app. 1. Add a `script` Step to your Workflow. ```yaml my-workflow: steps: script: inputs: - content: ``` 1. In the `content` input, add a script to download the file and store the destination path in an Env Var. :::tip[Uploading the file to Bitrise] If you [upload the file to Bitrise](/bitrise-ci/run-and-analyze-builds/managing-build-files/uploading-files-for-your-builds), you can use the file's download URL in your script. ::: In the example below, the download URL is stored in the BITRISE_IO_MY_FILE_ID_URL Env Var. We're using envman to store the destination path in the BITRISEIO_MY_FILE_LOCAL_PATH Env Var. Subsequent Steps can use this Env Var to access the file. ```yaml my-workflow: steps: - script: inputs: - content: #!/bin/bash set -ex # specify local download path export file_local_path=download/path/to/my/file # download the file wget -O "$file_local_path" "$BITRISEIO_MY_FILE_ID_URL" echo "file downloaded to: $file_local_path" ``` Alternatively, for example, you can set the location as an App Env Var and simply download it to that path instead of defining the path inside the Script Step. 1. Optionally, export the file's local path so you can use it in subsequent Steps in the same Workflow. ```yaml my-workflow: steps: - script: inputs: - content: #!/bin/bash set -ex # specify local download path export file_local_path=download/path/to/my/file # download the file wget -O "$file_local_path" "$BITRISEIO_MY_FILE_ID_URL" echo "file downloaded to: $file_local_path" # export the file path for subsequent steps envman add --key BITRISEIO_MY_FILE_LOCAL_PATH --value "$file_local_path" ``` --- ## Approving Pull Request builds Not all pull requests need to be built. After all, for most projects, anyone can create a fork of the repository and submit a pull request. However, if a project on Bitrise is set up with [Secrets](/bitrise-ci/configure-builds/secrets) that are exposed for pull request builds, for example, then you probably don’t want just anyone to be able to access those secrets. That is why you have the option to require approval for [a pull request build](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) before it can start. This feature works somewhat differently for public and private projects: - Private projects: by default, pull requests submitted from a fork require approval. The setting can be changed. If your secrets are NOT exposed to PRs, the build will run without asking for approval. - Public projects: pull requests submitted from a fork require approval by default and it cannot be changed. Public projects CANNOT opt out of this feature. ### Configuring manual approval for private projects To enable or disable manual approval, you need to be an **Admin** or an **Owner** of the project. The project MUST be private: public projects cannot opt out of this feature! 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Builds**. 1. Scroll down to **Manual approval**. ![Manual approval toggle on the Builds settings page](/img/run-and-analyze-builds/2026-07-14-manual-approval-toggle.png) Please note that you can only change this setting for private projects! For public projects, this is always enabled. 1. Toggle the switch to enable or disable it. ### Approving the PR build :::important[Approving the PR build] Please note that approving a PR build means approving it on Bitrise. Approving a pull request on GitHub, for example, isn't sufficient to start a build on Bitrise: an owner has to approve the build on Bitrise itself. ::: If a pull request is submitted from a fork, you will be notified that a PR build is waiting for approval: - A notification email will be sent with the name of the project, as well as links to the repository itself and to the project’s **Builds** page on Bitrise. - On the Git provider, the status of the CI check will show **Pending - Waiting for approval** - On the **Builds** page of the project, a confirmation box will be displayed. To approve and run the build, click the **Approve and run Build** button. Clicking **Review PR** opens the pull request on the website of your Git provider. --- ## Scheduling builds You can schedule your builds to run automatically at a specific time of the week so that you can check your logs when it’s most convenient for you. When scheduling a build, you can define custom [Environment Variables](/bitrise-ci/configure-builds/environment-variables). You can also set advanced filters for Git Tags and for Git commit hash. If you have one or more regularly scheduled builds, you can: - Edit their configuration. - Trigger them manually at any time. - Temporarily disable them. - Permanently delete them. ### Scheduling a build How to schedule a build with the basic configuration options on Bitrise: 1. On the **Bitrise CI** page of your app, find the **Start build** button and click the button with the clock icon next to it. ![scheduling-builds.png](/img/_paligo/uuid-ea158f34-25dc-4585-c7a3-0961c5ef5472.png) 1. In the **Schedule build** dialog, set up the scheduling cadence: you can choose between **Basic** and **Cron** settings. - In the **Basic** settings, you need to set a start date, a start time in 24-hour time format, and select a timezone. - In the **Cron** settings, you can set a `cron` [schedule expression](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html). The dialog will parse your expression and display the configured time in a human-readable format. 1. If you chose **Basic**, enable or disable repetition with the **Repetition** toggle. If you enable repetition, configure the frequency, from minutes to years. The build will be triggered with the configured frequency, always at the same time, determined by the scheduling cadence. For example, you can configure your builds to run on Monday and Thursday every week. ![repetition.png](/img/_paligo/uuid-e5013e56-2f65-12a8-c6c7-ba34733cde57.png) 1. When ready, click **Next** to proceed to the build configuration. 1. Select between **Basic** and **Advanced** configuration. Basic configuration offers three options: - A branch name. This is a required field. - A message in the **Message** field. This is not related to Git commit messages at all. It's just a place to provide some optional information about your build. - A Workflow or a Pipeline. You can select a specific one or use the **Based on trigger map** option to select one using the [the trigger map](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers) in the app's `bitrise.yml` configuration file. :::note[Pull request branch] Starting a build of a pull request’s branch is NOT the same as a pull request build. The manually started build of a pull request branch will only build the state of the code on that branch. An automatically triggered pull request build, however, builds the state of the code as it will look like once you merged the pull request. ::: For advanced configuration options, see the [Advanced configuration options for starting/scheduling builds](#advanced-configuration-options-for-startingscheduling-builds) section. ![schedule-basic.png](/img/_paligo/uuid-9e21a75a-a3ed-54f2-9b07-53a46d9a3d2d.png) 1. When done, click **Schedule build**. #### Advanced configuration options for starting/scheduling builds If you choose **Advanced** in the **Build configuration** window, you have all the options available with **Basic**, and a few more: You can select a source type in the **Source** dropdown menu. In addition to the default **Branch** option, you can also select: - **Git Tag**: Builds a particular branch or commit that is tagged with the Tag you enter. If you set this, you can't set a commit hash. :::important[Git Tags and commit hashes are conflicting options] You cannot specify both a Git Tag and a commit hash. When you set one, the other one will disappear. This ensures you cannot enter conflicting input values. ::: - **Commit Hash**: Copy a specific commit’s hash here to build that particular commit. This option can even send a build status update to your git hosting service. If you set this, you can't set a Git Tag. :::note[Commit hash takes precedence over the Branch option] If the **Branch** option specifies a branch where the commit hash you chose doesn't exist, Bitrise will find the branch that does have the given commit and run a build with that branch. ::: ![start-build-advanced.png](/img/_paligo/uuid-67f3a4f0-9315-bec3-0ea7-cca80d77b103.png) In addition to different sources, you can also add: - **Priority**: Determines the priority of your build in the build queue. The higher the number, the sooner your build will run. The priority must be an integer between -100 and 100. The default value is 0. For more information, check out [Build priority](/bitrise-ci/configure-builds/configuring-build-settings/build-priority). - **Custom Environment Variables**: Create a custom Environment Variable that is used in the build. See [Setting a custom Env Var when starting a build](/bitrise-ci/configure-builds/environment-variables#setting-a-custom-env-var-when-starting-a-build). ### Editing a scheduled build To change the configuration of a regularly scheduled build: 1. Go to the **Builds** page of your app. 1. Find the **Scheduled builds** section and open it to view your scheduled builds. ![scheduled-build.png](/img/_paligo/uuid-1f797261-860a-f2b2-42c0-a7817b7e07f5.png) 1. Click the options menu (⋮). 1. Select **Edit configuration**. ![edit-config.png](/img/_paligo/uuid-fd64fe74-fbea-b6f4-8445-406398a41ead.png) 1. Make the changes you want and click **Save**. ### Triggering a scheduled build manually To immediately trigger a scheduled build: 1. Go to the **Builds** page of your app. 1. Find the **Scheduled builds** section and open it to view your scheduled builds. ![scheduled-build.png](/img/_paligo/uuid-1f797261-860a-f2b2-42c0-a7817b7e07f5.png) 1. Click **Trigger now**. ### Pausing a scheduled build To temporarily pause a regularly scheduled build: 1. Go to the **Builds** page of your app. 1. Find the **Scheduled builds** section and open it to view your scheduled builds. ![scheduled-build.png](/img/_paligo/uuid-1f797261-860a-f2b2-42c0-a7817b7e07f5.png) 1. Click the options menu (⋮). 1. Select **Pause schedule**. The build will not run until you enable it again. ![edit-config.png](/img/_paligo/uuid-fd64fe74-fbea-b6f4-8445-406398a41ead.png) ### Deleting a scheduled build To permanently delete a regularly scheduled build: 1. Go to the **Builds** page of your app. 1. Find the **Scheduled builds** section and open it to view your scheduled builds. ![scheduled-build.png](/img/_paligo/uuid-1f797261-860a-f2b2-42c0-a7817b7e07f5.png) 1. Click the options menu (⋮). 1. Select **Delete** and then click **Delete** again when prompted for confirmation. ![edit-config.png](/img/_paligo/uuid-fd64fe74-fbea-b6f4-8445-406398a41ead.png) --- ## Starting builds manually Starting a build manually on Bitrise takes literally two clicks - if you leave everything on the default settings. If you do not wish to do that, or at least want to be sure what the default settings are, read on! To start a build using the basic configuration options: 1. On the **Bitrise CI** page of your app, click the **Start build** button. ![scheduling-builds.png](/img/_paligo/uuid-ea158f34-25dc-4585-c7a3-0961c5ef5472.png) 1. 1. Enter the branch you want to run into the **Source branch** input field. You can choose between typing the name or selecting it from a dropdown menu. Click **Select branch** to bring up the dropdown menu. You can only set one branch. If a pull request to your repository is made from a forked branch, type the name of that branch to run a build of the pull request. :::important[Pull request build] Starting a build of a pull request’s branch is NOT the same as a pull request build. The manually started build of a pull request branch will only build the state of the code on that branch. An automatically triggered pull request build, however, builds the state of the code as it will look like once you merged the pull request. ::: 1. Optionally, enter a build message in the **Message** field. Please note that entering the Git commit message of a specific commit doesn't trigger a build of that commit! 1. From the **Target** menu, select a Workflow or Pipeline. If you don't select one, Bitrise will choose a Workflow or Pipeline based on your app's [trigger setup](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers). :::note[Scheduling a build] The **Schedule this build** option allows you to configure builds to be triggered at specific times. Read more: [Scheduling builds](/bitrise-ci/run-and-analyze-builds/starting-builds/scheduling-builds). ::: ### Running Workflows from the Workflow Editor You can manually start a build by running a single Workflow from the Workflow Editor. To do so: 1. Open your project on Bitrise and click the **Workflows** button to open the Workflow Editor. 1. On the left, select **Workflows**, and use the dropdown menu to select the Workflow you would like to run. ![Workflow dropdown menu in the Workflow Editor](/img/run-and-analyze-builds/2026-07-14-workflow-editor-workflow-dropdown.png) 1. Click the **Run Workflow** button (the one with the **play** icon). ![Run Workflow button next to the Workflow dropdown](/img/run-and-analyze-builds/2026-07-14-workflow-editor-run-button.png) 1. Specify the branch that you want to build in the **Branch** field. ![Run dialog with a Branch field and Start build button](/img/run-and-analyze-builds/2026-07-14-run-workflow-branch-dialog.png) 1. Click **Start build**. And that's it! As soon as you click the **Start build** button, your build will be kicked off, and the build's page will open in a new tab. ### Advanced configuration options for starting/scheduling builds If you choose **Advanced** in the **Build configuration** window, you have all the options available with **Basic**, and a few more: You can select a source type in the **Source** dropdown menu. In addition to the default **Branch** option, you can also select: - **Git Tag**: Builds a particular branch or commit that is tagged with the Tag you enter. If you set this, you can't set a commit hash. :::important[Git Tags and commit hashes are conflicting options] You cannot specify both a Git Tag and a commit hash. When you set one, the other one will disappear. This ensures you cannot enter conflicting input values. ::: - **Commit Hash**: Copy a specific commit’s hash here to build that particular commit. This option can even send a build status update to your git hosting service. If you set this, you can't set a Git Tag. :::note[Commit hash takes precedence over the Branch option] If the **Branch** option specifies a branch where the commit hash you chose doesn't exist, Bitrise will find the branch that does have the given commit and run a build with that branch. ::: ![start-build-advanced.png](/img/_paligo/uuid-67f3a4f0-9315-bec3-0ea7-cca80d77b103.png) In addition to different sources, you can also add: - **Priority**: Determines the priority of your build in the build queue. The higher the number, the sooner your build will run. The priority must be an integer between -100 and 100. The default value is 0. For more information, check out [Build priority](/bitrise-ci/configure-builds/configuring-build-settings/build-priority). - **Custom Environment Variables**: Create a custom Environment Variable that is used in the build. See [Setting a custom Env Var when starting a build](/bitrise-ci/configure-builds/environment-variables#setting-a-custom-env-var-when-starting-a-build). - **Generated cURL command**: Based on the options you set in the Build configuration window, we provide an automatically generated cURL command. This can be copied and pasted, and you can run it on any platform that has cURL installed. ### Rebuilding failed builds Another way of starting a build manually is to rebuild a failed build. You can: - Rebuild a Workflow build: [Rebuilding a failed Workflow build](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rerunning-a-failed-workflow-build). - Rebuild a Pipeline, either the entire Pipeline or only unsuccessful Workflows: [Rebuilding a failed Pipeline](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline). - Rebuild with remote access: [Remote access](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/remote-access). --- ## Utility builds :::note[Beta] Utility builds are available as a beta for a limited period, for Workspaces on the Pro and Pro Trial plans. Beta terms are provisional and may change. We'll let you know what comes next before the beta ends. ::: Utility builds are short Linux builds that don't count against your plan's build quota. They're designed for the lightweight jobs that run many times a day — lint checks, unit tests, scripts, change detection, dependency audits — so a 30-second check no longer consumes the same quota as a full app build. A utility build still consumes build minutes as usual. Only the build count is excluded. ### How utility builds work Bitrise classifies a build as a utility build at build completion. A build qualifies when both of these are true: - The build ran on the **Linux Small** machine type (2 vCPU, 8 GB RAM). - The build finished in under five minutes. Qualifying builds don't count against your build quota. Build minutes are still metered as they are for any other build. There is no runtime enforcement: if a build runs longer than five minutes, it completes normally and simply counts as a regular build. On the **Builds** page, qualifying builds are marked with a **Utility build** label. ### Using utility builds You don't need to set anything up or opt in. [Set the Linux Small machine type for a Workflow](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds) and qualifying builds are automatically excluded from your build count. For the available machine types and their specifications, see [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types). ### Availability Utility builds are available on the Pro and Pro Trial plans during the beta. They are not available on Enterprise plans, legacy plans, or the Hobby plan. ### Fair use Utility builds are for lightweight workloads: automations, checks, and scripts. Splitting resource-intensive builds into short stages to avoid build counts isn't in the spirit of the offer, and we may adjust the terms or qualification rules if we see it. :::caution Utility machines are meant for lightweight jobs. We don't provide technical support for running larger, resource-intensive builds on them. ::: ### Related - [Setting the stack for your builds](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds) - [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types) - [Workspace billing and invoicing](/bitrise-platform/workspaces/workspace-billing-and-invoicing) --- ## Deploying and viewing test results View your test results in one place after a Bitrise CI build. All tests will be available on the build page, even if you have multiple testing Steps in your Workflows. Our goal is to make sure you have accessible and `actionable` test results on Bitrise, leading to faster time to recover from test failures and a better overall developer experience. ### Deploying test results Deploy your test results on the build page with minimal configuration. The requirements depend on your setup: - Using the official Bitrise testing Steps to run tests - Using other Steps to run tests #### Deploying results from the official Bitrise testing Steps The supported testing Steps are the following: - **Android Unit Test**: [Android unit tests](/bitrise-ci/testing/testing-android-apps/android-unit-tests). - **Android Instrumented Test**: [Running instrumented tests for Android apps](/bitrise-ci/testing/testing-android-apps/running-instrumented-tests-for-android-apps). - **Xcode Test for iOS**: [Running unit and UI tests for iOS apps](/bitrise-ci/testing/testing-ios-apps/running-unit-and-ui-tests-for-ios-apps). - **iOS Device Testing**: [Device testing for iOS](/bitrise-ci/testing/device-testing-with-firebase/device-testing-for-ios). - **Virtual Device Testing for Android**: [Device testing for Android](/bitrise-ci/testing/device-testing-with-firebase/device-testing-for-android). - **Flutter Test**: [Testing Flutter apps](/bitrise-ci/testing/testing-flutter-apps/running-the-dart-analyzer-on-bitrise). If you use any of these Steps, make sure you have the **Deploy to Bitrise.io** Step in your Workflow. Bitrise will automatically deploy your test results to the build page. :::important[Attachments and flaky tests] If your tests generate attachments or you want Bitrise to show flaky tests, the **Deploy to Bitrise.io** Step must be of version 2.19.1 or newer. ::: #### Deploying results from other Steps If you run your tests using other Steps (for example, you can use [Script](https://bitrise.io/integrations/steps/script) Steps for a fully custom testing solution), you need some additional configuration. 1. Add the Step running your tests to your Workflow. 1. Add the **Export test results to the Test Reports** Step to your Workflow. 1. Configure the Step: [Using the Export test results to the Test Reports Step](/bitrise-ci/testing/deploying-and-viewing-test-results#using-the-export-test-results-to-test-reports-step). 1. Make sure you have the **Deploy to Bitrise.io** Step in your Workflow. :::important[Attachments and flaky tests] If your tests generate attachments or you want Bitrise to show flaky tests, the **Deploy to Bitrise.io** Step must be of version 2.19.1 or newer. ::: ### Viewing test results :::note[Rich HTML reporting] If you use [rich HTML test reports](/bitrise-ci/testing/testing-ios-apps/viewing-xcode-test-results-in-rich-html-format), you can still find those on the **Artifacts** tab. ::: To view your results, open the build page and select the **Tests** tab. Your tests are sorted into different tabs based on their status: - Failed - Passed - Skipped - Error - Flaky By default, Bitrise shows the list of failed tests. You can view test run details within each of these categories. Click any test to check the details: the duration of the test, the output, and any attachments that the test generated. For easier debugging of failures, test reports display attached image files in line with their associated test cases. :::note[Supported file formats] Currently, we support the following file formats for attachments: `.jpg, .jpeg, .png, .txt, .log, .mp4, .webm, .ogg` ::: You can view flaky tests on the **Flaky** tab. Flaky tests are tests that sometimes fail and sometimes succeed without any changes in the code. If a test fails and then succeeds on [an automatic retry](/bitrise-ci/testing/testing-ios-apps/running-unit-and-ui-tests-for-ios-apps#test-repetitions), Bitrise marks the test as flaky, and you can view it on the **Flaky** tab. It also displays the details and attachments for each retry of the test. You can find more information on how to detect flaky tests and how to quarantine them, if needed, in [Detecting and quarantining flaky tests](/bitrise-ci/testing/detecting-and-quarantining-flaky-tests). ![test-run.png](/img/_paligo/uuid-53eba539-6b4d-b4cf-c33d-6168fca79640.png) Test reports also support the use of the `system-out` tag in JUnit. If a test case includes this tag, we display its contents on the **Test output** tab. If a test case has both a `system-out` tag and produces an error message, we display both. ### Collating test attachments with test results Many tests generate image files (screenshot tests, XCUITests, etc). Bitrise test reports automatically collate image files with associated test cases for Xcode tests (using the `xcresult` file). :::note[Supported file formats] Currently, we support the following file formats for attachments: `.jpg, .jpeg, .png, .txt, .log, .mp4, .webm, .ogg` ::: However, if your test doesn't generate an `xcresult` file, you can still achieve the same thing by generating a JUnit XML file and using Bitrise Steps: **Workflow Editor** 1. Generate a `JUnit.xml` file from your tests. The general file structure should look something like this: ```xml ``` 1. Add a `` element to associate an attachment with a `testcase`. The `name` attribute of the element must be set with a value `attachment_#` where `#` is the ordered index of the attachment file, and the value is the filename. Bitrise will show attachments for any test with the attachment properties, but it's most common to only attach screenshots to failed tests. Mark a test as failed with a `` element. ```xml Call stack printed here ``` 1. Add the **Export test results to Test Reports** Step to your Bitrise Workflow. It should be version 1.1.0 or higher. 1. Set a test name in the **The name of the test** input. 1. Set the path to your JUnit XML file in the **Test result search pattern** input. 1. Add the **Deploy to Bitrise.io** Step to the end of your Workflow. You don't have to change the default input values. **Configuration YAML** 1. Generate a `JUnit.xml` file from your tests. The general file structure should look something like this: ```xml ``` 1. Add a `` element to associate an attachment with a `testcase`. The `name` attribute of the element must be set with a value `attachment_#` where `#` is the ordered index of the attachment file, and the value is the filename. Bitrise will show attachments for any test with the attachment properties, but it's most common to only attach screenshots to failed tests. Mark a test as failed with a `` element. ```xml Call stack printed here ``` 1. Add the `custom-test-results-export` Step to your Bitrise Workflow after generating your JUnit XML file. It should be version 1.1.0 or higher. ```yaml workflows: inline_attachment: steps: - generate-text-file: inputs: - file_name: junit.xml - file_content: "xml content with references to image files here" - custom-test-results-export: ``` 1. Set a test name in the `test_name` input. ```yaml - custom-test-results-export@1: inputs: - test_name: example_tests ``` 1. Set the path to your JUnit XML file in the `search_pattern` input. ```yaml - custom-test-results-export@1: inputs: - test_name: example_tests - search_pattern: junit.xml ``` 1. Add the `deploy-to-bitrise-io` Step to the end of your Workflow. You don't have to change the default input values. The full Workflow in your configuration YAML file might look something like this: ```yaml workflows: inline_attachment: steps: - generate-text-file@0: inputs: - file_name: junit.xml - file_content: "xml content with references to image files here" - custom-test-results-export@1: inputs: - test_name: example_tests - base_path: "." - search_pattern: junit.xml - script@1: inputs: - content: | #!/usr/bin/env bash set -ex set -o pipefail TEST_RESULTS_DIR=$(find "$BITRISE_TEST_DEPLOY_DIR" -type d -name "example_tests" -print -quit) cp ~/*.jpg $TEST_RESULTS_DIR title: Copy image files to test directory - deploy-to-bitrise-io@2: {} ``` ### Using the Export test results to Test Reports Step You can use the **Export test results to Test Reports** Step to make sure your test results appear on the **Tests** tab, even if you use Steps that don’t automatically export their results. With the correct configuration, the Step finds the test results in your project’s repository and puts them in the export directory. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add the **Export test results to Test Reports** Step to your Workflow after the Step that runs your tests. 1. In the **The name of the test** input, set the name of the test run. 1. In the **Test result base path** input, set the path where your test results can be found. ![Managing_an_app_s_bitrise.png](/img/_paligo/uuid-fd13332e-571f-e706-88ed-a20a29db7aea.png) We recommend setting a folder here, though you can also set a specific filepath. The default value is the source directory of your project. Example patterns: - If your project’s root directory is `app`: `app/build/test-results/testDemoDebugUnitTest/` - If your test results are within a project folder but `app` is not the root directory: ./app/build/test-results/testDemoDebugUnitTest/ 1. In the **Test result search pattern** input, set a pattern that matches your test result file. This search pattern is used to search every file and folder of the path that was set in the **Path where custom test results reside** input. If there is more than one match, the Step will export the first match with a warning in the logs. If you set a specific filepath in the previous input, just set * here. Example patterns: - Matching all files within the base path: `*` - Matching all files within a given directory of the base path: `*/build/test-results/testDemoDebugUnitTest/*` 1. In the **Step’s test result directory** input, make sure the path is correct. Do NOT modify this input’s value: this is the folder where the **Deploy to Bitrise.io** Step will look for the test results to export them. It should be set to the `$BITRISE_TEST_RESULT_DIR` Env Var. 1. Make sure you have a **Deploy to Bitrise.io** Step in your Workflow. If your tests generate attachments, make sure the Step is of version 2.19.x or newer. --- ## Detecting and quarantining flaky tests Flaky tests block PRs even when the code is fine. A single transient failure forces you to dig through logs, hit rerun, and wait, slowing merges and masking real regressions. ### Detecting flaky tests Configure specific build Steps to automatically rerun any failed tests. If the tests pass on retry, the build can go green, and the tests are marked flaky, so you can fix it later. You can also [quarantine](/bitrise-ci/testing/detecting-and-quarantining-flaky-tests#quarantining-flaky-tests) it if you have an [Enterprise](https://bitrise.io/solutions/enterprise) plan. #### Steps allowing automatic reruns for failed tests The inputs in these testing Steps allow you to specify the number of retry attempts for failed tests. When a test fails during a run, the Step will automatically retry the tests. If the test passes on a subsequent attempt, it is marked as flaky; however, the Step itself will still succeed, allowing your build and PR check to turn green. This allows you to merge your changes without being blocked, while still providing the data you need to identify and fix unstable tests later. - [Xcode Test for iOS](https://bitrise.io/integrations/steps/xcode-test) - [Xcode Test without building](https://bitrise.io/integrations/steps/xcode-test-without-building) - [iOS Device Testing](https://bitrise.io/integrations/steps/virtual-device-testing-for-ios) - [Virtual Device Testing for Android](https://bitrise.io/integrations/steps/virtual-device-testing-for-android) - [Android unit test](https://bitrise.io/integrations/steps/android-unit-test) (via [Gradle plugin](https://github.com/gradle/test-retry-gradle-plugin)) For example, a UI test might occasionally fail because a network request times out or an animation hasn't completed. Instead of failing the entire build, you can now configure it to retry failed tests up to 3 times. If it passes on the second try, your PR is unblocked, and you can see in the test report that this specific test was flaky. Note that if you use either the **iOS Device Testing** Step or the **Virtual Device Testing for Android** Step, then the entire test suite will be rerun, and not just the tests that failed. #### Configuring flaky test detection Configure flaky test detection in the input fields of these testing Steps: ##### Xcode Test for iOS and Xcode Test without building Set below input fields under **Test repetition** in the Step: - **Test Repetition Mode**: Defines the repetition mode. For example, `retry_on_failure` will only rerun the tests that failed. - **Maximum Test Repetitions**: The maximum number of times to repeat a test. - **Relaunch Tests For Each Repetition**: It controls whether the app is relaunched for each repetition. ##### iOS device testing and Virtual device testing for Android Set below input field in the Step: - **Number of times a test execution is reattempted**: Specifies the number of times to retry a failed test execution. An execution that fails initially but succeeds on a reattempt is reported as flaky. The maximum value is 10. The default is 0 (no reruns). ![iosdevicetesting-flakytests.png](/img/_paligo/uuid-acd14919-6069-8806-9834-df5d53a539a5.png) :::note[Running tests with **Virtual Device Testing for Android** and**iOS Device Testing** Steps] Both Steps will always rerun all tests (successful and failed) as many times as is configured in the input. ::: ##### Android Unit Test This functionality is configured directly through the [Gradle plugin](https://github.com/gradle/test-retry-gradle-plugin). You can enable retries for failed tests within your project's `build.gradle` file. :::note[Quarantining flaky tests] It is possible to [quarantine](/bitrise-ci/testing/detecting-and-quarantining-flaky-tests#quarantining-flaky-tests) flaky tests that disrupt your builds to run until you can fix the issue. The above mentioned Steps will automatically skip the quarantined tests as you specify some quarantine details. ::: #### Environment Variable for flaky test detection Testing Steps now automatically populate BITRISE_FLAKY_TEST_CASES when retries are enabled, identifying which specific tests are behaving inconsistently. When any of these Steps run with retries enabled, they automatically track individual test results: - Xcode Test for iOS (ID: xcode-test) - Android Unit Test (ID: android-unit-test) - iOS Device Testing (ID: virtual-device-testing-for-ios) - Virtual Device Testing for Android (ID: virtual-device-testing-for-android) :::note[Extra precondition for the device-testing Steps] For **iOS Device Testing** and **Virtual Device Testing for Android**, enabling retries isn't enough on its own: you also need to set the **Download files** input to `true`. This input is `false` by default, and without it these two Steps won't populate BITRISE_FLAKY_TEST_CASES. ::: These Steps populate the BITRISE_FLAKY_TEST_CASES Env Var with tests that failed at least once but also passed at least once during retry attempts. The  BITRISE_FLAKY_TEST_CASES Env Var contains a newline-separated list of flaky test identifiers: ```yaml - TestTarget_1.TestClass_1.TestMethod_1 - TestTarget_1.TestClass_1.TestMethod_2 - TestTarget_1.TestClass_2.TestMethod_1 - TestTarget_2.TestClass_1.TestMethod_1 ``` ##### Examples of when to use the flaky test Env Var Here are a couple of use cases when using this Env Var comes handy: 1. The test fails if flaky tests are detected: ```yaml steps: ... - script:     run_if: '{{getenv "BITRISE_FLAKY_TEST_CASES" | ne ""}}'     inputs:     - content: |-         #!/bin/env bash         echo "Build failed due to flaky tests:"         echo "$BITRISE_FLAKY_TEST_CASES"         exit 1 ``` 1. To send Slack notification if flaky tests are detected: ```yaml steps: ... - slack:     run_if: '{{getenv "BITRISE_FLAKY_TEST_CASES" | ne ""}}'     inputs:     - webhook_url: $SLACK_WEBHOOK_URL     - text: |-         ⚠️ Flaky tests detected in build $BITRISE_BUILD_NUMBER:        $BITRISE_FLAKY_TEST_CASES ``` 1. Creates a GitHub issue automatically: ```yaml steps: ... - script:     run_if: '{{getenv "BITRISE_FLAKY_TEST_CASES" | ne ""}}'     inputs:     - content: |-         #!/bin/env bash         ISSUE_BODY="Flaky tests detected in build $BITRISE_BUILD_NUMBER:\n\n\`\`\`\n$BITRISE_FLAKY_TEST_CASES\n\`\`\`"         curl -X POST \           -H "Authorization: token $GITHUB_TOKEN" \           -H "Accept: application/vnd.github.v3+json" \          https://api.github.com/repos/owner/repo/issues \           -d "{\"title\":\"Flaky tests - Build $BITRISE_BUILD_NUMBER\",\"body\":\"$ISSUE_BODY\"}" ``` You can also log to the analytics service, save to build artifacts, count and categorize by test target, and set the Environment Variable for downstream Steps. #### Test results and outcomes after retries If a test fails, the Step reruns the tests up to the configured limit. If a previously failing test passes on retry, it’s marked flaky in the Bitrise **Tests** tab. If tests still fail after retries, the Step fails as usual. If all tests pass after retry, the build passes and flaky tests get highlighted in the new test report. If any test fails after retries, the Step fails and the build status says FAILED. :::note[Flaky test case with failed and successful runs] Even if a test case has successful and failed runs, it will be marked as flaky. The number and order of status do not matter. For example: 1 failed, 1 success, 1 failed is marked as flaky as well as 1 success and 2 failed runs (in this order). ::: ### Quarantining flaky tests This feature lets you temporarily isolate problematic tests without disrupting your entire test suite. You can mark [flaky tests](/bitrise-ci/testing/detecting-and-quarantining-flaky-tests#detecting-flaky-tests) as quarantined so Bitrise will skip them in future builds. Quarantined tests are tracked in a separate **Test Quarantine** tab and will continue being skipped from your builds until you remove them from quarantine. :::note[Use of Test Quarantine is limited] Please note that this feature is only available with the [Enterprise plan](https://bitrise.io/solutions/enterprise). Additionally, only an Admin, Platform Engineer and a Developer can have full read, write and edit access to quarantined tests. Testers and QA people have read-only access. ::: It’s recommended to quarantine tests if, for example: - A test passes locally but fails intermittently in CI. - You've identified a flaky test, but don't have time to fix it immediately. - You want to maintain green builds while investigating test stability issues. - You need to prevent automatic reruns from consuming build minutes on known problematic tests. #### Adding tests to quarantine You can quarantine tests from the **Tests** tab or from **Insights** to prevent unexpected build failures: **Tests tab** 1. Navigate to the **Flaky** tab on the **Tests** tab. ![pipelinebuild-quarantine.png](/img/_paligo/uuid-917bf276-d9f8-706a-9bb8-6b9e4d1bba39.png) 1. Click **Add to quarantine** next to any flaky test. 1. Define the quarantine scope (workflows, pipelines, or branches) by clicking **[Edit quarantine scope](/bitrise-ci/testing/detecting-and-quarantining-flaky-tests#defining-the-scope-of-quarantine)**. 1. Add an optional comment for future reference. ![editscope-quarantine.png](/img/_paligo/uuid-01568ffa-736b-b7a0-a692-03cf3784fd65.png) **Insights** 1. Go to **Insights** → **Tests** → **Flaky tests** → **Test cases**. 1. Apply the **Project filter**. 1. Click **Add to quarantine** next to any test in the breakdown view. 1. Configure the quarantine scope and conditions by clicking **[Edit quarantine scope](/bitrise-ci/testing/detecting-and-quarantining-flaky-tests#defining-the-scope-of-quarantine)**. 1. Submit to exclude the test from future runs. ![insights-quarantine.png](/img/_paligo/uuid-722f22f9-7a85-48f3-69b6-78a16b9df4f0.png) #### Defining the scope of quarantine By default, quarantine applies to all builds on your project, unless you specify otherwise. Leave fields empty to skip the test on all branches and all targets (workflows and pipelines). You can limit the scope by branches and targets: - Branch (optional): enter space-separated branch patterns with wildcard support (*). Examples: `main`, `release-*`, `feature/auth-*` - Targets (optional): enter space-separated workflow and pipeline names. Examples: `ci`, `nightly-tests`, `release-pipeline` :::note[Combining branches and target to narrow the scope] If you set both branches and targets, the test is quarantined only when both the branch AND the target match. Keep patterns tight to avoid silencing too much. Prefer `release-*` over `*` and target the specific workflow that runs the flaky test. ::: You can use the **Comment** field to note the quarantine reason and include a ticket link so you remember why you quarantined the test. You can edit or remove the scope later from the quarantine dashboard. #### Managing quarantined tests Access the quarantine dashboard from the **Test Quarantine** tab on your CI home page. :::note[Accessing Quarantined tests] Please note that only an Admin, Platform Engineer and a Developer can have full read, write and edit access to quarantined tests. Testers and QA people have read-only access. ::: The dashboard shows: - Test name and module path. - The build where the test was quarantined. - Timestamp and user who quarantined it. - Direct links to insights for each test. ![managingquarantinedtests.png](/img/_paligo/uuid-f06ef542-d72d-5bed-0c22-4d729b330691.png) Quarantined tests that were not executed in a build will not show up on your **Tests** tab. Quarantined tests remain in the dashboard until you remove them from the quarantine. We recommend that you scope narrowly; quarantine on the branches/workflows where the flakiness occurs. It is also helpful to leave a comment for future cleanup and set regular reviews for long-lived quarantines and fixed tests. #### Environment Variable for quarantined tests During builds, Bitrise injects the scoped list of quarantined tests into the $BITRISE_QUARANTINED_TESTS_JSON Environment Variable. Supported Steps read this variable to skip those tests and exclude them from automatic reruns. If you use custom Steps or direct runner calls, parse $BITRISE_QUARANTINED_TESTS_JSON and filter your test runner arguments accordingly. Here is an example of the value in the Env Var: ```yaml BITRISE_QUARANTINED_TESTS_JSON = "[ { testCaseName: 'EnableQuarantiningDisabledByPlan', testSuiteName: ['UITests', 'CI', 'Settings'], className: 'BuildSettings' }, { testCaseName: 'EnableQuarantiningDisabledByLDFlag', testSuiteName: ['UITests', 'CI', 'Settings'], className: 'BuildSettings' } ... ]" ``` :::note[Steps supporting quarantined tests] The following steps will automatically skip the quarantined tests within the specified scope. If you use custom steps or direct runner calls, parse $BITRISE_QUARANTINED_TESTS_JSON and filter your test runner arguments accordingly. - [Xcode Test for iOS](https://bitrise.io/integrations/steps/xcode-test) - [Xcode Test Without Building](https://bitrise.io/integrations/steps/xcode-test-without-building) - [iOS Device Testing](https://bitrise.io/integrations/steps/virtual-device-testing-for-ios) - [Android Unit Test](https://bitrise.io/integrations/steps/android-unit-test) - [Virtual Device Testing for Android](https://bitrise.io/integrations/steps/virtual-device-testing-for-android) ::: ##### Quarantine support for custom Steps Other Steps can convert the BITRISE_QUARANTINED_TESTS_JSON data to a suitable format for your test runner to skip given tests. For example, you can configure the fastlane `scan` action or a Gradle Init script to skip the quarantined tests. Here are some examples: **Fastlane - running scan action** You can run a fastlane lane in a Bitrise Workflow either with the official Bitrise **Fastlane** Step or using a **Script** Step. In either scenario, you will first need to convert the JSON data to a comma-separated list of `TestTarget/TestClass/TestMethod` items. You can convert the JSON data either in the configuration YAML file or in the fastlane config file (`Fastfile`). **Configuration YAML** 1. In this example, a **Script** Step converts the quarantined test JSON data to a comma-separated list of `TestTarget/TestClass/TestMethod` items and exposes the list in the BITRISE_QUARANTINED_TESTS_LIST Environment Variable: ```yaml workflows: test: steps: ... - script: title: Convert BITRISE_QUARANTINED_TESTS_JSON inputs: - content: |- #!/usr/bin/env bash set -e # Read JSON from environment variable json="$BITRISE_QUARANTINED_TESTS_JSON" # Convert to array of TestTarget/TestClass/TestMethod test_array=($(echo "$json" | jq -r '.[] | "\(.testSuiteName[0])/\(.className)/\(.testCaseName)"')) # Join the array elements with a comma skip_testing_list=$(IFS=, ; echo "${test_array[*]}") # Export the comma-separated string as an environment variable to be used by following Fastlane Steps envman add --key BITRISE_QUARANTINED_TESTS_LIST --value "$skip_testing_list" - fastlane: inputs: - lane: test ... ``` 1. The BITRISE_QUARANTINED_TESTS_LIST variable can then be used to set the `skip testing` option for the `scan` action in fastlane: ```ruby lane :test do ... scan(skip_testing: ENV['BITRISE_QUARANTINED_TESTS_LIST'].split(',')) ... end ``` **Fastfile** - Converting the data in the Fastfile also requires the BITRISE_QUARANTINED_TESTS_JSON variable. In the example below, the fastlane lane parses the list of quarantined tests into test identifiers and passes them to scan as `skip_testing`: ```ruby lane :test do ... skip_testing = JSON.parse(ENV['BITRISE_QUARANTINED_TESTS_JSON']).map do |item| "#{item['testSuiteName'][0]}/#{item['className']}/#{item['testCaseName']}" end unless ENV['BITRISE_QUARANTINED_TESTS_JSON'].to_s.empty? scan(skip_testing: skip_testing) ... end ``` **Script Step - running xcodebuild test or test-without-building** This example converts the BITRISE_QUARANTINED_TESTS_JSON variable's value to `skip-testing` options for xcodebuild `test` or `test-without-building` commands. ```yaml workflows: test: steps: - script: title: Convert BITRISE_QUARANTINED_TESTS_JSON inputs: - content: |- #!/usr/bin/env bash set -e # Read JSON from environment variable json="$BITRISE_QUARANTINED_TESTS_JSON" # Convert to array of -skip-testing:TestTarget/TestClass/TestMethod test_array=($(echo "$json" | jq -r '.[] | "-skip-testing:\(.testSuiteName[0])/\(.className)/\(.testCaseName)"')) # Join the array elements with a space skip_testing_list="${test_array[*]}" # Export the space-separated string as an environment variable to be used by following Fastlane Steps envman add --key XCODEBUILD_SKIP_TESTING_OPTION --value "$skip_testing_list" - script: inputs: - content: xcodebuild test -scheme -destination $XCODEBUILD_SKIP_TESTING_OPTION ``` **Script Step - running Gradle unit tests** When running Android local unit tests through Gradle (`/gradlew testUnitTest)`, a Gradle Init script can be used to skip quarantined test cases. ```yaml workflows: test: steps: - script: title: Create skip testing init script inputs: - content: |- #!/bin/bash # Script to generate Gradle init script for quarantined tests # Reads BITRISE_QUARANTINED_TESTS_JSON environment variable and generates # a Gradle init script that excludes the specified tests set -ex # Check if BITRISE_QUARANTINED_TESTS_JSON is set if [[ -z "${BITRISE_QUARANTINED_TESTS_JSON:-}" ]]; then echo "Error: BITRISE_QUARANTINED_TESTS_JSON environment variable is not set" >&2 exit 1 fi # Parse JSON and extract test patterns # Each test will be excluded using the pattern: className.testCaseName excluded_tests=$(echo "$BITRISE_QUARANTINED_TESTS_JSON" | jq -r '.[] | .className + "." + .testCaseName') # Generate the Gradle init script init_script_file=./gradle_quarantine_init.gradle.kts cat << 'EOF' > "$init_script_file" allprojects { tasks.withType().configureEach { EOF # Add filter.excludeTestsMatching lines for each excluded test while IFS= read -r test_pattern; do if [[ -n "$test_pattern" ]]; then echo " filter.excludeTestsMatching(\"$test_pattern\")" >> "$init_script_file" fi done <<< "$excluded_tests" cat << 'EOF' >> "$init_script_file" } } EOF # Output the path to the generated init script file envman add --key GRADLE_INIT_SCRIPT_FILE --value "$init_script_file" - script: title: Run tests inputs: - content: |- #!/bin/bash set -ex ./gradlew :app:testDebugUnitTest "--init-script" "$GRADLE_INIT_SCRIPT_FILE" ``` The `Create skip testing init script` Step creates the following Gradle init script: ```groovy allprojects { tasks.withType().configureEach { filter.excludeTestsMatching("..") filter.excludeTestsMatching("..") ... } } ``` --- ## Device testing for Android With Bitrise’s Android virtual device testing solution, you can run UI tests on emulators without having to set up and register your own devices. :::note[Limitations] The maximum duration for virtual device testing is 60 minutes. Configure this with the **Test timeout** input; the default is 15 minutes. A single build can contain only one **Virtual Device Testing** Step performing one type of test (`instrumentation`, `robo` or `gameloop`). ::: Our device testing solution is based on [Firebase Test Lab](https://firebase.google.com/docs/test-lab/). You can find the resulting logs, videos and screenshots on Bitrise. ### Running tests With Bitrise, you can choose from 3 different test types: - robo (default test type in Bitrise). - instrumentation. - gameloop. If you want to read up on the difference between these test types, take a look at [Firebase’s documentation.](https://firebase.google.com/docs/test-lab/android/get-started) There is a small difference between configuring your Workflow for robo and instrumentation tests, so let’s see them separately! #### Running robo tests **Workflow Editor** 1. Open the Workflow you want to use in the Workflow Editor. 1. Add the **Android Build** Step to your Workflow to export an APK. The Step stores the APK path in an [Env Var](/bitrise-ci/configure-builds/environment-variables). You will need this Env Var later. 1. Add the `Debug` task to the **Variant** Step input field. 1. Add **Virtual Device Testing for Android** Step after the **Android Build** Step. 1. Set the `App path` input field. 1. Set the **Test type** input to **robo**. 1. Add the type of test device in the **Test devices** input field. If choosing a different device than the default, your input should have the format of `deviceID`, `version`, `language`, `orientation` separated with `,`. Find the list of the available devices [here](https://firebase.google.com/docs/test-lab/android/available-testing-devices). 1. Optionally, set the **Test timeout** input to control how long a test execution can run before it's automatically canceled. The default is 15 minutes; the maximum is 60 minutes. 1. Start a build and [check your test results](/bitrise-ci/testing/deploying-and-viewing-test-results). **Configuration YAML** 1. In the Configuration YAML file, find the Workflow you want to use or create a new one. 1. Add the `android-build` Step to your Workflow. The Step stores the APK path in an [Env Var](/bitrise-ci/configure-builds/environment-variables). You will need this Env Var later. ```yaml my-workflow: steps: - git-clone: {} - android-build: inputs: ``` 1. Set the `variant` input to `Debug`. ```yaml my-workflow: steps: - git-clone: {} - android-build: inputs: - variant: Debug ``` 1. Add the `virtual-device-testing-for-android` Step. ```yaml my-workflow: steps: - git-clone: {} - android-build: inputs: - variant: Debug - virtual-device-testing-for-android: inputs: ``` 1. Set the `app_path` input field: by default, its value is the $BITRISE_APK_PATH Env Var. This Env Var is exported by the `android-build` Step. ```yaml my-workflow: steps: - git-clone: {} - android-build: inputs: - variant: Debug - virtual-device-testing-for-android: inputs: - app_path: $BITRISE_APK_PATH ``` 1. Set the `test_type` input to `robo`. ```yaml my-workflow: steps: - git-clone: {} - android-build: inputs: - variant: Debug - virtual-device-testing-for-android: inputs: - test_type: robo - app_path: $BITRISE_APK_PATH ``` 1. Add the type of test device in the `test_devices` input field. Your input should have the format of `device ID`,`version`,`language`,`orientation` separated with a  `,`. :::tip[Supported models] You can check the supported device models by running the `gcloud firebase test android models list --filter=virtualgcloud firebase test android models list --filter=virtual` command in the Google Cloud CLI. ::: ```yaml my-workflow: steps: - git-clone: {} - android-build: inputs: - variant: Debug - virtual-device-testing-for-android: inputs: - test_type: robo - app_path: $BITRISE_APK_PATH - test_devices: 'Nexus9,24,en,portrait' ``` 1. Optionally, set the `test_timeout` input to control how long a test execution can run before it's automatically canceled (in seconds). The default is 900 (15 min); the maximum is 3600 (60 min). ```yaml my-workflow: steps: - git-clone: {} - android-build: inputs: - variant: Debug - virtual-device-testing-for-android: inputs: - test_type: robo - app_path: $BITRISE_APK_PATH - test_devices: 'Nexus9,24,en,portrait' - test_timeout: '3600' ``` 1. Start a build and check your test results. ##### Setting user input with Robo directives for successful robo tests If your app needs specific user interaction for a successful robo test, you can use the Robo Directives input field to set those necessary inputs. For example, certain UI elements of the app are only accessible for robo testing if the required user inputs (username and email address) are populated for log in. 1. Click the Virtual Device Testing for Android Step in your workflow. 1. Click the Robo Test section. 1. Find the Robo directives input field and set your required user input directives. - provide a comma-separated list of key-value pairs, where the key is the Android resource name of the target UI element, and the value is the text string. EditText fields are supported but not text fields in WebView UI elements. For example, you could use the following parameter for custom login: ```text username_resource,username,ENTER_TEXT password_resource,password,ENTER_TEXT loginbtn_resource,,SINGLE_CLICK ``` - One directive per line, the parameters are separated with , character. For example: ResourceName,InputText,ActionType. ![Device_testing_for_Android.png](/img/_paligo/uuid-c9f67a4a-32c5-6ea8-fd0a-e1da4dccebf2.png) Based on the input you provide, you can successfully run a robo test (even on pages that are only accessible with a specific user input) and check the test results in the Tests tab on the Build page. The test results can be, for example: - Screenshots. Recorded video. Logs. Files. Here is a screenshot of a successful robo test, where the robo test got all the way through to My application by populating the email and password fields first with the pre-defined directives from the Robo directives. ![Device_testing_for_Android.jpg](/img/_paligo/uuid-9b533252-b690-2350-8a3d-5929fcd79ffb.jpg) ### Running instrumentation tests **Workflow Editor** 1. Open the Workflow you want to use in the Workflow Editor. 1. Add the **Android Build for UI testing** Step to your Workflow. 1. To export an APK and a Test APK, you have to set the following input fields in the **Android Build for UI testing** Step. - **Project Location**: the root directory of your Android project. - **Module**: set the module you wish to build. - **Variant**: set the variant you wish to build (usually `Debug`). ![Device_testing_for_Android.png](/img/2026-07-16-android-build-for-ui-testing-step.png) The Step outputs will be `BITRISE_APK_PATH` (which is the path of the generated APK after filtering) and `BITRISE_TEST_APK_PATH` (which is the path of the generated test APK after filtering). 1. Add the **Virtual Device Testing for Android** Step right after the **Android Build for UI testing** Step. 1. Set the **Test type** input to `instrumentation`. Our **Android Build for UI Testing** Step exports an APK and a Test APK and their paths get automatically set in the **App path** and the **Test APK path** input fields of the **Virtual Device Testing for Android** Step. 1. Add the type of test device in the **Test devices** input field. If choosing a different device than the default, your input should have the format of `device ID`,`version`,`language`,`orientation` separated with a  `,`. ![Device_testing_for_Android.png](/img/2026-07-16-virtual-device-testing-for-android-test-devices.png) 1. Optionally, set the **Test timeout** input to control how long a test execution can run before it's automatically canceled. The default is 15 minutes; the maximum is 60 minutes. 1. Start a build and check your test results. **Configuration YAML** 1. In the Configuration YAML file, find the Workflow you want to use or create a new one. 1. Add the `android-build-for-ui-testing` Step to your Workflow. ```yaml my-workflow: steps: - git-clone: {} - android-build-for-ui-testing: inputs: ``` 1. To export an APK and a Test APK, you have to set the following input fields in the **Android Build for UI testing** Step. - `project_location`: the root directory of your Android project. - `module`: set the module you wish to build. - `variant`: set the variant you wish to build (usually debug). ```yaml my-workflow: steps: - git-clone: {} - android-build-for-ui-testing: inputs: - module: module - variant: variant - project_location: $BITRISE_SOURCE_DIR ``` The Step outputs will be `BITRISE_APK_PATH` (which is the path of the generated APK after filtering) and `BITRISE_TEST_APK_PATH` (which is the path of the generated test APK after filtering). 1. Add the `virtual-device-testing-for-android` Step right after the **Android Build for UI testing** Step. ```yaml my-workflow: steps: - git-clone@8: {} - android-build-for-ui-testing: inputs: - module: module - variant: variant - project_location: $BITRISE_SOURCE_DIR - virtual-device-testing-for-android: inputs: ``` 1. Set the `test_type` input to `instrumentation`. Our `android-build-for-ui-testing` Step exports an APK and a Test APK and their paths get automatically set in the `app_path` and the `test_apk_path` input fields of the `virtual-device-testing-for-android` Step. ```yaml my-workflow: steps: - git-clone: {} - android-build-for-ui-testing: inputs: - module: module - variant: variant - apk_path_pattern: '*/build/outputs/apk/*.apk' - arguments: arg - project_location: $BITRISE_SOURCE_DIR - virtual-device-testing-for-android: inputs: - test_type: instrumentation - app_path: $BITRISE_APK_PATH - test_apk_path: $BITRISE_TEST_APK_PATH ``` 1. Add the type of test device in the `test_devices` input field. Your input should have the format of `device ID`,`version`,`language`,`orientation` separated with a  `,`. ```yaml my-workflow: steps: - git-clone: {} - android-build-for-ui-testing: inputs: - module: module - variant: variant - apk_path_pattern: '*/build/outputs/apk/*.apk' - arguments: arg - project_location: $BITRISE_SOURCE_DIR - virtual-device-testing-for-android: inputs: - test_devices: 'Nexus9,24,en,portrait' - test_type: instrumentation - test_apk_path: $BITRISE_TEST_APK_PATH - app_path: $BITRISE_APK_PATH ``` 1. Optionally, set the `test_timeout` input to control how long a test execution can run before it's automatically canceled (in seconds). The default is 900 (15 min); the maximum is 3600 (60 min). ```yaml my-workflow: steps: - git-clone: {} - android-build-for-ui-testing: inputs: - module: module - variant: variant - apk_path_pattern: '*/build/outputs/apk/*.apk' - arguments: arg - project_location: $BITRISE_SOURCE_DIR - virtual-device-testing-for-android: inputs: - test_devices: 'Nexus9,24,en,portrait' - test_type: instrumentation - test_apk_path: $BITRISE_TEST_APK_PATH - app_path: $BITRISE_APK_PATH - test_timeout: '3600' ``` 1. Start a build and check your test results. --- ## Device testing for iOS With Bitrise’s iOS device testing solution, you can run UI tests for iOS apps on physical devices without having to set up and register your own devices: you just need to use our dedicated Steps and set the device type(s) on which you want to test your app. There are no limits to using the Step, other than your overall build time limit. It also works for iOS apps developed using other frameworks, such as Flutter or React Native. Our device testing solution is based on [Firebase Test Lab](https://firebase.google.com/docs/test-lab/): it uses real, production devices running in a Google data center to test your app. The devices are flashed with updated APIs and have customizable locale settings. You can find the resulting logs, videos and screenshots on Bitrise. For iOS apps, Firebase Test Lab runs [XCTest](https://developer.apple.com/documentation/xctest) tests. Find the list of the available devices [here](https://firebase.google.com/docs/test-lab/ios/available-testing-devices). :::note[Limitations] You might be limited by your overall build time. Also note that a single build can contain only one [**iOS Device Testing**](https://github.com/bitrise-steplib/steps-virtual-device-testing-for-ios) Step, performing one type of test. This is because Bitrise sends the build slug to Firebase Test Lab. Sending the same build slug results in a `Build already exists`error. ::: ### Running device tests with Firebase for iOS apps To run device tests for iOS apps with the Firebase Test Lab solution, you will need to add two Steps to your Workflow: - **Xcode Build for testing for iOS**. - **iOS Device Testing**. :::note[Multiplatform apps] The Step can run device tests for iOS apps built with other frameworks, such as Flutter or React Native. You just need to make sure the **Xcode Build for testing for iOS** Step can access your app's `.xcodeproj` or `.xcworkspace` file. ::: The **[Xcode Build for testing for iOS](https://www.bitrise.io/integrations/steps/xcode-build-for-test)** Step performs the `xcodebuild` command’s `build-for-testing` action: it builds the tests defined in your iOS app’s [Xcode scheme](https://developer.apple.com/library/archive/featuredarticles/XcodeConcepts/Concept-Schemes.html). The Step exports a .zip file that contains your test directory (by default, it’s `Debug-iphoneos`) and the `xctestrun` file. To use this Step, you will need [code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) files for the test app. You can choose between using automatic provisioning and manual provisioning. The **[iOS Device Testing](https://github.com/bitrise-steplib/steps-virtual-device-testing-for-ios)** Step takes the path to this .zip file - exported as an Environment Variable - as input to run your tests and export the test results to Bitrise. :::important[Automatic vs manual code signing asset management] The **Xcode Build for testing for iOS** Step can manage your code signing assets without you having to manually manage your provisioning profiles. This only requires you to select the relevant inputs in the Step (see below) and upload the right certificates to the **Code Signing** tab. This is the [automatic code signing asset management](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning) method. If you decide to choose the [manual code signing asset management](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---manual-provisioning), then add the **Certificate and Profile Installer** Step before the **Xcode Build for testing for iOS** Step. The former will take care of the code signing asset management while the latter builds your project. Make sure the **Automatic code signing method** input of the **Xcode Build for testing for iOS** Step is set to `off`. The instructions below detail the steps of setting up automatic code signing asset management on Bitrise with the **Xcode Build for testing for iOS** Step. ::: **Workflow Editor** 1. Add the **Xcode Build for testing for iOS** Step to your Workflow. :::tip[Build for testing] This guide only mentions the most important inputs for setting up an app for device testing. For more information about the Step, see [Xcode Build for testing for iOS](https://bitrise.io/integrations/steps/xcode-build-for-test). ::: 1. In the **Scheme name** input, set the Xcode Scheme you want to use. By default, the value of the input is the `$BITRISE_SCHEME` [Environment Variable](/bitrise-ci/configure-builds/environment-variables) which is stored when your app is created. 1. In the **Build Configuration** input, add the name of the [Xcode build configuration](https://developer.apple.com/documentation/xcode/configuring-the-build-settings-of-a-target) you want to use. If no configuration is specified, the Xcode project's default build configuration will be used. 1. Set a destination option for `xcodebuild` in the **Device destination specifier** input of the Step. The default value is `generic/platform=ios`: this means the tests can be run on any iOS device. 1. Set the **Automatic code signing method** input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t do automatic code signing. - `api-key` if you use [API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id`if you use [Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). 1. Add the **iOS Device Testing** Step to the Workflow.The Step has to come after the **Xcode Build for testing for iOS** Step. :::important[API setting inputs] The inputs related to the Test API (**Test API's base URL** and **API token** cannot be changed on the graphical UI. You should not attempt to modify their values. ::: 1. In the **Test devices** input field, specify the devices on which you want to test the app. Find the list of the available devices [here](https://firebase.google.com/docs/test-lab/ios/available-testing-devices). You can add multiple devices to the input, in the following format: `deviceID,version,language,orientation` 1. Make sure you have the **Deploy to Bitrise.io** Step in your Workflow, with version 1.4.1 or newer. With the older versions of the Step, you won’t be able to check your results in the **Tests** tab! 1. [Start a build](/bitrise-ci/run-and-analyze-builds/starting-builds/approving-pull-request-builds). **Configuration YAML** 1. Add the `xcode-build-for-test` Step to your Workflow. :::tip[Build for testing] This guide only mentions the most important inputs for setting up an app for device testing. For more information about the Step, see [Xcode Build for testing for iOS](https://bitrise.io/integrations/steps/xcode-build-for-test). ::: ```yaml my-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: ``` 1. In the `scheme` input, set the Xcode Scheme you want to use. By default, the value of the input is the `$BITRISE_SCHEME` Environment Variable which is stored when your app is created. ```yaml my-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME ``` 1. In the `configuration` input, add the name of the [Xcode build configuration](https://developer.apple.com/documentation/xcode/configuring-the-build-settings-of-a-target) you want to use. If no configuration is specified, the Xcode project's default build configuration will be used. ```yaml my-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug ``` 1. Set a destination option for `xcodebuild` in the `destination` input of the Step. The default value is `generic/platform=ios`: this means the tests can be run on any iOS device. ```yaml my-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - destination: generic/platform=iOS ``` 1. Set the `automatic_code_signing` input to the Apple service connection you want to use for code signing. The available options are: - `off` if you don’t do automatic code signing. - `api-key` if you use [API key authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). - `apple-id` if you use [Apple ID authorization](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). ```yaml my-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - destination: generic/platform=iOS - automatic_code_signing: api-key ``` 1. Add the `virtual-device-testing-for-ios` Step to the Workflow. The Step has to come after the `xcode-build-for-test` Step. ```yaml my-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - destination: generic/platform=iOS - automatic_code_signing: api-key - virtual-device-testing-for-ios: inputs: ``` 1. In the `test_devices` input field, specify the devices on which you want to test the app. Find the list of the available devices [here](https://firebase.google.com/docs/test-lab/ios/available-testing-devices). You can add multiple devices to the input, in the following format: `deviceID,version,language,orientation` ```yaml my-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - destination: generic/platform=iOS - automatic_code_signing: api-key - virtual-device-testing-for-ios: inputs: - test_devices: 'iphone8,14.7,en,portrait ``` 1. Make sure you have the `deploy-to-bitrise-io` Step in your Workflow, with version 1.4.1 or newer. With the older versions of the Step, you won’t be able to check your results in the **Tests** tab! ```yaml fmy-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - destination: generic/platform=iOS - test_plan: test - automatic_code_signing: api-key - project_path: $BITRISE_PROJECT_PATH - virtual-device-testing-for-ios: inputs: - test_devices: 'iphone8,14.7,en,portrait' - deploy-to-bitrise-io: {} ``` 1. [Start a build](/bitrise-ci/run-and-analyze-builds/starting-builds/approving-pull-request-builds). If all goes well, you should be able to view your results among the [build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) or in the Tests tab. --- ## Running device tests with Firebase for multiplatform apps You can run native device tests for Flutter and React Native apps using Bitrise's device testing solution. ### Testing the iOS app 1. Add tests using the [XCTest](https://developer.apple.com/documentation/xctest) framework to the iOS app of the project. 1. [Build your app for testing](/bitrise-ci/testing/testing-ios-apps/building-an-ios-app-for-testing) with the [**Xcode Build for testing for iOS**](https://github.com/bitrise-steplib/steps-xcode-build-for-test) Step. Make sure that the **Project path** input of the Step points to the `.xcodeproj` or `.xcworkspace` file of your project. You can find these in the `iOS` folder. If you used automatic configuration to add your React Native app to Bitrise, you don't need to modify the default value of the input ($BITRISE_PROJECT_PATH. 1. Run your device tests with the [**iOS Device Testing**](https://github.com/bitrise-steplib/steps-virtual-device-testing-for-ios) Step. For detailed information on configuring an iOS app for device testing, see [Running device tests for iOS apps](/bitrise-ci/testing/device-testing-with-firebase/device-testing-for-ios#running-device-tests-with-firebase-for-ios-apps). ### Testing the Android app You can run robo-, instrumentation- and gameloop tests using the [**Virtual Device Testing for Android**](https://github.com/bitrise-steplib/steps-virtual-device-testing-for-android) Step. However, one instance of the Step can only run one type of test. If you need to run multiple test types, you need multiple instances of the Step. 1. Add tests to the Android app of the project. 1. Build the app for UI testing with the [**Android Build for UI Testing**](https://github.com/bitrise-steplib/bitrise-step-android-build-for-ui-testing) Step. Make sure the **Project Location** input of the Step points to the root directory of the Android app. For example, `./android`. 1. Run your device tests with the [**Virtual Device Testing for Android**](https://github.com/bitrise-steplib/steps-virtual-device-testing-for-android) Step. For detailed information on configuring an Android app for device testing, see [Device testing for Android](/bitrise-ci/testing/device-testing-with-firebase/device-testing-for-android). --- ## Measuring your code coverage with Codecov [Codecov](https://about.codecov.io/product/features/) is the leading code coverage solution for CI/CD pipelines, delivering coverage metrics right into your workflow. It integrates directly with Bitrise to provide valuable insights on code quality in order to allow users to ship healthier code with less risk. Codecov provides many features that make test coverage more available and actionable to speed up your development process and to deliver high-quality applications. Some of these features include: - Coverage changes overlaid with your source code, making it even easier to identify needed test areas. - [Multi-language](https://about.codecov.io/product/features/#multi-lang-multi-ci-cd) support so you can use Codecov right out of the box. - Summary of coverage information directly in your Workflow so that you can add and update tests quickly and effectively. - [Status checks](https://docs.codecov.com/docs/commit-status) to block underperforming pull requests from being merged. - Seamless coverage [report merging](https://docs.codecov.com/docs/merging-reports) for Workflows that upload multiple reports across jobs. - Custom coverage information based on groupings using [Codecov Flags](https://docs.codecov.com/docs/flags). ### Integrating Codecov with Bitrise In order to start using Codecov, you must be generating coverage reports with your preferred coverage tool (for example, Xcode or Gradle). 1. Create an account on [https://codecov.io](https://codecov.io). 1. Go to repository’s **Settings** tab on Codecov and copy the repository upload token. ![pic1.jpg](/img/_paligo/uuid-c8804850-f923-c194-e029-59d1d39e50d7.jpg) 1. Add the **Codecov** Step to your Workflow on Bitrise. Make sure you add the Step after the Steps that test and collect coverage. ![pic2.jpg](/img/_paligo/uuid-a0f5c42f-1f2c-8d2b-a381-5c37bb4fe37c.jpg) 1. Add the Codecov upload token as a secret variable, `CODECOV_TOKEN`, and set the **Expose for Pull Requests** option to `true`. Click **Add new**. ![pic3.jpg](/img/_paligo/uuid-cc9dfa1f-9277-fe9e-7d4a-92d5fb04d5d6.jpg) 1. Click **Save** and start a new build to get coverage metrics. :::tip[Additional options] The Codecov Step wraps around the Codecov CLI. Additional CLI options are exposed directly as Step inputs: see [Codecov CLI options](https://docs.codecov.com/docs/cli-options) for the full list. ::: ### Viewing your coverage reports on Codecov To view your coverage on Codecov, you can do the following: - View the URL supplied on the Codecov Step on Bitrise. ![pic4.png](/img/_paligo/uuid-d981eb34-fe27-6796-ff24-0e9206369758.png) - Go to [https://codecov.io](https://about.codecov.io/) and navigate directly to the applicable pull request or commit. - Click on the links provided by Codecov that are available on your code host’s status checks or pull request comment. ### What's next? Now that you have code coverage reports, you can take it to the next level with the following suggestions: - Set [non-blocking status checks](https://docs.codecov.com/docs/common-recipe-list#set-non-blocking-status-checks) to get your developers in the habit of thinking about code coverage. - Start working towards code coverage by setting status checks to [increase overall coverage](https://docs.codecov.com/docs/common-recipe-list#increase-overall-coverage-on-each-pull-request) on every pull request. - Isolate your coverage reports for different types of tests or different parts of your system with [Flags](https://docs.codecov.com/docs/flags) to measure what matters. - Already using flags and don’t want to run your entire test suite with every Bitrise CI run? Try out [Carryforward Flags](https://docs.codecov.com/docs/carryforward-flags) to measure only what changes. --- ## Test sharding Test sharding is the process of dividing a large suite of automated tests into smaller pieces (shards), which can be executed in parallel on different runners. This significantly reduces the time it takes to provide developers with feedback on their changes, allowing them to maintain focus and iterate fast. Bitrise offers easy to use test sharding optimization features out of the box, depending on your project type and whether you want Bitrise to provide the sharding optimization calculation. | Project type | Sharding with your own shard optimization calculation | Sharding with shard optimization calculation provided by Bitrise | | --- | --- | --- | | iOS | [Parallelism](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow) | Parallelism + Xcode Test Shard Calculation Step | | Android | [Parallelism](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow) | Parallelism + [Gradle Runner](https://github.com/bitrise-io/steps-gradle-runner) Step | ### Sharding with your own test split calculation If you already have a means to calculate the optimal test split for sharding, you can set up test sharding by using the [parallelism](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow) feature in your Pipelines. Parellelism executes the same Workflow in parallel on separate virtual machines. You manually set the number of copies you need by setting the `parallel` property of a Workflow: ```yaml ... workflows: test-without-building: depends_on: [build-for-testing] parallel: 5 ... ``` Each copy receives two new Environment Variables: - $BITRISE_IO_PARALLEL_INDEX: a zero based index for each copy of the Workflow. - $BITRISE_IO_PARALLEL_TOTAL: the total number of copies. You can leverage these Environment Variables to run test sharding. For example, with Jest: ```bash jest --shard=$((BITRISE_IO_PARALLEL_INDEX + 1))/$BITRISE_IO_PARALLEL_TOTAL ``` Or with yarn: ```bash yarn test --ci --silent --shard=$((BITRISE_IO_PARALLEL_INDEX + 1))/$BITRISE_IO_PARALLEL_TOTAL ``` To read more about how to configure parallelism, check our guide: [Parallelism in Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow). ### Sharding with a Bitrise Step calculating the test split You can have a Pipeline that automatically shards your tests based on an optimization algorithm provided by Bitrise Steps. This is supported for both iOS and Android projects. You need to: - Create a Pipeline that both builds and tests your app. - Add the Steps performing the shard calculation to the Workflow that builds your app: the **[Xcode test shard calculation](https://bitrise.io/integrations/steps/xcode-test-shard-calculation)** Step for iOS projects and the **Gradle Runner** Step for Android projects. - Configure parallelism so that multiple copies of the testing Workflow run in parallel. **iOS** 1. Create [an Env Var](/bitrise-ci/configure-builds/environment-variables) that will contain the number of shards you need. For example, NUMBER_OF_SHARDS. 1. Add the [**Xcode test shard calculation**](https://bitrise.io/integrations/steps/xcode-test-shard-calculation) Step to your Workflow that builds your Xcode app. 1. Click the Step to open its options menu and go to the **Configuration** tab. 1. In the **Product path** input, add your new Env Var. ![shard-calculate-product-path.png](/img/_paligo/uuid-3474472d-9f45-e08c-37a0-82dcc3516481.png) 1. Add the **Deploy to Bitrise.io** Step to the same Workflow. 1. Find the **Pipeline Intermediate File Sharing** input group. 1. In the **Files to share between Pipeline Workflows** input, add two Env Vars: - BITRISE_TEST_SHARDS_PATH - BITRISE_TEST_BUNDLE_PATH These are output variables automatically generated. ![shards-deploy-to-bitrise.png](/img/_paligo/uuid-2b040c7d-cbee-1050-4c6e-731d228fb547.png) 1. Open **Pipelines** and in your Pipeline, find the Workflow that runs your tests and click the gear icon to open the edit menu for the Workflow. 1. On the **Configuration** tab, open the **Pipeline Conditions** section. 1. Add the NUMBER_OF_SHARDS Environment Variable to the **Parallel copies** input. ![shards-pipeline.png](/img/_paligo/uuid-abd6b335-ae55-f91a-4cea-4a9df270ce2b.png) For more information about how to configure parallelism: [Parallelism in Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow). **Android** 1. Open your Pipeline and in the **Pipeline conditions** section, add the number of shards you need to the **Parallel copies** input. For more information about how to configure parallelism: [Parallelism in Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow). 1. Add the **Gradle Runner** Step to your Workflow. 1. Open the Step options and go to the **Configuration** tab. 1. In the **Config** input group, find the **Gradle task to run** input and add the following task to it: ```bash connectedAndroidTest \ -Pandroid.testInstrumentationRunnerArguments.numShards=$BITRISE_IO_PARALLEL_TOTAL \ -Pandroid.testInstrumentationRunnerArguments.shardIndex=$BITRISE_IO_PARALLEL_INDEX ``` The $BITRISE_IO_PARALLEL_TOTAL and $BITRISE_IO_PARALLEL_INDEX environment variables will tell Gradle which tests to apply to each shard. ![gradle-runner.png](/img/_paligo/uuid-b3349767-289a-0a77-f7d6-0ae2c4752ef2.png) --- ## Android unit tests Unit tests are useful if you want to verify individual code blocks, catch bugs or prevent crashes as early as possible. On Bitrise, you can run Android unit tests easily with the [**Android Unit Test**](https://github.com/bitrise-steplib/bitrise-step-android-unit-test) Step. The Step finds and runs all unit tests included in the specified module and variant of your Android project. :::tip[Running multiple tests in parallel] You can run multiple unit tests in parallel, for different devices or shards, by using the Pipelines feature: [Currently supported use cases for the Android platform](/bitrise-ci/workflows-and-pipelines/build-pipelines/pipelines-with-stages/currently-supported-use-cases-for-the-android-platform). ::: To run your unit tests: **Workflow Editor** 1. Make sure you included [unit tests](https://developer.android.com/training/testing/local-tests) in your Android project. 1. Add the [**Android Unit Test**](https://github.com/bitrise-steplib/bitrise-step-android-unit-test) Step to your Workflow. 1. Make sure the **Project Location** input points to the root directory of your Android project. The root directory is the directory where your `build.gradle` file exists. If you configured your Android project automatically when [adding it as an app](/bitrise-ci/getting-started/adding-a-new-project) on Bitrise, you don't have to change the default value. 1. In the **Module** and **Variant** inputs, set the module and the variant you want to test. Leave the inputs blank to test all modules and/or variants. You can check the available modules and variants of your project in [the Project window in Android Studio](https://developer.android.com/studio/projects). ![android-unit-test.png](/img/_paligo/uuid-6affd72d-61b9-8755-539a-5b26f62516a5.png) 1. In the **Options** input group, you can [pass additional Gradle arguments](https://docs.gradle.org/current/userguide/custom_tasks.html#sec:declaring_and_using_command_line_options) to the build task in the **Additional Gradle Arguments** input. 1. If you have custom output directories configured for the test results of the tests in your project, configure the Step to look for the test results in the correct location when exporting them: The **Local unit test HTML result directory pattern** input sets the directory for HTML test results. The **Local unit test XML result directory pattern** input sets the directory for XML test results. ![local-result-pattern.png](/img/_paligo/uuid-2e0224cb-0d48-8c50-3bb4-c5a126fff586.png) Both directories are zipped and exported to BITRISE_DEPLOY_DIR. This ensures that your test results can be viewed, for example, in the **Tests** tab. If you don't have custom output directories configured, you do not need to change these inputs: the default values will work. 1. Add the [**Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step to your Workflow to be able to view your test results: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). **Configuration YAML** 1. Make sure you included [unit tests](https://developer.android.com/training/testing/local-tests) in your Android project. 1. Add the `android-unit-test` Step to your Workflow. ```yaml my-workflow: steps: - git-clone: {} - android-unit-test: inputs: ``` 1. Make sure the `project_location` input points to the root directory of your Android project. The root directory is the directory where your `build.gradle` file exists. If you configured your Android project automatically when [adding it as an app](/bitrise-ci/getting-started/adding-a-new-project) on Bitrise, you don't have to change the default value. ```yaml my-workflow: steps: - git-clone: {} - android-unit-test: inputs: - project_location: $BITRISE_SOURCE_DIR ``` 1. In the `module` and `variant` inputs, set the module and the variant you want to test. If you don't set these inputs, the Step will test all modules and/or variants. You can check the available modules and variants of your project in [the Project window in Android Studio](https://developer.android.com/studio/projects). ```yaml my-workflow: steps: - git-clone: {} - android-unit-test: inputs: - module: app - variant: debug - project_location: $BITRISE_SOURCE_DIR ``` 1. In the `arguments` input, you can [pass additional Gradle arguments](https://docs.gradle.org/current/userguide/custom_tasks.html#sec:declaring_and_using_command_line_options) to the build task. ```yaml my-workflow: steps: - git-clone: {} - android-unit-test: inputs: - module: app - variant: debug - arguments: --task - project_location: $BITRISE_SOURCE_DIR ``` 1. If you have custom output directories configured for the test results of the tests in your project, configure the Step to look for the test results in the correct location when exporting them: The `report_path_pattern` input sets the directory for HTML test results. The `result_path_pattern` input sets the directory for XML test results. ```yaml my-workflow: steps: - git-clone: {} - android-unit-test: inputs: - module: app - variant: debug - arguments: --task - report_path_pattern: '*build/reports/tests' - result_path_pattern: '*build/test-results' - project_location: $BITRISE_SOURCE_DIR ``` Both directories are zipped and exported to BITRISE_DEPLOY_DIR. This ensures that your test results can be viewed, for example, in the **Tests** tab. If you don't have custom output directories configured, you do not need to change these inputs: the default values will work. 1. Add the `deploy-to-bitrise-io` Step to your Workflow to be able to view your test results: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). ```yaml my-workflow: steps: - git-clone: {} - android-unit-test: inputs: - module: app - variant: debug - arguments: --task - report_path_pattern: '*build/reports/tests' - result_path_pattern: '*build/test-results' - project_location: $BITRISE_SOURCE_DIR - deploy-to-bitrise-io: {} ``` --- ## Running instrumented tests for Android apps [Instrumented tests](https://developer.android.com/training/testing/instrumented-tests) run on Android devices, whether physical or emulated. On Bitrise, you can run instrumented tests using [the adb tool](https://developer.android.com/tools/adb). To run your instrumented tests, you need two Steps in your Workflow: - The [**Android Build for UI testing**](https://github.com/bitrise-steplib/bitrise-step-android-build-for-ui-testing) Step builds both an APK and a test APK. For example, `MyappDebug.apk` and `MyAppDebugAndroidTest.apk`. The Step stores the path to these APKs in two output Environment Variables: BITRISE_APK_PATH and BITRISE_TEST_APK_PATH. You can use these Env Vars to access the APKs in subsequent Steps in the same Workflow. - The [**Android Instrumented Test**](https://github.com/bitrise-steplib/bitrise-step-android-instrumented-test) Step runs the instrumented tests using the APKs built in the previous Step. To run instrumented tests for Android: **Workflow Editor** 1. Add the [**Android Build for UI testing**](https://github.com/bitrise-steplib/bitrise-step-android-build-for-ui-testing) Step to your Workflow. 1. Make sure the **Project location** input points to the root directory of your Android app. 1. Set the module and the variant you want to build in the **Module** and the **Variant** input. You can check the available modules and variants of your project in [the Project window in Android Studio](https://developer.android.com/studio/projects). ![build-forui-tsting.png](/img/_paligo/uuid-9de8c3bc-abac-16bb-8a19-be18a97ac998.png) 1. In the **Options** input group, you can set the location for the generated APK files in the **APK location pattern** input. The input takes a file pattern as a value. The default value is `*/build/outputs/apk/*.apk`. 1. Optionally, you can [pass additional Gradle arguments](https://docs.gradle.org/current/userguide/custom_tasks.html#sec:declaring_and_using_command_line_options) to the build task in the **Additional Gradle Arguments** input. 1. Add the [**Android Instrumented Test**](https://github.com/bitrise-steplib/bitrise-step-android-instrumented-test) Step to the Workflow, at some point after the [**Android Build for UI testing**](https://github.com/bitrise-steplib/bitrise-step-android-build-for-ui-testing) Step. 1. Make sure that the **Main APK path** and the **Test APK path** inputs point to the correct location. By default, the values of the two inputs are the BITRISE_APK_PATH and the BITRISE_TEST_APK_PATH Environment Variables, respectively. These variables are exported by the [**Android Build for UI testing**](https://github.com/bitrise-steplib/bitrise-step-android-build-for-ui-testing) Step. As such, in the vast majority of cases, you don't have to modify the value of these inputs. ![android-instrumented.png](/img/_paligo/uuid-ab9cf08d-eb9e-d46d-7bb2-740827ec96b9.png) 1. In the **Test runner class** input, specify the test runner you wish to use. The default runner is [the AndroidJUnitRunner class](https://developer.android.com/training/testing/instrumented-tests/androidx-test-libraries/runner). 1. Optionally, you can pass additional options to the test runner with the **Additional testing options** input. With this input, you issue commands to the activity manager tool of the `adb` shell. For more information about the commands you can issue, see [the official documentation for adb](https://developer.android.com/tools/adb#issuingcommands). 1. Add the [**Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step to your Workflow to view test results: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). **Configuration YAML** 1. Add the `android-build-for-ui-testing` Step to your Workflow. ```yaml steps: - git-clone: {} - android-build-for-ui-testing: inputs: - deploy-to-bitrise-io: {} ``` 1. Make sure the `project_location` input points to the root directory of your Android app. ```yaml steps: - git-clone: {} - android-build-for-ui-testing: inputs: - project_location: $BITRISE_SOURCE_DIR - deploy-to-bitrise-io: {} ``` 1. Set the module and the variant you want to build in the `module` and the `variant` input. You can check the available modules and variants of your project in [the Project window in Android Studio](https://developer.android.com/studio/projects). ```yaml steps: - git-clone: {} - android-build-for-ui-testing: inputs: - module: app - variant: debug - project_location: $BITRISE_SOURCE_DIR - deploy-to-bitrise-io: {} ``` 1. In the `apk_path_pattern` input, you can set the location for the generated APK files. The input takes a file pattern as a value. The default value is `*/build/outputs/apk/*.apk`. ```yaml steps: - git-clone: {} - android-build-for-ui-testing: inputs: - arguments: flag - module: app - variant: debug - apk_path_pattern: '*/build/outputs/apk/*.apk' - project_location: $BITRISE_SOURCE_DIR - deploy-to-bitrise-io: {} ``` 1. Optionally, you can [pass additional Gradle arguments](https://docs.gradle.org/current/userguide/custom_tasks.html#sec:declaring_and_using_command_line_options) to the build task in the `arguments` input. ```yaml steps: - git-clone: {} - android-build-for-ui-testing: inputs: - arguments: --task - module: app - variant: debug - apk_path_pattern: '*/build/outputs/apk/*.apk' - project_location: $BITRISE_SOURCE_DIR - deploy-to-bitrise-io: {} ``` 1. Add the `android-instrumented-test` Step to the Workflow, at some point after the `android-build-for-ui-testing` Step. ```yaml steps: - git-clone: {} - android-build-for-ui-testing: inputs: - arguments: flag - module: app - variant: debug - apk_path_pattern: '*/build/outputs/apk/*.apk' - cache_level: all - project_location: $BITRISE_SOURCE_DIR - android-instrumented-test: inputs: - deploy-to-bitrise-io: {} ``` 1. Make sure that the `main_apk_path` and the `test_apk_path` inputs point to the correct location. By default, the values of the two inputs are the BITRISE_APK_PATH and the BITRISE_TEST_APK_PATH Environment Variables, respectively. These variables are exported by the `android-build-for-ui-testing` Step. As such, in the vast majority of cases, you don't have to set the value of these inputs. ```yaml steps: - git-clone: {} - android-build-for-ui-testing: inputs: - arguments: flag - module: app - variant: debug - apk_path_pattern: '*/build/outputs/apk/*.apk' - cache_level: all - project_location: $BITRISE_SOURCE_DIR - android-instrumented-test: inputs: - main_apk_path: $BITRISE_APK_PATH - test_apk_path: $BITRISE_TEST_APK_PATH - deploy-to-bitrise-io: {} ``` 1. In the `test_runner_class` input, specify the test runner you wish to use. The default runner is [the AndroidJUnitRunner class](https://developer.android.com/training/testing/instrumented-tests/androidx-test-libraries/runner). ```yaml steps: - git-clone: {} - android-build-for-ui-testing: inputs: - arguments: flag - module: app - variant: debug - apk_path_pattern: '*/build/outputs/apk/*.apk' - cache_level: all - project_location: $BITRISE_SOURCE_DIR - android-instrumented-test: inputs: - test_runner_class: androidx.test.runner.AndroidJUnitRunner - main_apk_path: $BITRISE_APK_PATH - test_apk_path: $BITRISE_TEST_APK_PATH - deploy-to-bitrise-io: {} ``` 1. Optionally, you can pass additional options to the test runner with the `additional_testing_options` input. With this input, you issue commands to the activity manager tool of the `adb` shell. For more information about the commands you can issue, see [the official documentation for adb](https://developer.android.com/tools/adb#issuingcommands). For example, the value `KEY1 true KEY2 false` will be passed to adb as `adb shell am instrument -e "KEY1" "true" "KEY2" "false" [...]`. ```yaml steps: - git-clone: {} - android-build-for-ui-testing: inputs: - arguments: flag - module: app - variant: debug - apk_path_pattern: '*/build/outputs/apk/*.apk' - cache_level: all - project_location: $BITRISE_SOURCE_DIR - android-instrumented-test: inputs: - test_runner_class: androidx.test.runner.AndroidJUnitRunner - additional_testing_options: KEY1 true KEY2 false - main_apk_path: $BITRISE_APK_PATH - test_apk_path: $BITRISE_TEST_APK_PATH - deploy-to-bitrise-io: {} ``` 1. Add the [**Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step to your Workflow to view test results: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). --- ## Running lint for your Android apps Android Studio provides [a code scanning tool called lint](https://developer.android.com/studio/write/lint) that can help you identify and correct problems with the structural quality of your code. When using Android Studio, configured lint checks run automatically when building your app. Lint checks don't require test cases. On Bitrise, you can run lint checks with our dedicated Step called [**Android Lint**](https://github.com/bitrise-steplib/bitrise-step-android-lint). To do so: **Workflow Editor** 1. Add the [**Android Lint**](https://github.com/bitrise-steplib/bitrise-step-android-lint) Step to your Android app's Workflow. It should come before any Step that builds your app (for example, [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build)), if you have such a Step in your Workflow. 1. Make sure the **Project Location** input points to the root directory of your Android project, where the top level `build.gradle` file is located. 1. In the **Module** and **Variant** inputs, specify the module and variant of the app you want to check. ![android-lint.png](/img/_paligo/uuid-624b318c-ddc6-58e7-4c58-e426c2f3db50.png) If you are unsure about the exact names of modules and variants in your project, you can check them [in the Project view in Android Studio](https://developer.android.com/studio/projects). 1. In the **Options** input group, the **Report location pattern** input allows you to specify where the lint report should be found once the Step has run. The input accepts asterisks as a wildcard. You can set the input to return the results either as html or xml. 1. In the **Options** input group, the **Additional Gradle Arguments** input allows you to pass arguments to the Gradle task. **Configuration YAML** 1. In the Configuration YAML file, add the `android-lint` Step to your Android app's Workflow. It should come before any Step that builds your app (for example, [**Android Build**](https://github.com/bitrise-steplib/bitrise-step-android-build)), if you have such a Step in your Workflow. ```yaml my-workflow: steps: - git-clone: {} - android-lint: ``` 1. Make sure the `project_location` input points to the root directory of your Android project, where the top level `build.gradle` or `build.gradle.kts` file is located. ```yaml my-workflow: steps: - git-clone: {} - android-lint: inputs: - project_location: $BITRISE_SOURCE_DIR ``` 1. In the `module` and `variant` inputs, specify the module and variant of the app you want to check. If you are unsure about the exact names of modules and variants in your project, you can check them [in the Project view in Android Studio](https://developer.android.com/studio/projects). ```yaml my-workflow: steps: - git-clone: {} - android-lint: inputs: - module: module - variant: variant - project_location: $BITRISE_SOURCE_DIR ``` 1. The `report_path_pattern` input allows you to specify where the lint report should be found once the Step has run. The input accepts asterisks as a wildcard. You can set the input to return the results either as html or xml. ```yaml my-workflow: steps: - git-clone: {} - android-lint: inputs: - module: module - variant: variant - report_path_pattern: '*/build/reports/lint-results*.xml' - project_location: $BITRISE_SOURCE_DIR ``` 1. The `arguments` input allows you to pass arguments to the Gradle task. ```yaml my-workflow: steps: - git-clone: {} - android-lint: inputs: - module: module - variant: variant - report_path_pattern: '*/build/reports/lint-results*.xml' - arguments: arg - project_location: $BITRISE_SOURCE_DIR ``` --- ## Testing your app with Browserstack's App Automate [BrowserStack](https://www.browserstack.com/)’s App Automate Espresso lets you test your native and hybrid apps on a variety of Android mobile and tablet devices. You can use App Automate in your Bitrise builds by utilizing our dedicated integration. ### Setting up App Automate Espresso To configure the Browserstack integration: 1. Make sure you have a Browserstack Username and Access key. 1. On Bitrise, open the Workflow Editor and add the **Android Build for UI testing** Step to your Workflow. 1. Make sure the **Project location** input points to the root directory of your Android app. 1. Set the module and the variant you want to build in the **Module** and the **Variant** input. :::note[Gradle arguments] Optionally, you can pass additional Gradle arguments to the build task in the **Additional Gradle Arguments** input. ::: 1. Add the **BrowserStack App Automate - Espresso** Step to your Workflow. It should follow the **Android Build for UI testing** Step. 1. Configure the required Step inputs: | Input group | Input name | Input value | | --- | --- | --- | | **Authentication** | **BrowserStack username** | Your BrowserStack username in a string format. | | **BrowserStack access key** | Your BrowserStack Access Key. | | | **App & Test Suite** | **Android app under test** | The path to your test APK file. By default. you don't need to modify it: the **Android Build for UI testing** Step exports the path as an Env Var which is used as the default value. | | **Espresso test suite** | The path to your test suite file. By default. you don't need to modify it: the **Android Build for UI testing** Step exports the path as an Env Var which is used as the default value. | | | **Devices** | **Devices** | Set to one or more device-OS combinations in a new line. You can find the possible combinations [in this list](https://www.browserstack.com/list-of-browsers-and-platforms/app_automate). | 1. Optionally, [set advanced configuration options](#advanced-configuration-for-app-automate-espresso). ### Advanced configuration for App Automate Espresso The **BrowserStack App Automate - Espresso** Step provides advanced configuration options. All of these options are available in the **Test configuration** input group. | Input name | Description | Values | | --- | --- | --- | | **Filter tests** | Provide a comma-separated list of class or test names followed by supported filtering strategies. Only the filtered test cases will be executed. | Key-value pairs of filters. Possible filters include: class, package, annotation, size. For example: `class com.foo.AddToCartClass,class com.foo.CheckoutClass` | | **Project name** | Provide [a project name](https://www.browserstack.com/docs/app-automate/espresso/organize-tests) for the tests. You can logically group multiple Espresso test executions under a single project. This helps you easily access all related test executions on the App Automate dashboard on Browserstack. | A string. Valid characters are: letters (A-Z, a-z), digits (0-9), periods (.), colons (:), hiphens (-), square brackets ([]), forward slashes (/), asperands (@), ampersands (&), single quotes (‘), and underscores (_). Any other characters are ignored. | | **Test sharding** | Enable [test sharding](https://www.browserstack.com/docs/app-automate/espresso/test-sharding) to split test cases into different groups instead of running them sequentially. | Set key-value pairs to specify the number of shards and configure its behaviour. There are three types of sharding strategies, each requiring different configuration: - Auto strategy: ``` {"numberOfShards": 2}, "devices": ["Google Pixel 3-9.0"] ``` - Package strategy: ``` {"numberOfShards": 2, "mapping": [{"name": "Shard 1", "strategy": "package", "values": ["com.foo.login", "com.foo.logout"]}, {"name": "Shard 2", "strategy": "package", "values": ["com.foo.dashboard"]}]} ``` - Class strategy: ``` {"numberOfShards": 2, "mapping": [{"name": "Shard 1", "strategy": "class", "values": ["com.foo.login.user", "com.foo.login.admin"]}, {"name": "Shard 2", "strategy": "class", "values": ["com.foo.logout.user"]}]} ``` | | **Single runner invocation** | Enable [single runner inovcation](https://www.browserstack.com/docs/app-automate/espresso/single-runner-invocation) to run all tests in a single instrumentation process to reduce overall build time. | `true` or `false` The default value is `false`. | | **Local testing** | Enable [Local testing](https://www.browserstack.com/docs/app-automate/espresso/get-started-with-local-testing) to retrieve app data hosted on local/private servers. | `true` or `false` `false` The default value is `false`. | | **Mock server** | A mock web server mocks the behavior of an actual remote server. This makes it easy to test different scenarios without depending on your remote server and without having to make changes to your remote server. Local testing will not work with a mock server. | `true` or `false` The default value is `false`. | | **Clear app data** | Clear the app's storage after every test run, so each test case starts from a clean app state. | `true` or `false` The default value is `false`. | | **Notify project status** | A callback URL that BrowserStack calls when all builds under a given project have finished. You get a callback if no new builds are triggered for 5 minutes and all existing builds have completed. Requires **Project name** to also be set. | A URL. | | **Test capabilities** | Newline-separated key-value pairs of additional capabilities provided by BrowserStack, for example `coverage=true`. [Learn more](https://www.browserstack.com/docs/app-automate/api-reference/espresso/builds#execute-a-build). | Key-value pairs, one per line. | | **Build Status** | Wait for BrowserStack to complete the execution and fetch the test results. | `true` or `false` The default value is `true`. | ### Logging options for App Automate Espresso The **BrowserStack App Automate - Espresso** Step also provides logging and diagnostics options, available in the **Debug logs** input group. | Input name | Description | Values | | --- | --- | --- | | **Instrumentation logs** | A comprehensive record of your Espresso test executions that helps you identify all the steps executed in the test. | `true` or `false` The default value is `true`. | | **Network Logs** | Captures the network traffic, latency, and HTTP requests and responses in the HAR (HTTP Archive) format. | `true` or `false` The default value is `false`. | | **Android logcat logs** | System logs specific to your application, generated by Android logcat, that help you debug test crashes. | `true` or `false` The default value is `false`. | | **Capture Screenshots** | Captures screenshots to make it easier to identify the exact step in your test where a failure occurred. | `true` or `false` The default value is `false`. | | **Video recording** | Records a video of the test run, to help you review the entire test execution and debug any failed test. | `true` or `false` The default value is `true`. | --- ## Running the Dart analyzer on Bitrise You can perform static analysis of your Flutter code with [the Dart analyzer](https://docs.flutter.dev/testing/debugging#the-dart-analyzer) by using the **Flutter Analyze** Step on Bitrise. The Step runs the `flutter analyze` command that makes heavy use of type annotations that you put in your code to help track problems down. To run the analyzer: **Workflow Editor** 1. Add the **Flutter Install** Step to your Workflow. This Step runs the initial setup of the Flutter SDK and installs any missing components. 1. Make sure that the **Flutter Install** Step installs the correct version of the Flutter SDK for your app: check the **Flutter SDK version or bundle URL** input. ![flutter-install-step.png](/img/2026-07-16-flutter-install-step.png) The input's default value is **stable**, which installs the latest stable version of the SDK. You can, however, set the value to a specific version tag, a branch label, or a Flutter SDK bundle URL: - You can find the available version tags here: [Version tags](https://github.com/flutter/flutter/tags). - You can find the available branch labels here: [Branch labels](https://github.com/flutter/flutter/branches). :::tip[Installation bundle URL] You can also install the Flutter SDK from an installation bundle URL: set the URL as the value of the same **Flutter SDK version or bundle URL** input, for example `https://storage.googleapis.com/flutter_infra/releases/beta/macos/flutter_macos_v1.6.3-beta.zip`. ::: 1. Add the **Flutter Analyze** Step to your Workflow. 1. Make sure the **Project Location** input points to the root directory of your Flutter project. - If the project scanner automatically detected it as a Flutter project when [adding it as an app](/bitrise-ci/getting-started/adding-a-new-project) on Bitrise, you don't have to change the default value. - If you configured the app manually, check that the location is correct. 1. Set the **Fail Severity** input to the desired level. The input determines the minimum severity to fail the Step. Any issue with a severity at least as high as the specified fails the Step. It has three possible settings, from minimum to maximum severity: - **info**: When this setting is selected, info-, warning-, and error-level issues all fail the Step. - **warning**: When this setting is selected, only warning- and error-level issues fail the Step. - **error**: This is the default value. Only error-level issues fail the Step. ![fail-severity.png](/img/2026-07-16-flutter-analyze-fail-severity.png) 1. Optionally, add additional flag to the `flutter analyze` command in the **Additional Parameters** input. For a list of available flags, run `flutter help analyze`. For example, you can use the `--no-congratulate` flag if you don't want to see any output if there are no errors, warnings, hints or lints. **Configuration YAML** 1. Add the `flutter-installer` Step to your Workflow. This Step runs the initial setup of the Flutter SDK and installs any missing components. ```yaml primary: description: | Builds project and runs tests. steps: - activate-ssh-key: {} - git-clone: {} - flutter-installer: inputs: ``` 1. Make sure that the Step installs the correct version of the Flutter SDK for your app: you can specify the version using the `version` input. The input's default value is `stable` which installs the latest stable version of the SDK. If you do not see the `version` input in your Configuration YAML file, it is set to the default value. You can, however, set the value to a specific version tag, a branch label, or a Flutter SDK bundle URL: - You can find the available version tags here: [Version tags](https://github.com/flutter/flutter/tags). - You can find the available branch labels here: [Branch labels](https://github.com/flutter/flutter/branches). ```yaml # Installing version 3.7.7 of the Flutter SDK - flutter-installer: inputs: - version: 3.7.7 ``` :::tip[Installation bundle URL] You can also install the Flutter SDK from an installation bundle URL: set the URL as the value of the same `version` input. The URL is expected to begin with `https://storage.googleapis.com/flutter_infra`. For example: ```yaml - flutter-installer: inputs: - version: https://storage.googleapis.com/flutter_infra/releases/beta/macos/flutter_macos_v1.6.3-beta.zip ``` ::: 1. Add the `flutter-analyze` Step to your Workflow. ```yaml primary: description: | Builds project and runs tests. steps: - activate-ssh-key: {} - git-clone: {} - flutter-installer: inputs: - version: stable - flutter-analyze: inputs: ``` 1. Make sure the `project_location` input points to the root directory of your Flutter project. ```yaml - flutter-analyze: inputs: - project_location: "$BITRISE_SOURCE_DIR" ``` - If the project scanner automatically detected it as a Flutter project when [adding it as an app](/bitrise-ci/getting-started/adding-a-new-project) on Bitrise, you don't have to change the default value. - If you configured the app manually, check that the location is correct. 1. Set the `fail_severity` input to the desired level. The input determines the minimum severity to fail the Step. Any issue with a severity at least as high as the specified fails the Step. It has three possible settings, from minimum to maximum severity: - `info`: When this setting is selected, info-, warning-, and error-level issues all fail the Step. - `warning`: When this setting is selected, only warning- and error-level issues fail the Step. - `error`: This is the default value. Only error-level issues fail the Step. ```yaml - flutter-analyze: inputs: - project_location: "$BITRISE_SOURCE_DIR" - fail_severity: error ``` 1. Optionally, add additional flag to the `flutter analyze` command in the `additional_params` input. For a list of available flags, run `flutter help analyze`. For example, you can use the `--no-congratulate` flag if you don't want to see any output if there are no errors, warnings, hints or lints. ```yaml - flutter-analyze: inputs: - project_location: "$BITRISE_SOURCE_DIR" - fail_severity: error - additional_params: --no-congratulate ``` Once your build has run, you can check the Step's output in the [build logs](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/build-logs). --- ## Running unit and UI tests on Flutter apps The **Flutter Test** Step allows you to run unit tests, widget tests, and integration (also referred to as end-to-end or UI testing) tests on your Flutter app on Bitrise. The Step runs the `flutter test` command and saves the `json` file that is generated by the command. You can then view the test results at any time: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). :::tip[Code coverage] The **Flutter Test** Step can also generate code coverage reports. ::: To run tests using **Flutter Test**: **Workflow Editor** 1. Include tests in your Flutter project. For more information on how to write tests and include them in your Flutter project, check the official Flutter documentation: [Testing Flutter apps](https://docs.flutter.dev/testing). 1. Add the **Flutter Install** Step to your Workflow. This Step runs the initial setup of the Flutter SDK and installs any missing components. 1. Make sure that the **Flutter Install** Step installs the correct version of the Flutter SDK for your app: check the **Flutter SDK version or bundle URL** input. ![flutter-install-step.png](/img/2026-07-16-flutter-install-step.png) The input's default value is **stable**, which installs the latest stable version of the SDK. You can, however, set the value to a specific version tag, a branch label, or a Flutter SDK bundle URL: - You can find the available version tags here: [Version tags](https://github.com/flutter/flutter/tags). - You can find the available branch labels here: [Branch labels](https://github.com/flutter/flutter/branches). :::tip[Installation bundle URL] You can also install the Flutter SDK from an installation bundle URL: set the URL as the value of the same **Flutter SDK version or bundle URL** input, for example `https://storage.googleapis.com/flutter_infra/releases/beta/macos/flutter_macos_v1.6.3-beta.zip`. ::: 1. Add the **Flutter Test** Step to your Workflow. It should be after the **Flutter Install** Step. The Step runs the `flutter test` command with optional flags. It can also check code coverage. 1. Make sure the **Project Location** input points to the root directory of your Flutter project. ![flutter-test-step.png](/img/2026-07-16-flutter-test-step.png) - If the project scanner automatically detected it as a Flutter project when [adding it as an app](/bitrise-ci/getting-started/adding-a-new-project) on Bitrise, you don't have to change the default value. - If you configured the app manually, check that the location is correct. You can do so by going to the **Env Vars** tab on the Workflow Editor, and checking the BITRISE_FLUTTER_PROJECT_LOCATION [Environment Variable](/bitrise-ci/configure-builds/environment-variables). 1. By default, the Step will find and run all tests. But you can configure it to run only selected tests: use the **Test files pattern** input to tell the Step which tests to run. The input accepts both * and ** glob formats. For example, `lib/**/*_test.dart` is a valid input. ![flutter-test-files-pattern.png](/img/2026-07-16-flutter-test-files-pattern.png) 1. Optionally, use the **Additional parameters** input to append flags to the `flutter test` command. To see the available options, run the `flutter help test` command. You can do so on your own device or in a **Script** Step on Bitrise. 1. Optionally, set the **Generate code coverage files?** input to **yes** to generate code coverage files. With this input turned on, the `--coverage` flag is appended to the `flutter test` command. 1. Optionally, you can access the generated json test report and the code coverage file (`lcov.info`) in subsequent Steps by using the BITRISE_FLUTTER_TESTRESULT_PATH and the BITRISE_FLUTTER_COVERAGE_PATH [Environment Variables](/bitrise-ci/configure-builds/environment-variables#setting-and-managing-env-vars-during-a-build). 1. Add the **Deploy to Bitrise.io** Step to your Workflow to view test results: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). **Configuration YAML** 1. Include tests in your Flutter project. For more information on how to write tests and include them in your Flutter project, check the official Flutter documentation: [Testing Flutter apps](https://docs.flutter.dev/testing). 1. Add the `flutter-installer` Step to your Workflow. This Step runs the initial setup of the Flutter SDK and installs any missing components. ```yaml primary: description: | Builds project and runs tests. steps: - activate-ssh-key: {} - git-clone: {} - flutter-installer: inputs: ``` 1. Make sure that the Step installs the correct version of the Flutter SDK for your app: you can specify the version using the `version` input. The input's default value is `stable`, which installs the latest stable version of the SDK. If you do not see the `version` input in your Configuration YAML file, it is set to the default value. You can, however, set the value to a specific version tag, a branch label, or a Flutter SDK bundle URL: - You can find the available version tags here: [Version tags](https://github.com/flutter/flutter/tags). - You can find the available branch labels here: [Branch labels](https://github.com/flutter/flutter/branches). ```yaml # Installing version 3.7.7 of the Flutter SDK - flutter-installer: inputs: - version: 3.7.7 ``` :::tip[Installation bundle URL] You can also install the Flutter SDK from an installation bundle URL: set the URL as the value of the same `version` input. The URL is expected to begin with `https://storage.googleapis.com/flutter_infra`. For example: ```yaml - flutter-installer: inputs: - version: https://storage.googleapis.com/flutter_infra/releases/beta/macos/flutter_macos_v1.6.3-beta.zip ``` ::: 1. Add the `flutter-test` Step to your Workflow. It should be after the `flutter-installer` Step. The Step runs the `flutter test` command with optional flags. It can also check code coverage. ```yaml primary: description: | Builds project and runs tests. steps: - activate-ssh-key: {} - git-clone: {} - flutter-installer: inputs: - version: stable - restore-dart-cache: {} - flutter-test: inputs: ``` 1. Make sure the `project_location` input points to the root directory of your Flutter project. ```yaml - flutter-test: inputs: - project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION" ``` - If the project scanner automatically detected it as a Flutter project when [adding it as an app](/bitrise-ci/getting-started/adding-a-new-project) on Bitrise, you don't have to change the default value, which is BITRISE_FLUTTER_PROJECT_LOCATION. - If you configured the app manually, check that the location is correct. You can check where BITRISE_FLUTTER_PROJECT_LOCATION points in the `envs` property of the `app`: ```yaml # Pointing to the root directory app: envs: - opts: is_expand: false BITRISE_FLUTTER_PROJECT_LOCATION: . ``` 1. By default, the Step will find and run all tests. But you can configure it to run only selected tests: use the `tests_path_pattern` input to tell the Step which tests to run. The input accepts both * and ** glob formats. For example, `lib/**/*_test.dart` is a valid input. ```yaml - flutter-test: inputs: - tests_path_pattern: /lib/*_test.dart ``` 1. Optionally, use the `additional_params` input to append flags to the `flutter test` command. To see the available options, run the `flutter help test` command. You can do so on your own device or in a **Script** Step on Bitrise. ```yaml - flutter-test: inputs: # setting a test timeout of 60 seconds - additional_params: --timeout 60s ``` 1. Optionally, set the `generate_code_coverage_files` input to `'yes'` to generate code coverage files. With this input turned on, the `--coverage` flag is appended to the `flutter test` command. ```yaml - flutter-test: inputs: - generate_code_coverage_files: 'yes' ``` 1. Optionally, you can access the generated json test report and the code coverage file (`lcov.info`) in subsequent Steps by using the BITRISE_FLUTTER_TESTRESULT_PATH and the BITRISE_FLUTTER_COVERAGE_PATH [Environment Variables](/bitrise-ci/configure-builds/environment-variables#setting-and-managing-env-vars-during-a-build). 1. Add the `deploy-to-bitrise-io` Step to view test results: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). ```yaml primary: description: | Builds project and runs tests. steps: - activate-ssh-key: {} - git-clone: {} - flutter-installer: inputs: - version: stable - restore-dart-cache: {} - flutter-test: inputs: - project_location: "$BITRISE_FLUTTER_PROJECT_LOCATION" - generate_code_coverage_files: 'yes' - tests_path_pattern: /lib/*_test.dart - save-dart-cache: {} - deploy-to-bitrise-io: {} ``` --- ## Building an iOS app for a simulator You can build an iOS app for an iOS or tvOS simulator platform. To do this, you'll need the **Xcode Build for Simulator** Step. The Step creates an `.app` file which you can install on any macOS device or send to, for example, testers. This requires no code signing at all, so it is an easy way to create a distributable version of your iOS app. The Step also creates an `.xctestrun` file which you can use to run tests. Both the `.app` file and the `.xctestrun` file can be accessed by subsequent Steps referring to their output variable, and they can be [downloaded as a build artifact](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online). To build the app for a simulator: **Workflow Editor** 1. Make sure you install all necessary dependencies in your Workflow. We have dedicated Steps for many different dependency managers, including: - [Carthage](https://bitrise.io/integrations/steps/carthage) - [CocoaPods](https://bitrise.io/integrations/steps/cocoapods-install) - [Homebrew](https://bitrise.io/integrations/steps/brew-install) 1. Add the **Xcode Build for Simulator** Step to your Workflow after the Step(s) installing dependencies. 1. Make sure the **Project path** input points to either your `.xcodeproj` or `.xcworkspace` file. The input sets the `-project` or `-workspace` option of the `xcodebuild` command. In most cases, if your app has been automatically configured by the project scanner during the [process of adding the app](/bitrise-ci/getting-started/adding-a-new-project), the default value does not need to be changed. 1. In the **Scheme** input, set the name of the [Xcode scheme](https://developer.apple.com/documentation/xcode/customizing-the-build-schemes-for-a-project/) you want to use to build the app. ![scheme-input.png](/img/_paligo/uuid-2700f022-4822-82fe-77e4-1a0995b41ab6.png) The input sets the `-scheme` option of the `xcodebuild` command. The default value is an Environment Variable created when adding the app and performing the first-time configuration. If you need to use a different scheme, you can type its name here. :::tip[Build configuration] By default, the Step will use the build configuration specified in the scheme. However, you can override it and use a different build configuration: add the name of the desired build configuration to the **Configuration name** input. This input is optional and you only need it if you don't want to use the build configuration specified in the selected scheme. You can create new build configurations in your Xcode project at any time: [Adding a build configuration file to your project](https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project). ::: 1. In the **Device destination specifier** input, select **generic/platform=iOS Simulator** ![ios-simulator-destination.png](/img/_paligo/uuid-7235d345-4190-c1be-6ee3-fc25e1eb183e.png) 1. Optionally, set the **Build settings (xcconfig), allow code signing** input to **CODE_SIGNING_ALLOWED=YES**. This allows code signing files to be installed during the build. In most cases, you don't need code signing for an app built for a simulator. It might be required for certain test cases or third-party dependencies. To set up code signing, see [iOS code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). 1. To access your app as a build artifact, add the **Deploy to Bitrise.io** Step to the end of your Workflow. By default, you don't have to modify anything in the Step's configuration. **Configuration YAML** 1. Make sure you install all necessary dependencies in your Workflow. We have dedicated Steps for many different dependency managers, including: - [Carthage](https://bitrise.io/integrations/steps/carthage) - [CocoaPods](https://bitrise.io/integrations/steps/cocoapods-install) - [Homebrew](https://bitrise.io/integrations/steps/brew-install) 1. Add the `xcode-build-for-simulator` Step to your Workflow after the Step(s) installing dependencies. ```yaml workflows: primary: steps: - cocoapods-install - xcode-build-for-simulator: inputs: ``` 1. Make sure the `project_path` input points to either your `.xcodeproj` or `.xcworkspace` file. The input sets the `-project` or `-workspace` option of the `xcodebuild` command. In most cases, if your app has been automatically configured by the project scanner during the [process of adding the app](/bitrise-ci/getting-started/adding-a-new-project), the default value does not need to be changed. ```yaml - xcode-build-for-simulator: inputs: - project_path: $BITRISE_PROJECT_PATH ``` 1. In the `scheme` input, set the name of the [Xcode scheme](https://developer.apple.com/documentation/xcode/customizing-the-build-schemes-for-a-project/) you want to use to build the app. The input sets the `-scheme` option of the `xcodebuild` command. The default value is an Environment Variable created when adding the app and performing the first-time configuration. If you need to use a different scheme, make sure to type the name of the scheme correctly. ```yaml - xcode-build-for-simulator: inputs: - scheme: $BITRISE_SCHEME - project_path: $BITRISE_PROJECT_PATH ``` :::tip[Build configuration] By default, the Step will use the build configuration specified in the scheme. However, you can override it and use a different build configuration: add the name of the desired build configuration to the `configuration` input. This input is optional and you only need it if you don't want to use the build configuration specified in the selected scheme. You can create new build configurations in your Xcode project at any time: [Adding a build configuration file to your project](https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project). ::: 1. Set the `destination` input to `generic/platform=iOS Simulator`. ```yaml - xcode-build-for-simulator: inputs: - scheme: $BITRISE_SCHEME - destination: generic/platform=iOS Simulator - project_path: $BITRISE_PROJECT_PATH ``` 1. Optionally, set the `xcconfig_content` input with the value `CODE_SIGNING_ALLOWED=YES`. This allows code signing files to be installed during the build. In most cases, you don't need code signing for an app built for a simulator. It might be required for certain test cases or third-party dependencies. To set up code signing, see [iOS code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). ```yaml - xcode-build-for-simulator: inputs: - scheme: $BITRISE_SCHEME - destination: generic/platform=iOS Simulator - xcconfig_content: |- CODE_SIGNING_ALLOWED=YES COMPILER_INDEX_STORE_ENABLE = NO - project_path: $BITRISE_PROJECT_PATH ``` 1. To access your app as a build artifact, add the `deploy-to-bitrise-io` Step to the end of your Workflow. By default, you don't have to modify anything in the Step's configuration. ```yaml workflows: primary: steps: - cocoapods-install: {} - xcode-build-for-simulator: inputs: - scheme: $BITRISE_SCHEME - destination: generic/platform=iOS Simulator - xcconfig_content: |- CODE_SIGNING_ALLOWED=YES COMPILER_INDEX_STORE_ENABLE = NO - project_path: $BITRISE_PROJECT_PATH - deploy-to-bitrise-io: {} ``` --- ## Building an iOS app for testing You can build an iOS app specifically for testing: our dedicated Step builds your app and its associated tests and also exports an `.xctestrun` file. Once built, you can upload the app to a third-party testing service or install it on a simulator or a physical device. You can also use this Step to set up [virtual device testing with Firebase](/bitrise-ci/testing/device-testing-with-firebase/device-testing-for-ios). The Step uses the `build-for-testing` action of `xcodebuild`. To learn more about it, see [How do I implement the Build For Testing and Test Without Building features from the command line?](https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-PRODUCT) :::important[Code signing] Installing the app on a test device requires [code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). The [**Xcode Build for testing for iOS**](https://github.com/bitrise-steplib/steps-xcode-build-for-test) Step has a built in code signing configuration: it allows [code signing with automatic provisioning](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning). In most use cases, you don't need any other Step to code sign your app for testing. ::: To build your iOS app for testing: **Workflow Editor** 1. For code signing, make sure you have connected your [Apple service account](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) to Bitrise. The Step accepts Apple ID and API key authentication for automatic code signing. We recommend using API key authentication. :::tip[Manual code signing] You can also use [manual code signing](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---manual-provisioning): in that case, do not configure the automatic code signing options of the Step. ::: 1. Make sure [you install all of the app's dependencies](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-carthage) in your Workflow. 1. Add the [**Xcode Build for testing for iOS**](https://github.com/bitrise-steplib/steps-xcode-build-for-test) Step to your Workflow after the Step or Steps installing dependencies. 1. Make sure the **Project path** input points to the correct location. The input asks for the path to your `.xcodeproj` or `.xcworkspace` file. In most cases, you don't need to change this input: when adding a new app, the project scanner automatically finds the relevant file and stores its location in the [Environment Variable](/bitrise-ci/configure-builds/environment-variables) that is the default value of the input. :::note[Checking the default value] If you are not sure whether the default value of the **Project path** input points to the right location, go to the **Env Vars** tab and check that the $BITRISE_PROJECT_PATH variable's value is the correct path to your `.xcodeproj` or `.xcworkspace` file. ::: :::important[CocoaPods] If you use CocoaPods as your dependency manager, the **Project path** input must point to the `.xcworkspace` file. ::: 1. Make sure the **Scheme** input points to the scheme you want to use to build the app. The default value is the Environment Variable that stores the scheme you set during the initial configuration of the app. If you wish to use a different scheme, type its name into the input field. 1. Set [the build configuration](https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project) you want to build in the **Build Configuration** input. The default value is `Debug`. ![build-for-testing-step.png](/img/_paligo/uuid-2a3bef35-3d78-72e7-102b-8aa11def397f.png) 1. Configure the device destination in the **Device destination specifier** input: the input takes comma-separated key-value pairs. Since the `build-for-testing` action can be performed without an actual specific device, we recommend targeting a platform generically: ```yaml // building for physical iOS devices generic/platform=iOS // building for simulators generic/platform=iOS Simulator ``` The input sets the `-destination` option of `xcodebuild`. Read more about the possible options: [How do I run unit tests from the command line?](https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT) 1. Optionally, set a specific [test plan](https://developer.apple.com/documentation/xcode/organizing-tests-to-improve-feedback?changes=_8) in the **Test plan** input. The input sets the `-testPlan` option of the `build-for-testing` action of `xcodebuild`. If you leave this empty, the test plan specified in the Xcode scheme will be used. 1. If you need code signing, we recommend using the [automatic code signing](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning) option: find the **Automatic code signing** input group, and choose a method from the dropdown menu of the **Automatic code signing method** input. ![auto-code-signing-input.png](/img/_paligo/uuid-cae7939a-c5e3-917f-5121-e7ef852362d5.png) :::note[Code signing certificates] Keep in mind that you need to upload [code signing certificates](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning#uploading-ios-code-signing-certificates-to-bitrise) to Bitrise in order to successfully sign your app. ::: We recommend using [API key authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key#adding-api-key-authentication-data-on-bitrise): a Bitrise-managed authentication method configured on the **App settings** page. If you want to control API authentication on a Step level instead, you can override the default Bitrise-managed connection by setting all three inputs that define a different API key authentication in the **App Store Connect connection override** input group: ![api-connect-override.png](/img/_paligo/uuid-a41c4d89-eb5f-0913-ac80-a0af31f99b54.png) 1. Add the [**Deploy to Bitrise.io**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step to the end of your Workflow to be able to access the generated artifacts either [on the **Artifacts** tab](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) or in the **Tests** tab. **Configuration YAML** 1. For code signing, make sure you have connected your [Apple service account](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) to Bitrise. The Step accepts Apple ID and API key authentication for automatic code signing. We recommend using API key authentication. :::tip[Manual code signing] You can also use [manual code signing](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---manual-provisioning): in that case, do not configure the automatic code signing options of the Step. ::: 1. Make sure [you install all of the app's dependencies](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-carthage) in your Workflow. 1. Add the `xcode-build-for-test` Step to your Workflow after the Step or Steps installing dependencies. ```yaml your-workflow: steps: - git-clone: {} - xcode-build-for-test: {} ``` 1. Make sure the `project_path` input points to the correct location. The input asks for the path to your `.xcodeproj` or `.xcworkspace` file. In most cases, you don't need to change this input: when adding a new app, the project scanner automatically finds the relevant file and stores its location in the [Environment Variable](/bitrise-ci/configure-builds/environment-variables) that is the default value of the input. ```yaml your-workflow: steps: - git-clone: {} - xcode-build-for-test: {} inputs: - project_path: "$BITRISE_PROJECT_PATH" ``` :::note[Checking the default value] If you are not sure whether the default value of the **Project path** input points to the right location, go to the **Env Vars** tab and check that the $BITRISE_PROJECT_PATH variable's value is the correct path to your `.xcodeproj` or `.xcworkspace` file. ::: :::important[CocoaPods] If you use CocoaPods as your dependency manager, the **Project path** input must point to the `.xcworkspace` file. ::: 1. Make sure the `scheme` input points to the scheme you want to use to build the app. The default value is the Environment Variable that stores the scheme you set during the initial configuration of the app. If you wish to use a different scheme, type its name into the input field. ```yaml your-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - project_path: $BITRISE_PROJECT_PATH ``` 1. Set [the build configuration](https://developer.apple.com/documentation/xcode/adding-a-build-configuration-file-to-your-project) you want to build in the `configuration` input. The default value is `Debug`: if you do not set a value for the input, the build will target the **Debug** configuration. ```yaml your-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - project_path: $BITRISE_PROJECT_PATH ``` 1. Configure the device destination in the `destination` input: the input takes comma-separated key-value pairs. Since the `build-for-testing` action can be performed without an actual specific device, we recommend targeting a platform generically: ```yaml // building for physical iOS devices - destination: generic/platform=iOS // building for simulators - destination: generic/platform=iOS Simulator ``` The input sets the `-destination` option of `xcodebuild`. Read more about the possible options: [How do I run unit tests from the command line?](https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT) ```yaml your-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - destination: generic/platform=iOS Simulator - project_path: $BITRISE_PROJECT_PATH ``` 1. Optionally, set a specific [test plan](https://developer.apple.com/documentation/xcode/organizing-tests-to-improve-feedback?changes=_8) in the `test_plan` input. The input sets the `-testPlan` option of the `build-for-testing` action of `xcodebuild`. If you leave this empty, the test plan specified in the Xcode scheme will be used. ```yaml your-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - destination: generic/platform=iOS Simulator - test_plan: my_plan - project_path: $BITRISE_PROJECT_PATH ``` 1. If you need code signing, we recommend using the [automatic code signing](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning) option: set the `automatic-code-signing` input to either of two values: `apple-id`: Use [Apple ID authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) to manage code signing. `api-key`: Use [API key authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) to manage code signing. :::note[Code signing certificates] Keep in mind that you need to upload [code signing certificates](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning#uploading-ios-code-signing-certificates-to-bitrise) to Bitrise in order to successfully sign your app. ::: ```yaml your-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - destination: generic/platform=iOS Simulator - test_plan: my_plan - automatic_code_signing: api-key - project_path: $BITRISE_PROJECT_PATH ``` We recommend using [API key authentication](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key#adding-api-key-authentication-data-on-bitrise): a Bitrise-managed authentication method configured on the **App settings** page. If you want to control API authentication on a Step level instead, you can override the default Bitrise-managed connection by setting three inputs that define a different API key authentication: - `api_key_path`: Local path or remote URL to the private key (p8 file) for the App Store Connect API. - `api_key_id`: Private key ID used for App Store Connect authentication. - `api_key_issuer_id`: Private key issuer ID used for App Store Connect authentication. :::important[All inputs required] All three inputs must be set for the authentication override to work! ::: ```yaml your-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - api_key_path: path/to/p8 - api_key_id: key_id - api_key_issuer_id: issuer_id ``` 1. Add the `deploy-to-bitrise-io` Step to the end of your Workflow to be able to access the generated artifacts either [on the **Artifacts** tab](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) or in the **Tests** tab. ```yaml your-workflow: steps: - git-clone: {} - xcode-build-for-test: inputs: - scheme: $BITRISE_SCHEME - configuration: Debug - destination: generic/platform=iOS Simulator - test_plan: my_plan - automatic_code_signing: api-key - project_path: $BITRISE_PROJECT_PATH - deploy-to-bitrise-io: {} ``` --- ## Registering a test device You have multiple options to register test devices on [bitrise.io](http://bitrise.io): - [Open Safari on your iOS device and access the **Test devices** tab from your **Account settings** page](#register-an-ios-device-using-safari). - [Manually register a device from the **Test devices** tab from your **Account settings** page](#register-a-test-device-manually). After registering your device on Bitrise, make sure to register it on the [Apple Developer Portal](https://developer.apple.com/) as well. We recommend using the [Xcode Archive & Export for iOS](https://github.com/bitrise-steplib/steps-xcode-archive) Step which can: - [Register all available test devices of the app](#registering-all-devices-on-the-apple-developer-portal). - [Register a selection of test devices, defined in a text file that contains a list of their UDIDs](#registering-a-selection-of-devices-on-the-apple-developer-portal). :::important[Apple Developer Portal device limit] There is a limit on registrable devices on the Apple Developer Portal, so make sure to [check the list of available test devices of an app](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device#checking-the-available-test-devices-for-an-app) before you use the [Xcode Archive & Export for iOS](https://github.com/bitrise-steplib/steps-xcode-archive) Step to register devices! ::: ### Register an iOS device using Safari The most comfortable way to register your iOS test device on [bitrise.io](https://www.bitrise.io) is to open [bitrise.io](https://www.bitrise.io) with Safari. This way we can open your device’s Settings and create a temporary profile to get your Unique Device Identifier (UDID). This way you don’t have to look for it and manually copy/paste it. :::important[Clear the cache] When trying to install an app from the public install page, you should clear the cache: click the link appearing in the **If you synced your settings from your old device, you need to clear the cache and register your new device** line. The link redirects to the **Account settings** page where you can follow the procedure described below. Read more about installing an app from the public install page in our [Deploying an iOS app to Bitrise.io](/bitrise-ci/deploying/ios-deployment/deploying-an-ios-app-to-bitrise-io) guide. ::: 1. Open Safari in **non-incognito mode** on your iOS device and log into [bitrise.io](https://www.bitrise.io). 1. Go to your **Profile**. 1. Tap **Account Settings**. 1. Tap **Test devices** on the left. 1. Tap **Register this device**. 1. In the pop-up window, Tap **Allow** so that [bitrise.io](https://www.bitrise.io) can show your configuration profile. 1. Tap **Install** when the **Install Profile** dialog appears. 1. Enter your devices’s passcode. 1. Tap **Install** on the **Install Profile** again. Now you can see your UDID and your iOS device name in the **Register device** dialog. 1. Tap **Register device**. 1. Register this test device to the [Apple Developer Portal](https://developer.apple.com/) with the correct provisioning profile added to your device or use our [Auto Provisioning](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning) step with enabling profile generation. If you go back to `Test devices`, you can see the registered device. You can delete the registered device any time if you click on the **Remove** button. :::note[Safari as default browser] If you encounter any issues with your registered device, we recommend you make Safari your default browser. ::: ### Register a test device manually 1. On bitrise.io, open the account selector menu on the top right and select **Account settings**. 1. On the menu on the left side, select **Test devices**. 1. Click on **Register device manually**. 1. In the **Register device** dialog, fill out the **Title** field and the **Identifier** field with your device’s UDID. 1. Click **Register Devices**. You can **get your UDID** if you plug your device into a computer, and open iTunes. Under **Summary**, you should see a Serial Number. If you click on it, it will reveal your device’s **UDID** which you can paste into the **Identifier** field on our [Test Devices](https://app.bitrise.io/users/sign_in#/test_devices). 1. Register this test device to the [Apple Developer Portal](https://developer.apple.com/) with the correct provisioning profile added to your device or use our [Auto Provisioning Step](/bitrise-ci/code-signing/ios-code-signing/managing-ios-code-signing-files---automatic-provisioning) with enabling profile generation. Now you can see your registered test device under the **Registered test devices** section. You can remove this registered device any time if you click the orange **x** icon. ### Checking the available test devices for an app For any Bitrise app, you can check out the registered test devices available on the **App Settings** page. This will show an aggregated list of all registered test devices associated with users who have access to your app, regardless of their role. You can use any of those devices to run tests of your app. You can also download the list of registered devices as a `.json` file. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the menu on the left side, select **Test devices**. 1. Optionally, you can download the entire list as a `.json` file: click the **Download as json** button. ### Registering devices on the Apple Developer Portal with the Xcode Archive Step The **Xcode Archive & Export for iOS** Step allows you to automatically register your test devices on the Apple Developer Portal. By default, the Step registers all test devices that you registered to your Bitrise account but you can configure it to only register a specific selection of devices. :::important[Apple Developer Portal limit] Please note that the Apple Developer Portal has a limit for devices registered for testing purposes, typically set at 100 devices per account. Devices registered with the **Xcode Archive & Export for iOS** Step count towards this limit and you can only remove registered devices once a year. ::: #### Registering all devices on the Apple Developer Portal **Workflow Editor** 1. Register your devices on Bitrise. - [Register using an iOS device](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device#register-an-ios-device-using-safari). - [Register manually on the **Account settings** page](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device#register-a-test-device-manually). 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add the **Xcode Archive & Export for iOS** Step to your Workflow. 1. In the **Automatic code signing** input group, set the **Register test devices on the Apple Developer Portal** input to `yes`. **Configuration YAML** 1. Register your devices on Bitrise. - [Register using an iOS device](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device#register-an-ios-device-using-safari). - [Register manually on the **Account settings** page](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device#register-a-test-device-manually). 1. In the Configuration YAML file, add the `xcode-archive` Step to your Workflow. ```yaml your-workflow: steps: - git-clone: {} - xcode-archive: inputs: ``` 1. Set the `register_test_devices` input to `yes`. ```yaml your-workflow: steps: - git-clone: {} - xcode-archive: inputs: - register_test_devices: 'yes' ``` #### Registering a selection of devices on the Apple Developer Portal **Workflow Editor** 1. Get the UDID of the devices you want to register: [Checking the available test devices for an app](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device#checking-the-available-test-devices-for-an-app). 1. Create a `.txt` file and add the UDIDs of all devices you want to register to the file in a comma-separated list: ```text 00000000-0000000000000001,00000000-0000000000000002,00000000-0000000000000003 ``` 1. Make sure Bitrise can access the file in a Workflow: You can commit it to your repository. [You can upload it to the Generic File Storage and use the **File Downloader** Step to access it](/bitrise-ci/run-and-analyze-builds/managing-build-files/using-files-in-your-builds#downloading-a-file-using-the-file-downloader-step). You can dynamically generate the file during the build. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add the **Xcode Archive & Export for iOS** Step to your Workflow. 1. In the **Automatic code signing** input group, set the **Register test devices on the Apple Developer Portal** input to **yes**. 1. In the same input group, add the path to the `.txt` file containing the UDIDs to the **Path of file containing the devices to be registered** input. :::note[Devices registered on Bitrise] This input takes priority over the devices registered to your Bitrise account. ::: **Configuration YAML** 1. Get the UDID of the devices you want to register: [Checking the available test devices for an app](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device#checking-the-available-test-devices-for-an-app). 1. Create a `.txt` file and add the UDIDs of all devices you want to register to the file in a comma-separated list: ```text 00000000-0000000000000001,00000000-0000000000000002,00000000-0000000000000003 ``` 1. Make sure Bitrise can access the file in a Workflow: You can commit it to your repository. [You can upload it to the Generic File Storage and use the **File Downloader** Step to access it](/bitrise-ci/run-and-analyze-builds/managing-build-files/using-files-in-your-builds#downloading-a-file-using-the-file-downloader-step). You can dynamically generate the file during the build. 1. In the Configuration YAML file, add the `xcode-archive` Step to your Workflow. ```yaml your-workflow: steps: - git-clone: {} - xcode-archive: inputs: ``` 1. Set the `register_test_devices` input to `yes`. ```yaml your-workflow: steps: - git-clone: {} - xcode-archive: inputs: - register_test_devices: 'yes' ``` 1. Set the path to the `.txt` file containing the UDIDs in the `test_device_list_path` input. :::note[Devices registered on Bitrise] This input takes priority over the devices registered to your Bitrise account. ::: ```yaml your-workflow: steps: - git-clone: {} - xcode-archive: inputs: - register_test_devices: 'yes' - test_device_list_path: path/to/the/file ``` --- ## Running unit and UI tests for iOS apps You can run both unit and UI tests for iOS apps on Bitrise with our dedicated Step. The Step runs the [test targets you defined](https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods/) in your Xcode project and [exports the results for you to view it in detail](/bitrise-ci/testing/deploying-and-viewing-test-results). To run Xcode tests on Bitrise, you need two Steps to run Xcode tests and view their results: [**Xcode Test for iOS**](https://github.com/bitrise-steplib/steps-xcode-test). **Deploy to**[**Bitrise.io**](http://Bitrise.io). :::note[Code signing files] Running Xcode tests and deploying their results to Bitrise do not require any [code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) files. So don’t worry about them just yet! ::: The [**Xcode Test for iOS**](https://github.com/bitrise-steplib/steps-xcode-test) Step runs your tests, exports your test results, the `.xcresult` file, all test attachments, and the log of the `xcodebuild test` command. :::tip[Xcode test results in HTML] You can also view your Xcode test results in a rich HTML format, using the [**Generate Xcode test report html**](https://github.com/bitrise-steplib/bitrise-step-generate-xcode-html-report) Step: [Viewing Xcode test results in rich HTML format](/bitrise-ci/testing/testing-ios-apps/viewing-xcode-test-results-in-rich-html-format). ::: To run tests using the Step: **Workflow Editor** 1. Make sure [you install all of the app's dependencies](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-carthage) in your Workflow. 1. Add the [**Xcode Test for iOS**](https://github.com/bitrise-steplib/steps-xcode-test) Step to the Workflow. 1. Make sure the **Project path** input points to the correct location. The input asks for the path to your `.xcodeproj,``.xcworkspace` , or `Package.swift` file. In most cases, you don't need to change this input: when adding a new app, the project scanner automatically finds the relevant file and stores its location in the [Environment Variable](/bitrise-ci/configure-builds/environment-variables) that is the default value of the input. ![xcode-test-for-ios.png](/img/_paligo/uuid-bba07440-4913-8b44-0391-1dd275534500.png) 1. Make sure the **Scheme** input points to the scheme you want to use to build the app. The default value is the [Environment Variable](/bitrise-ci/configure-builds/environment-variables) that stores the scheme you set during the initial configuration of the app. If you wish to use a different scheme, type its name to the input field. :::important[Shared scheme only] The scheme must be a shared Xcode scheme! ::: 1. Configure the device destination in the **Device destination specifier** input: the input takes comma-separated key-value pairs. For example, if you wish to build an app to test on an iPhone 14 with the latest available OS: ```bash platform=iOS,name=iPhone 14 Plus,OS=latest ``` The input sets the `-destination` option of `xcodebuild`. Read more about the possible options: [How do I run unit tests from the command line?](https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT) 1. Optionally, set a specific [test plan](https://developer.apple.com/documentation/xcode/organizing-tests-to-improve-feedback?changes=_8) in the **Test plan** input. The input sets the `-testPlan` option of the `test` action of `xcodebuild`. If you leave this empty, the test plan specified in the Xcode scheme will be used. 1. Add the [**Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step to the end of your Workflow to be able to access the test results and other outputs: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). **Configuration YAML** 1. Make sure [you install all of the app's dependencies](/bitrise-ci/dependencies-and-caching/ios-dependencies/managing-dependencies-with-carthage) in your Workflow. 1. Add the `xcode-test` Step to the Workflow. ```yaml your-workflow: steps: - activate-ssh-key: {} - git-clone: {} - xcode-test: inputs: ``` 1. Make sure the `project_path` input points to the correct location. The input asks for the path to your `.xcodeproj,``.xcworkspace` , or `Package.swift` file. In most cases, you don't need to change this input: when adding a new app, the project scanner automatically finds the relevant file and stores its location in the [Environment Variable](/bitrise-ci/configure-builds/environment-variables) that is the default value of the input. ```yaml your-workflow: steps: - activate-ssh-key: {} - git-clone: {} - xcode-test: inputs: - project_path: "$BITRISE_PROJECT_PATH" ``` 1. Make sure the `scheme` input points to the scheme you want to use to build the app. The default value is the [Environment Variable](/bitrise-ci/configure-builds/environment-variables) that stores the scheme you set during the initial configuration of the app. If you wish to use a different scheme, type its name to the input field. ```yaml your-workflow: steps: - activate-ssh-key: {} - git-clone: {} - xcode-test: inputs: - project_path: "$BITRISE_PROJECT_PATH" - scheme: test ``` :::important[Shared scheme only] The scheme must be a shared Xcode scheme! ::: 1. Configure the device destination in the `destination` input: the input takes comma-separated key-value pairs. For example, if you wish to build an app to test on an iPhone 14 with the latest available OS: ```yaml your-workflow: steps: - activate-ssh-key: {} - git-clone: {} - xcode-test: inputs: - project_path: "$BITRISE_PROJECT_PATH" - scheme: test - destination: platform=iOS Simulator,name=iPhone 14 Plus,OS=latest ``` The input sets the `-destination` option of `xcodebuild`. Read more about the possible options: [How do I run unit tests from the command line?](https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT) 1. Optionally, set a specific [test plan](https://developer.apple.com/documentation/xcode/organizing-tests-to-improve-feedback?changes=_8) in the `test_plan` input. The input sets the `-testPlan` option of the `test` action of `xcodebuild`. If you leave this empty, the test plan specified in the Xcode scheme will be used. ```yaml your-workflow: steps: - activate-ssh-key: {} - git-clone: {} - xcode-test: inputs: - project_path: "$BITRISE_PROJECT_PATH" - scheme: test - destination: platform=iOS Simulator,name=iPhone 11 Plus,OS=latest - test_plan: my_plan ``` 1. Add the `deploy-to-bitrise-io` Step to the end of your Workflow to be able to access the test results and other outputs: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). ```yaml your-workflow: steps: - activate-ssh-key: {} - git-clone: {} - xcode-test: inputs: - project_path: "$BITRISE_PROJECT_PATH" - scheme: test - destination: platform=iOS Simulator,name=iPhone 11 Plus,OS=latest - test_plan: my_plan - deploy-to-bitrise-io: ``` :::note[Headless mode] From Xcode 9 onwards, tests are run in headless mode by default: this means that the simulator will run in the background only. To change it, go to the Step’s Debug input group and set the **Run the simulator in headless mode** input’s value to `no`. However, with this option, tests will take more time. ```yaml - xcode-test: inputs: - headless_mode: 'no' ``` ::: :::important[Using xcpretty] The `xcpretty` output tool does not support parallel tests. If parallel tests are enabled in your project, go to the Step’s **xcodebuild log formatting** input group and set the **Log formatter** input’s value to `xcodebuild` or `xcbeautify`. ```yaml - xcode-test: inputs: - log_formatter: xcbeautify ``` ::: ### Rerunning failed tests (Not available in Xcode 13) The **Should retry test on failure? (Not available in Xcode 13+)** input in the **Test repetition** section of the **Xcode Test for iOS** Step allows you to automatically rerun ALL your tests, not just the failed ones. If you set this input to `yes`, the Step will run `xcodebuild` one more time in the case of test failure. From Xcode 13 and above, the feature is not available anymore. Use the **Test Repetitions Mode (Available in Xcode 13+)** input with the `retry_on_failure` option selected. This allows you to rerun only the failed test/s instead of running all your tests. You can find this test repetition feature with our **Xcode Test for iOS** Step from version 3.0.0 and above. ### Test Repetitions [Xcode’s test repetition modes](https://developer.apple.com/videos/play/wwdc2021/10296/) are available with the [Xcode Test for iOS Step](https://www.bitrise.io/integrations/steps/xcode-test) on stacks running Xcode 13 and above on Bitrise. With test repetitions, you can run any type of tests multiple times in various ways such as retry on failure, until failure and until max repetitions. The **Xcode Test for iOS** Step’s **Test Repetitions Mode (Available in Xcode 13+)** input offers the following options: - `none`: The tests won’t repeat. - `until_failure`: Repeats a test until the test fails or until the maximum repetition. The default number of test runs is three. - `retry_on_failure`: Failed tests run until they succeed or until the repetition number you specify. The default number of test repetitions is three. - `up_until_maximum_repetitions`: Reruns all tests until maximum test repetition is reached regardless of the test outcomes. ![test-repetition.png](/img/_paligo/uuid-d2ee7fd1-7743-7720-d114-5f38632cd2e1.png) Please note that these options are only available from **Xcode Test for iOS** version 3.0.0 and above. With the **Maximum Test Repetitions (Available in Xcode 13+)** input you can specify the maximum number of test repetitions. Please note that you have to add a greater number than one if the **Test Repetition Mode (Available in Xcode 13+)** input is set to other than `none`. Enable the **Relaunch Tests for Each Repetition (Available in Xcode 13+)** input to launch tests in a completely new process for each repetition. --- ## Viewing Xcode test results in rich HTML format Enhanced Xcode reporting allows you to immediately view your Xcode test results in a rich HTML format. It will show both successful and failed test cases, as well as any videos and screenshots generated by the test. To use it, your build needs to do two things: - Run your Xcode tests and place the `.xcresult` file in the correct location. The **Xcode Test for iOS** and the **Xcode Test for Building** Steps do this by default and require no further configuration. You can also use other Steps, for example, **fastlane**, but you need to specify where Xcode should place the `.xcresult` file. - Run the **Generate Xcode HTML report** Step: it takes the `.xcresult` file and generates the report. If you use the **Xcode Test for iOS** Step to run your tests, this Step requires no configuration. When using other Steps, you have to manually set the location of your `.xcresult` file. We strongly recommend using the official **Xcode Test for iOS** Step to run your tests: this Step generates an `.xcresult` file and the **Generate Xcode HTML report** Step finds it without any additional configuration. To view the rich test results: **Workflow Editor** 1. Add a Step that runs your Xcode tests to your Workflow. :::note[We recommend using the Xcode Test for iOS Step] Using our **Xcode Test for iOS** Step (as well as the **Xcode Test without building** Step) means you don't need any additional configuration to export your results. You can use other Steps to run your tests and then view the rich results afterwards. In that case, you have to make sure that the Step generates an `.xcresult` file and point the **Generate Xcode HTML report** Step to its location. For example, you can use the **fastlane** Step or your own **Script** Step. ::: For more information on configuring the Step to run your Xcode tests, see [Running unit and UI tests for iOS apps](/bitrise-ci/testing/testing-ios-apps/running-unit-and-ui-tests-for-ios-apps). 1. Add the **Generate Xcode HTML report** Step to your Workflow. It should, of course, come after the Step that runs your tests. 1. Make sure the **Xcresult file paths** input points to the location of your `.xcresult` files. You can add multiple `.xcresult` files to this input, either by specifying one or more directories or by specifying filepaths, separated by a newline (/n). Each file will have its own report. :::important[No configuration required] If you use the **Xcode Test for iOS** Step, you don't have to modify this input! ::: ![generate-xcode-reports_input.png](/img/_paligo/uuid-a928eed7-d498-758b-6a6c-5a8ef7b202d1.png) 1. Make sure the Workflow includes the **Deploy to Bitrise.io** Step at the end. Without this Step, the results won't be exported. :::important[Version requirement] The Step must be version 2.7.2 or newer. ::: 1. After the build is finished, go to the build summary page. :::note[Failed builds] The test results will be available even if the build fails. ::: 1. Select the **Tests** tab to view the results. :::important[Expiry date] The HTML test reports are available for seven days after they are generated. After seven days, you can no longer access them. ::: ![html-test-result.png](/img/_paligo/uuid-bf85c17c-277e-088a-13b0-3fe96e79cc7d.png) **Configuration YAML** 1. Add a Step that runs your Xcode tests to your Workflow. We strongly recommend using the `xcode-test` Step for this. ```yaml my-workflow: steps: - xcode-test: {} ``` :::note[We recommend using the xcode-test Step] Using our `xcode-test` Step (as well as the `xcode-test-without-building` Step) means you don't need any additional configuration to export your results. You can use other Steps to run your tests and then view the rich results afterwards. In that case, you have to make sure that the Step generates an `.xcresult` file and point the `generate-xcode-html-report` Step to its location. For example, you can use the `fastlane` Step or your own `script` Step. ::: For more information on configuring the Step to run your Xcode tests, see [Running unit and UI tests for iOS apps](/bitrise-ci/testing/testing-ios-apps/running-unit-and-ui-tests-for-ios-apps). 1. Add the `generate-xcode-html-report` Step to your Workflow. It should, of course, come after the Step that runs your tests. ```yaml my-workflow: steps: - xcode-test: {} - generate-xcode-html-report: {} ``` 1. Make sure the `xcresult_patterns` input points to the location of your `.xcresult` files. You can add multiple `.xcresult` files to this input, either by specifying one or more directories or by specifying filepaths, separated by a newline (/n). Each file will have its own report. ```yaml my-workflow: steps: - xcode-test: {} - generate-xcode-html-report: is_always_run: true inputs: - xcresult_patterns: /path/to/MyApp.xcresult ``` :::important[No configuration required] If you use the **Xcode Test for iOS** Step, you don't have to modify this input! ::: 1. Make sure the Workflow includes the `deploy-to-bitrise-io` Step at the end. Without this Step, the results won't be exported. :::important[Version requirement] The Step must be version 2.7.2 or newer. ::: ```yaml my-workflow: steps: - xcode-test: {} - generate-xcode-html-report: is_always_run: true inputs: - xcresult_patterns: /path/to/MyApp.xcresult - deploy-to-bitrise-io: {} ``` 1. After the build is finished, go to the build summary page. :::note[Failed builds] The test results will be available even if the build fails. ::: 1. Select the **Tests** tab to view the results. :::important[Expiry date] The HTML test reports are available for seven days after they are generated. After seven days, you can no longer access them. ::: ![html-test-result.png](/img/_paligo/uuid-bf85c17c-277e-088a-13b0-3fe96e79cc7d.png) :::caution Please note that the generated HTML report is not official Bitrise content! It is generated entirely according to your Workflow configuration. Bitrise has no direct control over what appears in the report. ::: --- ## Running Detox tests on Bitrise Detox is a gray box end-to-end tests and automation library for mobile apps built with React Native. It supports both iOS and Android apps. If you have a React Native app on Bitrise, you can run Detox tests. ### Before you start Running Detox requires: - A Mac with a macOS (El Capitan 10.11 or newer version). - Xcode 8.3 or newer version with Xcode command line tools. - A working React Native app. [Install and set up Detox for your project](https://wix.github.io/Detox/docs/introduction/getting-started/). You will need to install Homebrew, Node.js and applesimutils, as well as the Detox command line tools. Add Detox to your project and then create and run Detox tests locally. If you have an Android app, go through [this guide](https://wix.github.io/Detox/docs/guide/android-dev-env/) after the initial setup process. Once you are done, you can test your Detox-configured project on Bitrise. ### Running a Detox test 1. Create a release device configuration either in the `package.json` file under the `detox` section, or in a separate Detox configuration file. For more information on setting up a Detox configuration, check out the documentation: [Project setup](https://wix.github.io/Detox/docs/introduction/project-setup/). Example: ```yaml "detox": { "configurations": { "ios.sim.debug": { "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/SampleProjectReactNative.app", "build": "xcodebuild -project ios/SampleProjectReactNative.xcodeproj -scheme SampleProjectReactNative -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build -UseNewBuildSystem=NO", "type": "ios.simulator", "name": "iPhone 8" }, "ios.sim.release": { "binaryPath": "ios/build/Build/Products/Release-iphonesimulator/SampleProjectReactNative.app", "build": "xcodebuild -project ios/SampleProjectReactNative.xcodeproj -scheme SampleProjectReactNative -configuration Release -sdk iphonesimulator -derivedDataPath ios/build -UseNewBuildSystem=NO", "type": "ios.simulator", "name": "iPhone 8" } }, ``` 1. On [bitrise.io](https://www.bitrise.io/), go to your project and open the **Workflow Editor.** 1. Switch to the Workflow you want to use. 1. Add a **Run npm command** Step to your Workflow. 1. Install the Detox CLI and the React Native CLI using the **npm command with arguments to run** input: ```bash install -g detox-cli install -g react-native-cli ``` 1. Install a test runner. For example, [our sample app](https://github.com/bitrise-samples/sample-project-react-native) uses `mocha`, installed with the `yarn` Step. To install yarn dependencies, just set the **The yarn command to run** input’s value to `install`. 1. Add a **Script** Step to install the necessary utilities and then run Detox. ```bash #!/bin/bash # applesimutils is a collection of utils for Apple simulators brew tap wix/brew brew install applesimutils # we are building and testing a release device configuration detox build --configuration ios.sim.release detox test --configuration ios.sim.release --cleanup ``` You can, of course, put each of these commands in separate Script Steps, for the sake of modularity. 1. Run a build. If the build fails, check out our example `bitrise.yml` file: ```yaml --- workflows: primary: steps: - activate-ssh-key: {} - git-clone: inputs: - clone_depth: '' title: Git Clone Repo - yarn: inputs: - command: install - npm: inputs: - command: install -g detox-cli title: Install Detox CLI - script: inputs: - content: |- #!/bin/bash brew tap wix/brew brew install applesimutils detox build --configuration ios.sim.release detox test --configuration ios.sim.release --cleanup title: Detox - Build and Test Release App - deploy-to-bitrise-io: {} ``` ### Troubleshooting Detox tests If you run into issues with using Detox on Bitrise, we recommend trying to rebuild the entire Detox package before running the test. To do so, run the following command in your Bitrise build: ```text `npm rebuild detox` ``` If your Detox tests still fail or hang, contact our support! --- ## Running unit and UI tests for React Native apps You can run all kinds of tests for your React Native app on Bitrise: unit tests, integration tests, or component tests. You can use [Jest](https://jestjs.io/), for example, to write all your tests and then run them during the build process with either [npm](https://www.npmjs.com/) or [Yarn](https://yarnpkg.com/). :::tip[E2E testing] For end-to-end testing, check out Detox: [Running Detox tests on Bitrise](/bitrise-ci/testing/testing-react-native-apps/running-detox-tests-on-bitrise). ::: **Workflow Editor** 1. Write your tests and add them to your React Native project. 1. On Bitrise, add either the [**Run npm command**](https://github.com/bitrise-steplib/steps-npm) or the [**Run yarn command**](https://github.com/bitrise-community/steps-yarn) Step to your Workflow, depending on which package manager you use in your project. 1. Configure the Step to run the `test` command: - For Yarn, find the **Arguments for running yarn commands** input and add `test`. - For npm, find the **The npm command with arguments to run** input and add `test`. ![npm-test.png](/img/_paligo/uuid-195577ac-fbba-5fe4-810b-3749e614682c.png) In either case, the Step will run the `test` script in the `scripts` object of your package. **Configuration YAML** 1. Write your tests and add them to your React Native project. 1. In the Configuration YAML file, add either the `npm` or the `yarn` Step to your Workflow, depending on which package manager you use in your project. 1. Configure the Step of your choice to run the `test` command: for either Step, set the `command` input to `test`. ```yaml empty: steps: - git-clone: {} - npm: inputs: - command: test - yarn@0: inputs: - command: test - deploy-to-bitrise-io: {} ``` Either Step will run the `test` script in the `scripts` object of your package. Run the tests and view their results: [Deploying and viewing test results](/bitrise-ci/testing/deploying-and-viewing-test-results). --- ## AI configuration assistant :::note This is a beta feature, currently available only to customers on Starter and Pro plans. If you are on an Enterprise plan, please contact your customer success manager to enable it. ::: Bitrise offers hundreds of integrations for all CI/CD purposes, allowing complex workflows. It takes time to become familiar with our Steps, our stacks, or the intricacies of configuration YAML - time that you could spend developing your app. To speed up the process, we introduced the AI configuration assistant. The AI config assistant is a chat-based assistant built into the Bitrise Workflow Editor that turns natural-language descriptions into validated YAML. You describe what you want in plain language: for example, "build an iOS app with Fastlane and send artifacts to Slack". The assistant produces a working Workflow or Pipeline that you can refine and iterate on either with the help of the assistant or manually. The assistant can also explain, in plain language, a given Workflow or Pipeline, including what each Step does. It can also suggest improvements. You can request modifications and improvements for an already existing Workflow or Pipeline even if it was created manually. ### Enabling the AI configuration assistant The AI configuration assistant requires two separate toggles to be enabled: one at the workspace level and one at the project level. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Select **AI settings**. 1. Enable the **Enable AI features** toggle. This turns on Bitrise AI for the workspace. Individual AI features still need to be enabled separately in each project's settings. ![Workspace settings — AI settings page with the Enable AI features toggle](/img/workflows-and-pipelines/2026-07-03-workspace-settings-ai-settings.png) 1. Open your project on the Bitrise CI page and click **Project settings**. 1. Select **Bitrise AI** in the left navigation. 1. Under **Workflows and pipelines**, enable the **Configuration generator** toggle. ![Project settings — Bitrise AI page with the Configuration generator toggle enabled](/img/workflows-and-pipelines/2026-07-03-project-settings-bitrise-ai-configuration-generator.png) :::note[AI credits] AI features consume monthly AI credits. The number of credits available depends on your plan. You can check your remaining credits on the **Bitrise AI** page in Project settings. ::: Once both toggles are enabled, the AI configuration assistant is available in the Workflow Editor. ### Explaining a Workflow or a Pipeline You can get the AI assistant to explain how any part of your Bitrise configuration works and it can suggest improvements to existing Workflows and Pipelines. To get an explanation, open a Workflow Editor and select a Workflow or Pipeline. Next to its name, click **Explain**. The AI assistant will open with a prompt already submitted. For example, if you click the button for a Workflow called **test**, the prompt will be **Explain 'test' workflow**. The explanation aims to cover all parts of the configuration: the triggers and the Environment Variables belonging to the Workflow, the infrastructure, including the stack and the machine type, and the Steps, each with its own explanation. The assistant also provides information about the usage of the Workflow in other contests: for example, whether it's part of a Pipeline and what function it serves there. ### Creating a Workflow or Pipeline with the AI assistant Use the Bitrise AI configuration assistant to create a fully validated, working Workflow or Pipeline. Use plain language to list your requirements and the AI will create a configuration that you can modify at any point. It will be available in the Workflow Editor and in your configuration YAML file just as any other Workflow or Pipeline. 1. Open the Workflow Editor. 1. On the top bar, click **Ask AI**. 1. In the **Assistant** window, select **Create a new Workflow**. :::note You can also open the Workflow selector dropdown and click **Create Workflow with AI** at the bottom of the list. ::: 1. Add your prompt in the input field. Use plain language to explain what you need the Workflow or Pipeline to do. You don't have to use Step names or Bitrise-specific terms. The more detailed your prompt is, the better the AI output. :::note While the AI assistant is working, you can modify your configuration manually. However, your changes will be overwritten when the assistant is ready and you apply its changes. ::: 1. Ask for changes if you need them. You can keep iterating. 1. When finished, click **Apply changes**. This overwrites your configuration YAML file. --- ## About Pipelines A Bitrise Pipeline is the top level of our CI/CD configuration. Pipelines can be used to organize the entire CI/CD process and to set up advanced configurations with multiple different tasks running parallel and/or sequentially. A Pipeline allows you to configure dependencies between Workflows. Each Workflow starts executing when its parent Workflows are done. Workflows on the same level are executed in parallel: ![pipeline-example.png](/img/_paligo/uuid-e85b689a-0101-6664-7f58-6e9ae5c851a7.png) In this example, B and C are executed, in parallel, once A is successful. D is executed once B and C are both successful. Read more about Pipelines: - [Configuring a Bitrise Pipeline](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline) - [Pipeline builds](/bitrise-ci/workflows-and-pipelines/build-pipelines/pipeline-builds) - [Default Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/default-pipelines) --- ## Build Pipelines FAQ **Can I use Pipelines if I store my bitrise.yml file in my own repository?** Yes, absolutely. It makes no difference to Pipelines. **How can I set the stack for my Pipeline?** In the current version, you can set the default stack for your app, or you can set Workflow-specific stacks, just like with standalone builds: [Setting the stack for your builds](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds). **How can I use Environment Variables with a Pipeline?** You can keep using project-level and Workflow-level [Environment Variables](/bitrise-ci/configure-builds/environment-variables). **Can I rerun a failed Pipeline?** Yes. Go to the **Pipeline details** page, and click the **Rebuild** button. From there you have the option to rebuild unsuccessful Workflows or to rebuild the entire Pipeline. Both options are also available with remote access. **Does the Rolling Builds feature work on Pipelines?** Yes! You don’t have to worry about wasting credits with builds that are no longer necessary because of new commits or pull requests. --- ## Configuring a Bitrise Pipeline :::important[Pipelines with stages] If you have an existing Pipeline configuration from before December 2024, you probably have stages in your Pipeline. We strongly recommend to stop using stages and instead focus on configuring dependencies between Workflows. These dependencies determine the order of execution in a Pipeline. This eliminates unnecessary waiting time in stages and allows you to create more flexible CI configurations. You can keep using Pipelines with stages but they will receive no updates in the future. You can have both types of Pipelines in the same configuration YAML file but you can't mix and match the two types: you can't have both stages and Workflow dependencies in the same Pipeline. You can find the documentation for Pipelines with stages here: [Pipelines with stages](/bitrise-ci/workflows-and-pipelines/build-pipelines/pipelines-with-stages/configuring-a-pipeline-with-stages). You can convert a Pipeline with stages into the new format: [Converting a Pipeline with stages into a graph Pipeline](/bitrise-ci/workflows-and-pipelines/build-pipelines/converting-a-pipeline-with-stages-into-a-graph-pipeline). ::: You can define your Pipelines under a `pipelines` element in a configuration YAML file. You can use the following elements to set up a Pipeline: - A Pipeline name: the human readable identifier of the Pipeline. - The `workflows` element: this contains a list of the Workflows that are part of the Pipeline. - The `depends_on` property: This is a property of the `workflows element` and accepts an array of Workflow names. It defines the dependencies between Workflows. For example, here's a simple Pipeline configuration: ![pipeline-example.png](/img/_paligo/uuid-e85b689a-0101-6664-7f58-6e9ae5c851a7.png) In this Pipeline, we have four Workflows: 1. Workflow A runs first. 1. Once Workflow A is finished, Workflows B and C start at the same time. 1. Workflow D starts only when both Workflows B and C are successfully finished. ### Creating a Pipeline **Workflow Editor** Open the Workflow Editor and select **Pipelines** on the left. Click **Create Pipeline** and set a name, then click **Create Pipeline** again. To add your first Workflow, click **Workflows**. ![add-workflow-pipeline.png](/img/_paligo/uuid-6f5bdb24-c8e6-3923-723f-07a33eae84bc.png) You can keep adding Workflows this way. This method creates no dependencies between Workflows: they will all run at the same time. ![basic-pipeline.png](/img/_paligo/uuid-13e965a3-cef3-17c5-970b-b4308460ae26.png) A Workflow can depend on one or more Workflows: if any of the Workflows it depends on fails, the Workflow won't run. To create Workflow dependencies, hover over the right end of a Workflow and click the plus sign: ![add-dependent-workflow.png](/img/_paligo/uuid-cc676406-6eb6-010a-1daa-9a687d3902ea.png) You can add multiple dependent Workflows to the same Workflow this way: ![multiple-dependent-flows.png](/img/_paligo/uuid-9e8845d9-aa8e-6c98-642a-4e13fddf93ea.png) The same Workflow can depend on two or more different Workflows: you can create a path by dragging from the plus sign to another Workflow already in the Pipeline: ![drag-and-drop-dep.png](/img/_paligo/uuid-636d0224-45fb-307d-a1d5-69a7d8e84d9f.png) **Configuration YAML** A bare minimum Pipeline configuration consists of a single Workflow: ```yaml pipelines: example: workflows: A: {} ``` You can have multiple Workflows that all run in parallel: ```yaml pipelines: example: workflows: A: {} B: {} C: {} ``` A Workflow can depend on one or more Workflows: if any of the Workflows it depends on fails, the Workflow won't run. To create Workflow dependencies, you need to use the `depends_on` property: ```yaml pipelines: example: workflows: A: {} B: depends_on: - A C: depends_on: - A D: depends_on: - B - C ``` If a Workflow depends on multiple Workflows, both YAML array syntaxes can be used: ```yaml # Option 1 D: depends_on: - B - C # Option 2 D: depends_on: [A, B] ``` ### Configuration restrictions - A Pipeline can have a maximum of 200 Workflows. Each must be an existing Workflow under the root level `workflows` element. - [Utility Workflows](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#utility-workflows) can't be added to a Pipeline. If you want to use utility Workflows, include them as part of a regular Workflow. - Each Workflow can be added to the same Pipeline only once. You can't include the same Workflow in multiple different parts of a Pipeline. - Any Workflow defined in the dependency list must be part of the same Pipeline. - The dependency graph resulting from your configuration can't contain a circle or loop. You can't start builds with an invalid Pipeline configuration. ### Conditional Workflow execution in a Pipeline Use `run_if` expressions to control Workflow execution: you can set conditions under which a Workflow should or should not run. **Workflow Editor** 1. 1. Open your Pipeline. 1. Hover over the Workflow you need and click the gear icon to open the Edit Workflow dialog. ![workflow-properties-edit.png](/img/_paligo/uuid-df55cc4e-3e1f-2b08-c111-6e0a231065fd.png) 1. Select **Pipeline Conditions**. 1. In the **Additional running conditions** input, add a valid [Go template](https://pkg.go.dev/text/template). The input accepts three helper functions: - `getenv`: Accesses an Environment Variable's value. - `enveq`: Compares an Environment Variable to a given value. - `envcontain`: Checks whether an Environment Variable contains a given string. ![run-if-template.png](/img/_paligo/uuid-4ababac0-1bb5-1f86-165a-f31d14fa9f28.png) 1. Close the Edit Workflow dialog, and click **Save changes**. **Configuration YAML** In Pipelines, the `run_if` property needs an `expression` field that contains a [Go template](https://pkg.go.dev/text/template): ```yaml pipelines: example: workflows: A: {} B: run_if: expression: {{ enveq "EXAMPLE_KEY" "example value" }} depends_on: [A] ``` The `expression` field accepts three helper functions: - `getenv`: Accesses an Environment Variable's value. - `enveq`: Compares an Environment Variable to a given value. - `envcontain`: Checks whether an Environment Variable contains a given string. The Bitrise CLI evaluates the expression during runtime: a Workflow only runs if its `run_if` expression evaluates to `true`. A Workflow that is skipped because of a `run_if` expression is counted as a successful Workflow so its dependent Workflows will run. In this example, B will only run if the EXAMPLE_KEY Environment Variable has the value `example value`. Because a skipped Workflow counts as successful, a Pipeline where every Workflow is skipped still finishes successfully and reports a green status to your Git provider. You can use a skipped Workflow to pass a required status check on pull requests that shouldn't trigger a build, such as documentation-only changes. For how to set this up reliably, see [Passing a required check on documentation-only pull requests](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider#passing-a-required-check-on-documentation-only-pull-requests). ### Always executing a Workflow in a Pipeline You can mark a Workflow to make sure it runs even if a Workflow it depends on failed. :::important[Transitive dependency] Even if a Workflow is configured to always run, its dependent Workflows might not run. If one or more of its parent Workflows failed, the Workflow in question will still run but its dependent Workflows might not. For example, let's say we have Workflow C that depends on Workflow B. Workflow B depends on Workflow A. Of the three Workflows, only B is set to always run: - If A fails, B will run but regardless of its result, C won't run because by depending on B, it also depends on A. - C only runs if both A and B are successful. ::: **Workflow Editor** 1. 1. Open your Pipeline. 1. Hover over the Workflow you need and click the gear icon to open the Edit Workflow dialog. ![workflow-properties-edit.png](/img/_paligo/uuid-df55cc4e-3e1f-2b08-c111-6e0a231065fd.png) 1. Select **Pipeline Conditions**. 1. Set the **Always run** input to **Workflow**. This setting means the Workflow will run even if one or more of its parent Workflows fail. However, its dependent Workflows might not run! **Configuration YAML** Use the `should_always_run` property. It requires a string to specify the scope of the configuration. It has two available values: - `none`: If a parent Workflow fails, the Workflow will not run. This is the default value. - `workflow`: If a parent Workflow fails, the Workflow will run anyway. ```yaml pipelines: example: workflows: A: {} B: depends_on: [ A ] should_always_run: workflow C: depends_on: [ B ] D: depends_on: [ C ] should_always_run: workflow ``` In this example: - If A fails, B still runs. - If either A or B fails, C won't run. - If C won't run or runs but fails, D will still run. ### Aborting the Pipeline on Workflow failure You can configure the Pipeline to immediately terminate when any given Workflow fails. By default, the Pipeline won't terminate **Workflow Editor** 1. 1. Open your Pipeline. 1. Hover over the Workflow you need and click the gear icon to open the Edit Workflow dialog. ![workflow-properties-edit.png](/img/_paligo/uuid-df55cc4e-3e1f-2b08-c111-6e0a231065fd.png) 1. Select **Pipeline Conditions**. 1. Toggle the **Abort Pipeline on failure** input on. If the Workflow in question fails, the Pipeline will immediately stop running. **Configuration YAML** Add the `abort_on_fail` field set to `true` to the selected Workflows: ```yaml pipelines: example: workflows: A: {} B: abort_on_fail: true ``` In this example, the Pipeline stops running if Workflow B fails: Workflow A will be aborted and no subsequent Workflows will run. ### Pipeline priority You can set a priority for each Pipeline. The priority setting determines the position of the Pipeline build in the build queue: the higher the priority, the sooner the Pipeline build will run. You can assign a priority either in the Workflow Editor or in the configuration YAML file of your project. The priority is always an integer between -100 and 100: the higher the number, the higher the priority. The default priority is 0. For more information about build priority, and the order of precedence between different types of priorities, check out [Build priority](/bitrise-ci/configure-builds/configuring-build-settings/build-priority). ### Sharing files between Workflows in a Pipeline To share files between Workflows in a Pipeline, you can use the **Deploy to Bitrise.io** Step and the **Pull Pipeline intermediate files** Step. The Step downloads Pipeline intermediate files to a local folder. To configure file sharing: **Workflow Editor** 1. Add the **Deploy to Bitrise.io** Step to the Workflow that generates the file(s) you need. 1. In the **Pipeline Intermediate File Sharing** input group, find the **Files to share between Pipeline Workflows** input and add the files as a newline-separated list of colon-separated items using the following structure: `:`. You can use another Environment Variable as a filepath: for an iOS project, `$BITRISE_IPA_PATH:BITRISE_IPA_PATH` is a valid way to share a generated IPA with other Workflows. 1. Add the **[Pull Pipeline intermediate files](https://www.bitrise.io/integrations/steps/pull-intermediate-files)** Step to any Workflow that needs the generated files. 1. Use the **Intermediate file source** input to specify a set of Workflows from which you need files. ![pipeline-intermediate.png](/img/_paligo/uuid-5d9fd00b-0507-1ae7-80a2-b42a4377343e.png) You can use wildcards in the input. In the example above, we’re pulling all intermediate files from all Workflows which have a name starting with `workflow`. 1. When the Step finishes, your files and directories specified via the **[Deploy to Bitrise.io - Apps, Logs, Artifacts](https://www.bitrise.io/integrations/steps/deploy-to-bitrise-io)** Step should be available. **Configuration YAML** 1. Add the **Deploy to Bitrise.io** Step to the Workflow that generates the file(s) you need. 1. Add the files to the `pipeline_intermediate_files` input as a newline-separated list of colon-separated items using the following structure: `:`. You can use another Environment Variable as a filepath: for an iOS project, `$BITRISE_IPA_PATH:BITRISE_IPA_PATH` is a valid way to share a generated IPA with other Workflows. ```yaml steps: - deploy-to-bitrise-io: { inputs: - pipeline_intermediate_files: "$BITRISE_IPA_PATH:BITRISE_IPA_PATH" ``` 1. Add the **[Pull Pipeline intermediate files](https://www.bitrise.io/integrations/steps/pull-intermediate-files)** Step to any Workflow that needs the generated files: ```yaml steps: - pull-intermediate-files: {} ``` 1. Use the `artifact_sources` input to specify a set of Workflows from which you need files: ```yaml steps: - pull-intermediate-files@1: inputs: - artifact_sources: workflow.* ``` You can use wildcards in the input. In the example above, we’re pulling all intermediate files from all Workflows which have a name starting with `workflow`. 1. When the Step finishes, your files and directories specified via the **[Deploy to Bitrise.io - Apps, Logs, Artifacts](https://www.bitrise.io/integrations/steps/deploy-to-bitrise-io)** Step should be available. For more information and details, check out the [Step repository](https://www.bitrise.io/integrations/steps/pull-intermediate-files). ### Sharing Env Vars between Workflows You can reuse any environment variable from a Workflow and reuse it in subsequent Workflows using the [Share Pipeline variables](https://github.com/bitrise-steplib/bitrise-step-share-pipeline-variable) Step. :::tip[Optional Workflows using run_if conditions] You can easily combine the [**Share Pipeline variables**](https://github.com/bitrise-steplib/bitrise-step-share-pipeline-variable) Step with `run_if` expressions to create Pipelines with optional Workflows. For more information, check out [Enabling or disabling a Step conditionally](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally). ::: To do so: 1. Add the [**Share Pipeline variables**](https://github.com/bitrise-steplib/bitrise-step-share-pipeline-variable) Step to the Workflow. 1. Optionally, you can define additional run conditions in the **Additional run conditions** input. The Step will only run if the conditions you specify here are true. 1. Add the Env Var(s) you would like to use in subsequent Workflows in the **Variables to share between Pipeline Workflows** input. :::tip[Using environment variable keys] You can define Env Vars using a `{key}={value}` syntax. For example, `MY_ENV_KEY=value`, or `INSTALL_PAGE_URL=$BITRISE_PUBLIC_PAGE_URL`. If you want to use the default environment variable keys, you can use a shorthand syntax. For example, `EXISTING_ENV_KEY`. Sharing Env Vars using this Step does not override existing Env Vars defined in the app. ::: ### Running variations of the same Workflow Parallelism allows you to split the execution of a single Workflow in a Pipeline over many runners in a single instruction. This is particularly useful for test sharding: you can reuse a single testing Workflow several times over, without needing to specify boilerplate code for each shard. At runtime, Bitrise automatically creates a set of parallel Workflows and provides you with the shard number and total number of shards as environment variables. You can also use a parallel configuration to build and test multiple white label apps from the same codebase, or to achieve any other goal that requires running the same CI jobs multiple times. #### Parallelism overview :::important[Graph pipelines only] Parallelism isn't available for Pipelines containing stages. To take advantage of the feature, convert your stage-based Pipelines into graph Pipelines: [Converting a Pipeline with stages into a graph Pipeline](/bitrise-ci/workflows-and-pipelines/build-pipelines/converting-a-pipeline-with-stages-into-a-graph-pipeline). ::: You can create a parallel configuration for a Workflow by using the `parallel` property. A Pipeline can have multiple Workflows with a parallel configuration. These Workflows can depend on other Workflows. If a Workflow depends on a Workflow with a parallel configuration, it will depend on the execution of all copies of the Workflow. The `parallel` property takes an integer for a value: for example, if the value is 5, five copies of the Workflow will be executed. Each copy receives two new environment variables: - $BITRISE_IO_PARALLEL_INDEX: a zero based index for each copy of the Workflow. - $BITRISE_IO_PARALLEL_TOTAL: the total number of copies. #### Configuring parallelism To set up the configuration: **Workflow Editor** 1. Open the Workflow Editor. 1. In the Pipeline graph, find your Workflow and click the gear icon to access the Workflow configuration. 1. On the **Configuration** tab, find the **Parallel copies** input and set a value. :::important[Value limitations] The value has to be a fixed number. You can only use integers. The maximum accepted value is 200. You can use an Environment Variable as the value: it allows you to dynamically calculate the optimal number of parallel copies during the build. ::: If another Workflow depends on the Workflow with a parallel configuration, it will run only if all copies of the Workflow have been successful. **Configuration YAML** 1. Open your [configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/accessing-a-build-s-bitrise-yml-file) file. 1. In the `workflows` property of your Pipeline, find the Workflow you need. 1. Add the `parallel` property to it and set a value. :::important[Value limitations] The value has to be a fixed number. You can only use integers. The maximum accepted value is 200. You can use an Environment Variable as the value. You can use an Environment Variable as the value: it allows you to dynamically calculate the optimal number of parallel copies during the build. ::: In this example, the `run-tests` Workflow is executed five times in parallel. The `report-results` Workflow depends on `run-tests` so it only runs once all 5 copies have been successful. ```yaml pipelines: my-ci-pipeline: workflows: build-without-testing: {} run-tests: depends_on: [build-without-testing] parallel: 5 report-results: depends_on: [run-tests] ``` ### Supported use cases for Pipelines We have prepared some Pipeline recipes based on common iOS and Android use cases. These contain some of the most frequent tasks our users need to run. You can find them in our [GitHub repository](https://github.com/bitrise-io/workflow-recipes/tree/main/recipes). ### Troubleshooting a Pipeline If a Pipeline build fails, you have two main options: - [Rebuild the Pipeline](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline). You can rebuild either the entire Pipeline, or the failed Workflows. - Rebuild with [remote access](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/remote-access) which allows you to access the build machine while the build is running. --- ## Converting a Pipeline with stages into a graph Pipeline You can convert your old, existing Pipelines that contain stages into graph Pipelines without stages. This unlocks the full benefits of using Pipelines: faster build times, more granular configuration, and a full editing capability in the Workflow Editor. Pipelines with stages are read-only in the Workflow Editor. To edit them, you need to convert them first. The original Pipeline won't be removed and will still work after the conversion, so your builds won't break. You can switch to using the new Pipeline when all your configurations are ready. :::note All new Pipeline features and improvements will only be available for graph Pipelines. Pipelines with stages will have no further features added. ::: To convert a Pipeline: 1. Open the Workflow Editor and select the Pipeline you want to convert. 1. Click **Convert Pipeline** in the banner at the top of the canvas. ![Convert Pipeline banner](/img/workflows-and-pipelines/2026-07-06-convert-pipeline-banner.png) Bitrise creates a converted copy named `_converted` and selects it automatically. 1. Review and adjust the converted Pipeline as needed. :::important[No cycles allowed] If your Pipeline conversion creates a cycle in the graph, you won't be able to save the Pipeline. You have to manually edit the configuration to remove the cycle. ::: 1. Click **Save changes** in the top right corner. --- ## Default Pipelines When you add a new project on [bitrise.io](https://www.bitrise.io), we create initial Pipelines and Workflows for you. You can use these to run your tests or create installable binaries such as IPAs or APKs. Feel free to modify the default Pipelines and Workflows to suit your needs. Default Pipelines are created for all new iOS and Android projects. These Pipelines consist of automatically created default Workflows. | Pipeline ID | Pipeline summary | Workflows within the Pipeline | | --- | --- | --- | | `run_tests` | Builds your iOS project, runs your Xcode tests in two [parallel shards](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow). The number of shards is specified in the env var $TEST_SHARD_COUNT. | `build_for_testing` `test_without_building` | | Pipeline ID | Pipeline summary | Workflows within the Pipeline | | --- | --- | --- | | `run_tests` | Run your Android instrumented tests in [two parallel test shards](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow) and get a test report. The number of shards is specified in the env var $TEST_SHARD_COUNT. | `run_instrumented_tests` | --- ## Pipeline builds You can run Pipeline builds the same way you would run builds of standalone Workflows: - [You can start Pipeline builds manually](/bitrise-ci/run-and-analyze-builds/starting-builds/starting-builds-manually). - [Schedule Pipeline builds](/bitrise-ci/run-and-analyze-builds/starting-builds/scheduling-builds). - [Trigger Pipeline builds automatically](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers). You can configure Pipeline triggers in the Workflow Editor or in YAML: [YAML syntax for build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/yaml-syntax-for-build-triggers). Pipeline builds are capable of sending build status reports: a Pipeline build will send a status report of the Pipeline itself and of any Steps that export test results: [Reporting the build status to your Git hosting provider](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider). All artifacts of a Pipeline build are available on the **Artifacts** page: [Build artifacts online](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online). You can use Pipeline builds to upload installable artifacts to Release Management, in order to distribute your mobile app to testers and release the app in an online store. All you need is a Workflow that generates an installable APK, AAB or IPA file: [see topic](urn:resource:component:92027). --- ## Configuring a Pipeline with stages Configuring a Pipeline that contains stages is only possible by directly editing the bitrise.yml file. You can create and modify Workflows in the graphical Workflow Editor but you need to define Pipelines and Stages in YAML format. ### Defining Pipelines with stages The `bitrise.yml` file contains the full configuration of your Pipelines. As with all `bitrise.yml` files, first you need to define the format version and the project type. ```yaml --- format_version: '8' default_step_lib_source: project_type: android ``` This is a bare minimum `bitrise.yml` configuration. To define your Pipelines, you will need to use the `pipelines` attribute. ```yaml pipelines:   pipeline-successful:     stages:     - stage-successful-1: {}     - stage-successful-2: {}     - stage-successful-3: {} ``` In this example, we have a Pipeline called `pipeline-successful`, with three Stages that will run consecutively. This means that if `stage-successful-1` finishes successfully, `stage-successful-2` starts. If any of the Stages fail, the subsequent Stage will not start: instead, the Pipeline will be aborted and marked as failed. Each Stage has to be defined separately under the `stages` attribute. Defining a Stage means specifying the Workflows that are part of the Stage. ```yaml stages:   stage-successful-1:     workflows:     - test-1: {}   stage-successful-2:     workflows:     - build-1: {}     - build-2: {}   stage-successful-3:     workflows:     - deploy-1: {}     - deploy-2: {} ``` In this example, the Stages run the `test-1`, `build-1`, `build-2`, `deploy-1`, and `deploy-2` Workflows. ### Configuring a Stage to always run By default, if a Stage fails - because one of its Workflows failed -, any other subsequent Stages of the Pipeline will not run. However, you can configure your Pipeline to run certain Stages unless the Pipeline is aborted. To do so, you just need to set the should_always_run attribute of the Stage to true: ```yaml stages:   stage-always-run-successful-1:     should_always_run: true     workflows:     - deploy-1: {}     - deploy-2: {} ``` In the example above, the Stage called `stage-always-run-successful-1` will always run, regardless of the status of previous Stages. The only way these Stages will not run is if the Pipeline build is aborted by the user. ### Aborting the Workflows of a failed Stage By default, if a Workflow in a particular Stage fails, the other Workflows in the same Stage aren’t automatically aborted: these Workflows will run but the next Stage won’t start. However, you can change this behavior to immediately and automatically abort all other Workflows in the same Stage. To do so, you need to set the abort_on_fail attribute to `true`: ```yaml stages:   stage-abort-on-fail-1:     abort_on_fail: true     workflows:     - deploy-1: {}     - deploy-2: {} ``` ### Sharing Env Vars between Pipeline Stages You can reuse any environment variable from a Workflow and reuse it in subsequent Workflows using the [Share Pipeline variables](https://github.com/bitrise-steplib/bitrise-step-share-pipeline-variable) Step. :::tip[Optional Workflows using run_if conditions] You can easily combine the **Share Pipeline variables** Step with `run_if` expressions to create Pipelines with optional Workflows. For more information, check out [Enabling or disabling a Step conditionally](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally). ::: To do so: 1. Add the **Share Pipeline variables** Step to the Workflow. 1. Optionally, you can define additional run conditions in the **Additional run conditions** input. The Step will only run if the conditions you specify here are true. 1. Add the Env Var(s) you would like to use in subsequent Workflows in the **Variables to share between Pipeline Workflows** input. :::tip[Using environment variable keys] You can define Env Vars using a `{key}={value}` syntax. For example, `MY_ENV_KEY=value`, or `INSTALL_PAGE_URL=$BITRISE_PUBLIC_PAGE_URL`. If you want to use the default environment variable keys, you can use a shorthand syntax. For example, `EXISTING_ENV_KEY`. Sharing Env Vars using this Step does not override existing Env Vars defined in the app. ::: That's it! You can now use the Env Var in any subsequent Stage! --- ## Currently supported use cases for the Android platform We have prepared some Pipeline recipes based on common Android use cases. These contain some of the most frequent tasks our users need to run. The examples include entire Workflows that can be copied and pasted for the most part. ### (Android) Run UI tests in parallel on multiple devices or shards #### Description Running the UI (instrumentation) tests of a single module in parallel Workflows utilizing pipelines. You can run the tests in parallel by shards or by devices. The Pipeline contains two Stages that are run serially: 1. `build_for_ui_testing`: This Stage executes a Workflow — also named `build_for_ui_testing` — that runs the `android-build-for-ui-testing` Step to build APKs for use in testing, and runs the `deploy-to-bitrise-io` Step to save those APKs for use in the later Stages. Performing this Stage separately from the actual testing allows for each test Stage to use these pre-built APKs rather than having to rebuild them for each test Stage. 1. `run_ui_tests_on_devices`: This Stage executes three UI test Workflows in parallel — `ui_test_on_phone`, `ui_test_on_tablet`, `ui_test_on_foldable` — which use the `android-instrumented-test` Step to run the UI tests on the APKs built in the previous Workflow on each specific device type. ![android_example.png](/img/_paligo/uuid-f545c6a6-701f-485f-c852-70ed2222392a.png) #### Instructions To test this configuration in a new Bitrise example project, do the following: 1. Visit the [Create New App page](https://app.bitrise.io/apps/add) to create a new App. 1. When prompted to select a git repository, choose **Other/Manual** and paste the sample project repository URL (`https://github.com/bitrise-io/Bitrise-Android-Modules-Sample.git`) in the **Git repository (clone) URL** field. 1. Confirm that this is a public repository in the resulting pop-up. 1. Select the `main` branch to scan. 1. Wait for the project scanner to complete. 1. Enter `app` as the specified module. 1. Enter `debug` as the specified variant. 1. Continue through the prompts as normal — no changes are needed. 1. Open the new Bitrise project’s Workflow Editor. 1. Switch to **YAML** at the top of the Workflow Editor, and replace the existing yaml contents with the contents of the example `[bitrise.yml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/android-parallel-ui-tests-on-multiple-devices.md#bitriseyml)`. 1. Click the **Start/Schedule a Build** button, and select the `ui_test_on_multiple_devices` option in the **Workflow, Pipeline** dropdown menu at the bottom of the popup. #### bitrise.yml GitHub link: [https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/android-parallel-ui-tests-on-multiple-devices.md#bitriseyml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/android-parallel-ui-tests-on-multiple-devices.md#bitriseyml) ### (Android) Running unit and UI tests in parallel #### Description Run unit tests and UI tests in parallel utilizing Pipelines. This Pipeline contains one Stage — `stage_unit_and_ui_test` — that executes two Workflows in parallel: 1. `unit_tests`: This Workflow simply runs the unit tests of the given module and variant using the `android-unit-test` Step. 1. `ui_tests`: This Workflow builds the given module and variant using the `android-build-for-ui-testing`Step, spins up an emulator using the `avd-manager` Step, waits for the emulator to boot using the `wait-for-android-emulator` Step, and runs the UI tests using the `android-instrumented-test` Step. ![android_example2.png](/img/_paligo/uuid-573f2524-97b7-94ea-38d4-c76306fafa29.png) #### Instructions 1. Visit the [Create New App page](https://app.bitrise.io/apps/add) to create a new App. 1. When prompted to select a git repository, choose **Other/Manual** and paste the sample project repository URL (`https://github.com/bitrise-io/Bitrise-Android-Modules-Sample.git`) in the **Git repository (clone) URL** field. 1. Confirm that this is a public repository in the resulting pop-up. 1. Select the `main` branch to scan. 1. Wait for the project scanner to complete. 1. Enter `app` as the specified module. 1. Enter `debug` as the specified variant. 1. Continue through the prompts as normal — no changes are needed. 1. Open the new Bitrise project’s Workflow Editor. 1. Switch to **YAML** at the top of the Workflow Editor, and replace the existing yaml contents with the contents of the example `[bitrise.yml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/android-parallel-unit-and-ui-tests.md#bitriseyml)`. 1. Click the **Start/Schedule a Build** button, and select the `pipeline_unit_and_ui_test` option in the **Workflow, Pipeline** dropdown menu at the bottom of the popup. #### bitrise.yml GitHub link: [https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/android-parallel-unit-and-ui-tests.md#bitriseyml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/android-parallel-unit-and-ui-tests.md#bitriseyml) ### (Android) Unit test sharding by module #### Description Run the unit tests of a modularized app in parallel Workflows utilizing Pipelines. This Pipeline contains one Stage — stage_unit_test — that executes two Workflows in parallel: 1. `unit_test_app`: This Workflow runs the unit tests of the app module using the `android-unit-test` Step. 1. `unit_test_library`: This Workflow runs the unit tests of the `lib-example` module using the `android-unit-test` Step. ![android_example_3.png](/img/_paligo/uuid-fb91dae2-cdfe-d531-2559-c02a58915ce3.png) #### Instructions 1. Visit the [Create New App page](https://app.bitrise.io/apps/add) to create a new App. 1. When prompted to select a git repository, choose **Other/Manual** and paste the sample project repository URL (`https://github.com/bitrise-io/Bitrise-Android-Modules-Sample.git`) in the **Git repository (clone) URL** field. 1. Confirm that this is a public repository in the resulting pop-up. 1. Select the `main` branch to scan. 1. Wait for the project scanner to complete. 1. Enter `app` as the specified module. 1. Enter `debug` as the specified variant. 1. Continue through the prompts as normal — no changes are needed. 1. Open the new Bitrise project’s Workflow Editor. 1. Switch to **YAML** at the top of the Workflow Editor, and replace the existing yaml contents with the contents of the example `[bitrise.yml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/android-parallel-testing-unit-test-shards.md#bitriseyml)`. 1. Click the **Start/Schedule a Build** button, and select the `pipeline_unit_test` option in the **Workflow, Pipeline** dropdown menu at the bottom of the popup. #### bitrise.yml GitHub link: [https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/android-parallel-testing-unit-test-shards.md#bitriseyml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/android-parallel-testing-unit-test-shards.md#bitriseyml) --- ## Currently supported use cases for the iOS platform We have prepared some Pipeline recipes based on common iOS use cases. These contain some of the most frequent tasks our users need to run. ### (iOS) Run tests in parallel on multiple simulators #### Description This example uses the [sample-swift-project-with-parallel-ui-test](https://github.com/bitrise-io/sample-swift-project-with-parallel-ui-test) iOS Open Source sample app, which has some example Unit and UI tests and uses Test Plans to group the tests. The example Pipeline config showcases how to run all the test cases of the project on different iOS simulators. `run_tests_on_simulators` Pipeline runs two Stages sequentially: 1. `build_tests stage` that runs the `build_tests` Workflow. This Workflow git clones the sample project and runs the `xcode-build-for-test` Step to build the target and associated tests. The built test bundle is transferred to the next Stage (`run_tests_on_simulators`) via the `deploy-to-bitrise-io` Step. :::note[The build test bundle is compressed] `xcode-build-for-test` Step compresses the built test bundle and moves the generated zip to the $BITRISE_DEPLOY_DIR. That directory’s content is deployed to the Workflow artifacts by default via the `deploy-to-bitrise-io` Step. ::: :::important[Artifact file size limitation] There is no limitation on the number of files deployed to **Artifacts** per build. There is a limitation, however, on the file size which is 2GB per file. ::: 1. `run_tests_on_simulators` Stage runs three Workflows in parallel: `run_tests_iPad`, `run_tests_iPhone`, and `run_tests_iPod`. All three of these Workflows use the new `xcode-test-without-building` Step, which executes the tests based on the previous stage built test bundle. The pre-built test bundle is pulled by the `_pull_test_bundle`utility Workflow. ![iOS_example_modified.png](/img/_paligo/uuid-5b325bb0-a98a-bd3d-943f-c7d26897e362.png) #### Instructions To test the configuration in a new Bitrise example project, do the following: 1. Visit the [Create New App page](https://app.bitrise.io/apps/add) to create a new App. 1. When prompted to select a git repository, choose **Other/Manual** and paste the sample project repository URL (`https://github.com/bitrise-io/sample-swift-project-with-parallel-ui-test`) in the **Git repository (clone) URL** field. 1. Confirm that this is a public repository in the resulting pop-up. 1. Select the `master` branch to scan. 1. Wait for the project scanner to complete. 1. Select any of the offered Distribution methods (for example **development**, it does not really matter as now we are focusing on testing). 1. Confirm the offered stack, skip choosing the app icon and the webhook registration and kick off the first build. 1. Open the new Bitrise project’s Workflow Editor. 1. Go to the **bitrise.yml** tab and replace the existing `bitrise.yml` with the contents of the example `[bitrise.yml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/ios-run-tests-in-parallel-on-multiple-simulators.md#bitriseyml)` file. 1. Click the **Start/Schedule a Build** button, and select the **run_tests_on_simulators** option in the “**Workflow, Pipeline**” dropdown menu at the bottom of the popup. #### bitrise.yml GitHub link: [https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/ios-run-tests-in-parallel-on-multiple-simulators.md#bitriseyml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/ios-run-tests-in-parallel-on-multiple-simulators.md#bitriseyml) ### (iOS) Run test groups in parallel #### Description This example uses the [sample-swift-project-with-parallel-ui-test](https://github.com/bitrise-io/sample-swift-project-with-parallel-ui-test) iOS Open Source sample app, which has some example Unit and UI tests and uses Test Plans to group the tests. :::tip[XCode test plans] Xcode Test Plans provide a way to run a collection of tests with different test configurations. raywenderlich.com has a great [tutorial on how to get started with Xcode Test Plans](https://www.raywenderlich.com/10212963-xcode-test-plans-for-ios-getting-started). ::: The example Pipeline config showcases how to run different test groups in parallel. `run_tests_groups` Pipeline runs two Stages sequentially: 1. `build_tests` Stage that runs the `build_tests` Workflow. This Workflow git clones the sample project and runs the `xcode-build-for-test` Step to build the target and associated tests. The built test bundle is transferred to the next Stage (`run_tests_groups`) via the `deploy-to-bitrise-io` Step. 1. `run_tests_groups` Stage runs two Workflows in parallel: `run_ui_tests` and `run_unit_tests`. Both of these Workflows use the new `xcode-test-without-building` Step, which executes the tests based on the previous Stage built test bundle. The pre-built test bundle is pulled by the `_pull_test_bundle` utility Workflow. ![iOS_example_2.png](/img/_paligo/uuid-789ed335-aeab-b87c-6045-270c5e87a641.png) #### Instructions 1. Visit the [Create New App page](https://app.bitrise.io/apps/add) to create a new App. 1. When prompted to select a git repository, choose **Other/Manual** and paste the sample project repository URL (`https://github.com/bitrise-io/sample-swift-project-with-parallel-ui-test`) in the **Git repository (clone) URL** field. 1. Confirm that this is a public repository in the resulting pop-up. 1. Select the `master` branch to scan. 1. Wait for the project scanner to complete. 1. Select any of the offered Distribution methods (for example **development**, it does not really matter as now we are focusing on testing). 1. Confirm the offered stack, skip choosing the app icon and the webhook registration and kick off the first build. 1. Open the new Bitrise project’s Workflow Editor. 1. Go to the **bitrise.yml** tab and replace the existing `bitrise.yml` with the contents of the example `[bitrise.yml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/ios-run-test-groups-in-parallel.md#bitriseyml)` file. 1. Click the **Start/Schedule a Build** button, and select the `run_tests_groups` option in the “**Workflow, Pipeline**” dropdown menu at the bottom of the popup. #### bitrise.yml GitHub link: [https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/ios-run-test-groups-in-parallel.md#bitriseyml](https://github.com/bitrise-io/workflow-recipes/blob/main/recipes/ios-run-test-groups-in-parallel.md#bitriseyml) --- ## Creating your own Bitrise project scanner The project scanner is a tool that identifies the given project’s type and generates a basic Bitrise configuration. Each supported project type has its own scanner: these scanners are stored as separate packages. A project type scanner defines at least two Workflows: one for testing (`primary`) and one for building (`deploy`). It includes the minimal amount of Steps to successfully run them. :::important[Build and test Steps] Build Steps and test Steps have specific requirements: - A build Step must build your app so that it is ready for deployment and it must output an Environment Variable that points to the output file(s). For example, a build Step to build an iOS app must output an .ipa file (not, say, `.xcodearchive`) and the path to this .ipa file. - A test Step must output the test results so that they are available for viewing on the build page on bitrise.io. ::: When adding a new project on the website or initializing a project on your own machine, the [bitrise-init](https://github.com/bitrise-io/bitrise-init) tool iterates through every scanner, calls the scanner interface methods on each of them and collects their outputs. Based on these outputs, a basic configuration is generated. The possible Workflows are described in a scan result model. The model consists of: - options - configs - warnings Here is the basic structure of the model, in YAML: ```yaml options: DETECTED_PLATFORM_1: OptionNode DETECTED_PLATFORM_2: OptionNode ... configs: DETECTED_PLATFORM_1: CONFIG_NAME_1: ConfigModel CONFIG_NAME_2: ConfigModel ... DETECTED_PLATFORM_2: CONFIG_NAME_1: ConfigModel CONFIG_NAME_2: ConfigModel ... ... warnings: DETECTED_PLATFORM_1: - "warning message 1" - "warning message 2" ... DETECTED_PLATFORM_2: - "warning message 1" - "warning message 2" ... ``` - Every platform scanner writes its possible options, configurations and warnings into this model. These will be translated into Step input values by choosing the desired values for the given options. - Every option chain’s last option selects a configuration. - Warnings display the issues with the given project setup. ### Options `Options` represents a question and the possible answers to the question. For example: - Question: What is the path to the iOS project files? - Possible answers: List of possible paths to check These questions and answers are translated into Step inputs. The scanner should either determine the input value or let the user select or type the value. For example, the `Xcode Archive & Export for iOS` Step has an input called export-method. This informs the Step of the type of .ipa you want to export. The value cannot be determined based on the source code so the scanner collects every possible value and presents them to the user in the form of a list to choose from. Selecting an option can start a chain: it can lead to different options being presented afterwards. For example, if you select an Xcode scheme that has associated test targets, it leads to different “questions”. Similarly, selecting a certain option can lead to a different workflow being generated afterwards. #### The option model The `OptionNode` represents an input option. It looks like this in Go: ```go // OptionNode ... type OptionNode struct { Title string Summary string EnvKey string ChildOptionMap map[string]*OptionNode Icons []string Components []string Head *OptionNode } ``` - Title: the human readable name of the input. - Summary: a short description of the option. - EnvKey: it represents the input’s key in the step model. - ChildOptionMap: the map of the subsequent options if the user chooses a given value for the option. For example, let’s see a scenario where you choose a value for the Scheme input. You will have a value_map in the `options`. The possible values are: - SchemeWithTest - SchemeWithoutTest By choosing `SchemeWithTest`, the next option will be related to the simulator used to perform the test. By choosing `SchemeWithoutTest`, the next option will be about the export method for the .ipa file. ```json { "title": "Scheme", "env_key": "scheme", "value_map": { "SchemeWithTest": { "title": "Simulator name", "env_key": "simulator_name", ... }, "SchemeWithoutTest": { "title": "Export method", "env_key": "export_method", ... } } } ``` Every option chain has a first option: this is called `head`. The possible values of the options can branch the option chain. Every option branch’s last `options` must have a config property set. config holds the id of the generated Bitrise configuration. An options chain’s last `options` cannot have a value_map. ```json { "title": "Scheme", "env_key": "scheme", "value_map": { "SchemeWithTest": { "title": "Simulator name", "env_key": "simulator_name", "value_map": { "-": { "config": "bitrise_config_with_test", } } }, "SchemeWithoutTest": { "title": "Export method", "env_key": "export_method", "value_map": { "development": { "config": "bitrise_config_without_test", }, "app-store": { "config": "bitrise_config_without_test", }, "ad-hoc": { "config": "bitrise_config_without_test", } } } } } ``` ### Scanners Scanners generate the possible `options` chains and the possible workflows for the `options` per project type. Scanners are returned by the `ProjectScanners()` and `AutomationToolScanners()` functions. Every specific scanner implements the `ScannerInterface`. ```go // ScannerInterface ... type ScannerInterface interface { Name() string DetectPlatform(string) (bool, error) Options() (models.OptionNode, models.Warnings, models.Icons, error) Configs(sshKeyActivation models.SSHKeyActivation) (models.BitriseConfigMap, error) DefaultOptions() models.OptionNode DefaultConfigs() (models.BitriseConfigMap, error) ExcludedScannerNames() []string } ``` - `Name() string`: This method is used for logging and storing the scanner output (warnings, options and configs). The scanner output is stored in `map[SCANNER_NAME]OUTPUT`. For example, the `options` for an iOS project is stored in `optionsMap[ios]options`. - `DetectPlatform(string) (bool, error)`: This method is used to determine if the given search directory contains the project type or not. - `Options() (models.OptionNode, models.Warnings, models.Icons, error)`: This method is used to generate option branches for the project. Each branch should define a complete and valid option set to build the final bitrise config model. Every option branch’s last `Options` has to store a configuration id, which will be filled with the selected options. - `Configs(sshKeyActivation models.SSHKeyActivation) (models.BitriseConfigMap, error)`: This method is used to generate the possible configs. BitriseConfigMap’s each element is a bitrise config template which will be fulfilled with the user selected option values. - `DefaultOptions() models.OptionNode` and `DefaultConfigs() (models.BitriseConfigMap, error)`: These methods are used to generate the options and configs without scanning the given project. In this case every required step input value is provided by the user. This way even if a scanner fails, the user has an option to get started. #### Testing a scanner To test a scanner, we require both unit tests and integration tests. Unit tests are written using Go’s standard testing library. For integration tests, we are validating that the project type scanners are generating the desired Bitrise configurations for an instance of the project type. To do this, we use the new scanner to scan the given sample project and we modify the generated scan result to fit our integration tests. The reason for the modification is that the scanners are adding Steps to the generated config, but the Step versions are updated from time to time. The Step version definitions can be found at `steps/const.go`. So we call `bitrise-init --ci config` in the sample project’s root directory, and in the generated `scan_result.yml` file we replace the Step versions with `%s` and we use `fmt.Sprintf` to inject the latest defined Step versions into the config. In the integration tests, we are matching the `scan_result.yml` file generated by the scanner with the previously generated reference `scan_result` content. #### Submitting your own scanner You can submit your own scanner to Bitrise: we will review it and integrate it to the bitrise-init tool once it’s approved! The development path for a new scanner starts with your own sample project and ends with updating the existing Steps for your project type. Let’s go through it! 1. Find or create an open source sample app that demonstrates a typical instance of your project type. It should include: - a readme file (including tool versions required for updating, building and testing this project). - a `bitrise.yml` file that is generated by your scanner. 1. Build and test your sample app with existing Steps or custom scripts. 1. Create the missing Steps the new project type needs. The PR for these Steps should link the scanner PR once you created the scanner. 1. Create a scanner for your project type. 1. Run the required unit tests and integration tests. 1. Open a scanner pull request to the bitrise-init project. It should: - link the new project type’s sample app. - link the new project type’s guides for testing and building. - include an icon for the new project type - otherwise we will create one for you. - recommend the default stack by listing the required tools for building and testing the new project type. 1. Update the existing Steps with the new project type if necessary. The PR for these Steps should link the scanner PR. --- ## Developing a new Step A Step is a task in a bigger CI/CD workflow: for example, the [**Git Clone Repository**](https://github.com/bitrise-steplib/steps-git-clone) Step clones your Git repository at the start of a build while the [**Manage iOS Code Signing**](https://github.com/bitrise-steplib/bitrise-step-manage-ios-code-signing) Step is performing code signing for your iOS app. :::tip[Sharing Steps] Sharing your team's custom Steps is optional: if the problem you are solving with a Step is specific to your team or company, you may not need to share it. As you can run a Step from your own machine or from any Git repository, your custom Steps do not have to be part of the Bitrise Step Library. However, if the Step solves a common problem, it is worth sharing it with the community. For more info on sharing Steps with other users, check out the [Sharing Steps](/bitrise-ci/workflows-and-pipelines/developing-your-own-bitrise-step/sharing-steps-with-all-bitrise-users) guide. ::: :::important[Duplicate Steps] Before deciding to create a new Step, don't forget to [check](https://www.bitrise.io/integrations/steps) if existing (first-party or third-party) Steps already cover your use case. Contributing new behavior to existing Steps is always preferred over creating a brand new Step. ::: A Step contains the code that performs the build task. You can configure the inputs and parameters that define the task, and view and reuse the outputs a Step generates. Reusing the output means that a subsequent Step in the workflow can use it as its input. First-party Bitrise Steps are written in [Go](https://golang.org/), but you can use any language and framework as long as you wrap it in a Bash step and set up its entrypoint. Each step has its own git repo that includes code and the `step.yml` metadata file. If you wish to make the Step available to other users, the `step.yml` file needs to be submitted to Bitrise Step Library (`bitrise-steplib` repository) so that it can be discovered and re-used in the Workflow Editor. ### Creating the Step We start with scaffolding the basic structure of the Step. Certain properties and inputs will be generated and assigned automatically. You can change these later. At the end of this process, you will have a `step.yml` file, a `README.md` file and either a `main.go` or a `step.sh` file in the repository. :::important[Before you start] During the Step creation process, you will be prompted to set a number of options. Note that you can change any of these before submitting your Step to Bitrise for review: the data will be included in the generated `step.yml` file that you can edit at your leisure later. During the initial Step creation process, you can use placeholders if you want to. ::: 1. Make sure to [install the Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli). 1. Create a new directory and run `bitrise :step create` inside it. 1. Follow the prompts to set up your Step. You are all done! You should now have a `step.yml`, a `README.md` file, and either a `main.go` or a `main.sh` file. ### The step.yml file The `step.yml` file contains all metadata that Bitrise systems need to know about a Step. It's where you define the inputs and outputs of your Step, as well as the dependencies required for the Step to function. For a complete reference of the `step.yml` file, see [About step code](/bitrise-ci/references/steps-reference/about-step-code). ### Naming and describing a Step Every Step must have at least a title and a summary defined in the `step.yml` file. These appear on the [Integrations](https://www.bitrise.io/integrations/) page and in the [Workflow Editor](/bitrise-ci/references/glossary#workflow-editor). :::tip[Markdown] All text properties are rendered as Markdown, you are encouraged to use external links and other Markdown features. ::: #### Title It should be short and descriptive. Include the name of the service and the function it fulfils, such as **Git Clone Repository**. The title is not the same as the unique Step ID: the ID is used in the configuration YAML files to reference the Step. For example, `git-clone` is the ID of the **Git Clone Repository** Step. A few other guidelines to follow: - Do not use the word ‘Step’. - Use imperative verbs instead of nouns when possible. For example, instead of **Script Runner**, it should be **Run Script**. - Make sure you use the correct name of a service or tool. For example, GitHub instead of Github. - Do not include implementation details. #### Summary A single line of the most significant information about the Step. Keep it below 100 characters. The summary is visible by default on the Workflow Editor. If a user expands the summary, the Step’s description will be presented. #### Description A detailed explanation of the Step. The `description` property contains a longer and more detailed description so that other users better understand how your Step works. It also contributes to search rankings when users search Steps in the Workflow Editor. It should include: - What the Step does. - External services the Step interacts with (if any). - Configuration, including the most important inputs. - Troubleshooting information: potential issues and their solutions. By default, the Step’s description is collapsed on the Workflow Editor and the summary is presented. ### Step categories There is another thing we’d like to know about your Step: what type of Step is it? As you can see on our Integrations page or on the Workflow Editor, Steps are sorted into different categories based on two factors: the platforms for which they are available and their functionality. #### Platforms The relevant platforms are controlled by the `project_type_tags` attribute. If your Step is available for every platform or project type, do not specify `project_type_tags`. In any other case, select all platform types for which your Step is relevant and fully supported. The available values are: - `ios` - `macos` - `android` - `react-native` - `cordova` - `ionic` - `flutter` - `web` - `kotlin-multiplatform` #### Category Functional categories are controlled by the `type_tags` attribute in the `step.yml`. One Step should have only a single type tag assigned to it. Use `utility` only if you believe none of the other types fit your Step. The available values are: - `build` - `code-sign` - `test` - `deploy` - `notification` - `access-control` - `artifact-info` - `installer` - `dependency` - `utility` - `security` ### Step inputs Inputs are the primary way for users to configure a Step. For example, the **Git Clone** Step has an input called `branch`, which controls the branch to check out. ```yaml title: Git Clone Repository summary: Clone a repository to the specified path on the VM inputs: - branch: $BITRISE_GIT_BRANCH ``` Implementation-wise, Step inputs are [Environment Variables](/bitrise-ci/configure-builds/environment-variables) with additional metadata and validation rules. Step inputs are visible on the Workflow Editor: they are presented in the order as they appear in the `step.yml`. As such, required and frequently used inputs should be at the top. A minimal input definition: ```yaml - install_defaults: "yes" opts: title: Installs default Codesign Files value_options: - "no" - "yes" ``` The above input is defined as `install_defaults`, and its default value is `yes`. There is additional validation for the two valid input values. Use lower case [snake case](https://en.wikipedia.org/wiki/Snake_case) style input keys (e.g. `project_path`, not `ProjectPath` or `PROJECT_PATH`). There is no need to add domain-specific prefixes to the input keys, as inputs are only exposed at runtime for that single Step process. This means the `project_path` input will not overlap with subsequent Steps’ `project_path` inputs. Step input values are strings, but you can define additional validation rules for the values (see below). Provide default values for Step inputs if possible (and if it makes sense). That makes the Step configuration easier for Bitrise users. Environment Variables must not be used as default values, unless: - They are exposed by the [Bitrise CLI or by bitrise.io](/bitrise-ci/configure-builds/environment-variables). - They are generated as an output by another Step (for example, `$BITRISE_IPA_PATH`, `$BITRISE_AAB_PATH`). This is because the Workflow Editor highlights required inputs without values to express the Step will not work without setting a valid value for the given input. If you set an Env Var, which does not have an automatically assigned value, as the default value for an input, the Workflow Editor will think the required input in question has a valid value set (even if the default Env Var has no value yet). Also, there is no reason to suggest a certain name for an Environment Variable this way: users might have the same value assigned to an Env Var with a different name. In addition to a key and a value, Step inputs are required to have an `opts` property. This property contains the different options that define how the inputs are passed to the code of the Step and how it is presented in the Workflow Editor. The possible values of the input can be set in `opts` as well. Let’s see an example. #### Naming and describing Step inputs A Step input can have a name, a summary, and a description, just like the Step itself. To define these: 1. Include an `opts` property with the Step input. 1. Under `opts`, provide a `title`, a `summary`, and a `description` option. :::tip[Description and summary] Both `description` and `summary` accept Markdown formatting. ::: - `title`: User-friendly name of the input. It should not be too different from the input key, but you have more flexibility than with the raw YML key. For example, `apk_signature_scheme` and `APK Signature Scheme`. - `summary`: Short version of the description, which provides a quick overview of the input. On the Bitrise Workflow Editor, the summary of the inputs is presented by default when you click on a Step. - `description`: This should provide a deeper, more detailed explanation of the input. By default, it is not visible in the Workflow Editor, unless the user clicks on the input in question. Here is an example: ```yaml - track: alpha opts: title: Track summary: The distribution track you want to assign the uploaded app to. description: |- The distribution track you want to assign the uploaded app to. Can be one of the built-in tracks (internal, alpha, beta, production), or a custom track name you added in Google Play Developer Console. is_required: true ``` #### Required inputs When the input is marked as required (and the input has no default value defined), the user must provide a value, either a static string or an Environment Variable which resolves to a non-empty string. A required input is also displayed as **REQUIRED** on the Workflow Editor and validated when saving changes. To mark a Step input as required, use the is_required option of the `opts` property. ```yaml - keychain_password: $BITRISE_KEYCHAIN_PASSWORD opts: title: "Keychain password" is_required: true ``` #### Using Env Vars as input values (is_expand) As noted earlier, it is possible to use Environment Variables as the value of any given input. By default, Env Vars in Step inputs are expanded to the value behind that Env Var. This is controlled by the `is_expand` option of the `opts` property. ```yaml - project_path: $BITRISE_PROJECT_PATH opts: is_expand: true ``` If set to `true`, the value of `$BITRISE_PROJECT_PATH` is expanded and used as the string input of `project_path`. If set to `false`, the string value `$BITRISE_PROJECT_PATH` will be used without any expansion (and this particular Step will fail as it will not find the project location). :::warning[Reading Env Vars in Step Code] If possible, avoid reading Environment Variables without exposing them as Step inputs via `step.yml`. This helps users configure and understand Step behavior, and you don't need to write input validation by hand (required inputs, default values, value options, and so on). ::: #### Sensitive inputs You can mark Step inputs as sensitive to avoid leaking them to build logs and UIs. Sensitive inputs only accept [Secrets](/bitrise-ci/configure-builds/secrets) as values. To mark a Step input as sensitive, use the `is_sensitive` option of the `opts` property. If set to `true`, the input will be displayed as **SENSITIVE** on the Workflow Editor and even if it gets logged in builds, the value is replaced with `[REDACTED]` in the build log. :::important[The `is_expand` option] If you mark an input as sensitive, the `is_expand` option of the input also must be true, which is the default setting. ::: ```yaml inputs: - certificate_urls: $BITRISE_CERTIFICATE_URL opts: title: "Certificate URL" is_sensitive: true ``` #### Input grouping The `category` property is used to group related inputs. Inputs with a category are collapsed by default in the Workflow Editor, only displaying the category name. ```yaml - default_certificate_passphrase: $BITRISE_DEFAULT_CERTIFICATE_PASSPHRASE opts: category: Default code signing files description: | Certificate passphrase of the default certificate. is_sensitive: true title: Default certificate passphrase ``` Categories may be used if the Step has many related inputs, or infrequently used ones. The suggested maximum number of inputs in a group or in the root is six. Please keep in mind, when designing Step categories, that: - Required inputs should not be grouped as they are easy to miss when configuring the Step. - Grouped inputs should be defined after inputs without a category. #### Lists as input values At the moment, a string list is not a supported Step input type. The following conventions are used for list-like inputs: - We strongly recommend adding a `list` suffix to the key of the input (for example, `input_path_list`). - Step code should parse the input value by splitting at a newline character (\n) (for example, `first value\nsecond value`). Don't forget to filter out empty items after the split. - Make sure the input `summary` and `description` clearly indicate that the input is a list of values, and how to format it. ### Step outputs Steps can generate outputs which can then be used in other Steps as inputs. That means that if a Step generates an artifact, the path to that artifact can be the input of another Step in the build. For example, the **Xcode Archive & Export for iOS** Step exposes the `$BITRISE_IPA_PATH` output which can then be used as an input value for the **Deploy to Bitrise.io** Step. Outputs are defined in the `step.yml` file, under the `outputs` property. They have the same structure as Step inputs and the guidelines above also apply to them. #### Lists as output values The same limitation applies to Step outputs as to Step inputs, see the [Lists as input values](#lists-as-input-values) section above. ### Setting conditions for running the Step There are three properties that define whether a Step is run in a given Workflow or not: `is_always_run`, `is_skippable` and `run_if`. These properties can be set in the `step.yml` file to govern the default behavior of the Step. User-provided values in the `bitrise.yml` file override these defaults. `is_always_run`: By default, Steps do not run if a previous Step in the Workflow failed. However, if the `is_always_run` property is set to `true`, the Step runs regardless of the status of previous Steps in the Workflow. This can be useful for sending notifications or cleaning up resources after a failed step. `is_skippable`: If a Step’s `is_skippable` property is set to `true`, the build will not fail and subsequent Steps will run even if this particular Step fails. Useful for optional tasks, which should not block the build if they fail. `run_if`: Use the `run_if` property to make Step execution dependent on a certain condition. For example, you can configure a Step to only run in PR-triggered builds. Read more in our [Enabling or disabling a Step conditionally](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally) guide about the possible use cases. ### Step dependencies Step code often relies on local CLI tools or interacts with external APIs. Steps are run in various environments (macOS and Linux, different OS versions with different pre-installed tools), so it's important to make sure that your Step works in all of them. You can declare dependencies from OS dependency managers (APT and Homebrew). A Step dependency is installed by the Bitrise CLI before the Step runs. List every dependency, even if you know that they are pre-installed on the Bitrise stacks as this might not be true for future stacks. ```yaml deps: brew: - name: cmake apt_get: - name: cmake ``` If a Step dependency is not packaged in OS dependency managers, the next best option is to install it at runtime. A few guidelines to follow: - Add network retries for reliable downloads, such as `curl`'s `--retry --connect-timeout 10 --max-time 30` flags. - Use checksum and signature verification wherever possible. - Make sure to only download from domains that you trust and control (or listed as the official source of the dependency). - Do not use git submodules as a dependency management solution: they are not cloned when the Step is run. #### Accessing files in the Step repo with an Env Var If you need to keep a binary, assets or anything else required for your Step that should be bundled in the Step repository, then you can include them beside your `step.yml` file and the code of your Step. The Bitrise CLI automatically exports an Environment Variable called `$BITRISE_STEP_SOURCE_DIR` that allows you to access these files at any time. For example, you can access a `.jar` file in the root of your Step’s repository like this: `$BITRISE_STEP_SOURCE_DIR/mytool.jar` --- ## Sharing Steps with all Bitrise users If you think your Step can be of use to others, you can share it! Before doing so, however, please check that there are no other Steps that solve the same problem. You can check: - In the list of [released Steps](https://www.bitrise.io/integrations/steps). - In the list of [open pull requests](https://github.com/bitrise-io/bitrise-steplib/pulls) in our StepLib. - In the list of [closed pull requests](https://github.com/bitrise-io/bitrise-steplib/pulls?q=is%3Apr+is%3Aclosed) in our StepLib. If you find a Step which is missing a particular feature, please try to contribute to it before developing or sharing a brand new Step for that feature. You can use our [Integrations page](https://www.bitrise.io/integrations/steps) to search for Steps in the Bitrise StepLib. By clicking the GitHub source button on a given Step’s page you will be taken to the Step’s repository, where you can submit a feature request or open a pull request. Also, please keep in mind that shared Steps must be actively maintained and they must be open to contributors. ### Sharing a new Step The sharing process is relatively straightforward - but please make sure to go through the process carefully when sharing a new Step. :::note[The bitrise share command] During Step development, you can get help anytime by simply running bitrise share. This will print a short guide on sharing. ::: There are two ways to share a Step: - You can do it manually, using the `bitrise share` command. - If you created the Step with the Step plugin, you can run the `share-this-step` Workflow in your Step’s directory. #### Before you start Before you start, make sure that: - Your Step is in a public Git repository. - The step.yml file contains a support_url property which points to a valid issue tracker (for example, the **Issues** page of your Step’s GitHub repository). - The step.yml file contains a source_code_url property which points to the correct Git URL of your repository. :::important[Sharing more than one Step] Sharing more than one Step - that is, adding more than one new step.yml file to the Bitrise StepLib - must be done in separate pull requests! You cannot open a pull request that contains more than one new Step! ::: If you’re ready, go ahead with your preferred sharing process! #### Sharing with the bitrise share command 1. Fork the [Bitrise StepLib](https://github.com/bitrise-io/bitrise-steplib.git) repository. 1. Prepare your forked StepLib locally for sharing: ```bash $ bitrise share start -c ``` 1. Add the Step version tag to your Step’s repository. 1. Add the Step to your forked StepLib repository: ```bash $ bitrise share create --tag [step-version-tag] --git [step-git-uri].git --stepid [step-id] ``` 1. Optionally, perform a complete health check on your forked StepLib: ```bash $ bitrise share audit -c ``` 1. Review your Step’s step.yml file, and if you’re happy with it, finish the share process: This commits and pushes the step.yml file to the forked StepLib repository. ```bash $ bitrise share finish ``` This commits and pushes the step.yml file to the forked StepLib repository. 1. Open a pull request in the official [Bitrise StepLib](https://github.com/bitrise-io/bitrise-steplib.git) repository. #### Sharing with the share-this-step Workflow The share-this-step Workflow is included in the bitrise.yml file that the Step plugin automatically generates when you create a new Step with it. Using it, sharing a Step is incredibly easy: 1. Fork the [Bitrise StepLib](https://github.com/bitrise-io/bitrise-steplib.git) repository. 1. Set the required Workflow Environment Variables as app level Environment Variables in the bitrise.yml file: ```yaml app: envs: - BITRISE_STEP_ID: - BITRISE_STEP_VERSION: - BITRISE_STEP_GIT_CLONE_URL: - MY_STEPLIB_REPO_FORK_GIT_URL: ``` 1. Run the share-this-step Workflow in the Bitrise CLI: ```bash $ bitrise run share-this-step ``` #### Fixing issues in a StepLib pull request Once you submitted your Step version to the StepLib, wait for the Bitrise team to review it. If we ask for changes: 1. Close the pull request. 1. Delete the share branch from your fork of the Bitrise StepLib. 1. Fix the issues in the Step repository. 1. Add a new version tag to the commit that contains your fixes in the Step repository. 1. Run the [share process](/bitrise-ci/workflows-and-pipelines/developing-your-own-bitrise-step/sharing-steps-with-all-bitrise-users#sharing-a-new-step) again. Hopefully, after fixing the issues, we’ll be able to merge your pull request and release your Step to the public! ### Adding a Step icon You can add a Step icon to your Step: you will see it in the Workflow Editor and on our [Integrations](https://www.bitrise.io/integrations/) page. This is optional: you only need an icon if you want to add your Step to the official Bitrise Step Library. There are some requirements: - Its background color should not be transparent. - Size: 256x256 px. - Margin: 60 px. - Format: SVG. To submit your Step’s icon: - Add the .svg file into your StepLib fork repo at: `STEPLIB_FORK_ROOT/steps/YOUR_STEP_ID/assets/icon.svg`. - Create a new pull request to the [StepLib repository](https://github.com/bitrise-io/bitrise-steplib). ### Abandoned Steps If you are a Step maintainer, you should be reachable within a reasonable timeframe if anyone submits an issue or a pull request to your Step. If we try to contact you several times regarding an important fix/update in your Step and you refuse to answer for several weeks we might deprecate, remove or replace your Step in the collection! Abandoned Steps can be a threat for those who use it, please keep this in mind if you decide to share your Step with others! The repository and issue tracker must not be removed, as there are permanent links to it included in the step.yml that is in the Bitrise StepLib. If they are removed, already shared Step versions will continue to function as they are also shared on a Bitrise managed file hosting service during the share process. A new version of the step may be released, managed by Bitrise. If you shared a Step but you’re no longer able or willing to maintain it, please create a GitHub issue in this repository: [Bitrise StepLib](https://github.com/bitrise-io/bitrise-steplib) ### Reporting Step issues If you’re a user of a Step which has critical (security or functionality) issues, please create a ticket in the Step’s Issue Tracker. Every Step declares the preferred way of reporting issues with the `support_url` attribute. If you don’t get a response from the Step’s maintainer for an extended period (for more than a couple of weeks) please create a GitHub issue in this repository: [https://github.com/bitrise-io/bitrise-steplib](https://github.com/bitrise-io/bitrise-steplib) and we’ll try to resolve the issue, following the Abandoned Step policy. Please be patient and keep in mind that everyone who contributes to this collection does so to help you by providing a Step for you to use! --- ## Verified Steps ### About Verified Steps A Step contains the code that performs a specific build task. Bitrise has over 400 Steps in its [Step Library (StepLib)](https://github.com/bitrise-io/bitrise-steplib) which third party companies or open source teams can enrich with Steps based on their services/tools. This means they have full power to roll out updates to the Step while Bitrise maintains an overlaying control to ensure service quality and security. A Verified Step means that the owner of a service or tool or an open source team guarantees secure, maintained, consistent, and high-quality performance for any Bitrise user. Our official Bitrise Steps are maintained by us, whereas our Community Steps are maintained by the community. It’s easy to decide which type a Step falls into on our GUI. - Verified Steps are labeled with a blue badge in [Bitrise](http://bitrise.io/). - Official Bitrise Steps are labeled with a green badge. - Community created Steps do not have any badge. ![Verified_Steps.jpg](/img/_paligo/uuid-088fa6df-9163-1518-308d-87ad0916c60f.jpg) We strongly recommend that you consult with our [Step development](/bitrise-ci/workflows-and-pipelines/developing-your-own-bitrise-step/developing-a-new-step) guidelines before creating a Step. ### Managing contributions The following guidelines aim to help Verified Step authors categorize contributions. The Verified Step author is responsible for any contribution made to the Verified Step. The Verified Step author acknowledges the contribution by adding a label an estimated time to perform the fix, and merge the PR. There are four labels the author can use to categorize the type of contribution: - `critical-bug` label means that the current feature set has abnormal behavior, which blocks users from using the Step and there is no workaround to fix the issue. This critical bug must be fixed by the author. - `bug` label means that the current feature set has abnormal behavior, which does not block users from using the Step and there is a workaround for the issue. This bug must be fixed by the author. - `feature-request` label means that a new feature or Step is being requested. The Verified Step author can decide if the feature is worth implementing. - `maintenance` label means improving the Step’s source code in a way that it does not add new features or potential bugs to the Step. The Verified Step author can decide whether the feature is worth implementing or not. - `rejected` label means the contribution which gets rejected by the Verified Step author must be closed within the first response time, that is 5 business days. When rejecting a contribution, the Verified Step author has to provide an explanation to the contributor within the first response time. - `accepted` contribution means that the given: critical-bug, bug, feature, maintenance will be fixed/merged within the given resolution time. First response time means that there is a 5 day window during which the Verified Step author should respond to the contribution with the accepted or rejected labels. Resolution time means a certain amount of business days during which the contribution (issue or PR) should be completed by the Verified Step author. | Type | First response time | Resolution time | | --- | --- | --- | | critical-bug | 5 business days | 10 business days | | bug | 5 business days | 15 business days | | feature-request | 5 business days | 20 business days | | maintenance | 5 business days | 20 business days | ### How do we go about Step duplications? In general we try to keep our StepLib streamlined and avoid Step duplications for the same build task. Here you can find some questions and answers when it comes to any potential Step duplications. - *I was going to submit a Step and apply for the Verified badge, but found out there was an official Bitrise Step for the same build task in the StepLib. What should I do?* Submit your Step and go through the application process. Once your application is completed, we deprecate the official Bitrise Step and our users can use your new Verified Step. - *I was going to submit a Step and apply for the Verified badge, but found out there was a Community Step for the same build task. What should I do?* Submit your Step and go through the application process. Your new Verified Step and the Community Step will be both available in our StepLib. - *I was going to submit a Community Step but found out there was a Verified Step for the same build task. What should I do?* If a Verified Step is already available in our StepLib, we reject Community Step submission for the same build task to avoid Step duplication. We offer to the Community Step developer to work on future updates of the already existing Verified Step. ### Our requests to verified Step maintainers We ask verified Step maintainers to follow our best practices: - Monitor issues opened by users in your Step repository and respond in a timely manner. - Be familiar with our [Stack update policy](/bitrise-build-hub/infrastructure/build-stacks/macos-stack-update-policy), especially the cadence of breaking changes. Your Step might (accidentally or on purpose) depend on tools from the stack environment, and we don’t want Steps to be broken after stack updates. - Test your Steps regularly on all available stacks and platforms. We recommend setting up CI workflows with scheduled builds and some form of notification if the build fails. If you need any help with Step-related questions, feel free to reach out! For example, we're happy to help with: - Best practices for performing common tasks in Steps. - Best practices for Step inputs and outputs, chaining Steps. - Troubleshooting Step errors. --- ## Adding Steps to a Workflow Steps can be added or removed any time from your Workflows. When adding a new app to Bitrise, the project scanner generates at least one Workflow with some default Steps but you don't have to use these at all: it's up to you what Steps you want to include. You can add any Step to your Workflow - there are absolutely no restrictions. Please note that this means that it’s possible to add a Step specific to, for example, iOS apps to a Workflow of an Android app. Always make sure you only add the relevant Steps to your Workflow! ### Adding Steps in the Workflow Editor 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Click the **+** symbol between two Steps to insert a Step at that position. 1. Search for the Step you need. :::important[Search filter] Be aware of the filter tags below the search field. You can filter by category (such as **Build**, **Deploy**, or **Test**) and by maintainer (**Official**, **Verified**, **Community**). You can select multiple tags at the same time. By default, no filters are applied and all Steps are shown. ::: 1. Click the Step to add it to the Workflow. ### Adding Steps from alternative sources Generally, we recommend using Steps that are part of the official Bitrise Step Library. But you can add Steps from other sources, if you want to: you can use either a Git URL or a local path. On the Bitrise website, the `git::` special source is the easiest way to use a Step that is not in the Bitrise Step Library. Let’s see how. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Switch to **YAML** at the top of the Workflow Editor. 1. Add the git URL of the Step you want to use. In this example, we’re adding the Script Step from a git source: ```yaml - git::https://github.com/bitrise-io/steps-script.git@1.1.3: ``` 1. Click **Save**. ### Removing a Step from a Workflow You can remove a Step at any time. Be aware, however, that if you add it back at a later date, the Step inputs will be set to the default value - any custom configuration will be gone. :::tip[Disabling a Step] If you don't want a Step to run but want to keep the Step configuration intact, you can disable the Step: [Enabling or disabling a Step conditionally](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally). ::: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Click the Step you want to remove. 1. Click the three-dot menu icon and select **Delete item**. 1. Click **Save**. --- ## Detecting and aborting hanging Steps You can detect and abort hanging Steps that do not produce any log output for a certain amount of time using the **No Output Timeout** function. You can use this function to automatically abort hung builds after a configurable timeout period to save credits and to enable Bitrise to gather data on hanging builds. You can use the **No Output Timeout** function in two ways: - [Enable globally for all Steps](#enabling-the-no-output-timeout-function-globally-for-all-steps). - [Enable for specific Steps only](#enabling-the-no-output-timeout-function-for-specific-steps). The **No Output Timeout** function can be used alongside other timeout functionalities, such as the one described in the [M1 Hanging builds issue guide](https://devcenter.bitrise.io/en/infrastructure/build-stacks/apple-silicon-m1-stacks.html#hanging-builds-issue) or in [Setting a time limit for Steps](/bitrise-ci/workflows-and-pipelines/steps/setting-a-time-limit-for-steps). ### Enabling the No Output Timeout function globally for all Steps :::important[Bitrise 1.50.0 or newer is required] You must use Bitrise 1.50.0 or a newer version to use the **No Output Timeout** function. ::: To enable the **No Output Timeout** globally for all Steps: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Go to the **Secrets** tab. 1. Add a new secret Env Var: `BITRISE_NO_OUTPUT_TIMEOUT` and set its value to the number of seconds you want the build to wait for output logs before aborting. We recommend setting it to 600 seconds (10 minutes). ![app-level-secret.png](/img/_paligo/uuid-7d34c319-a1a2-05a1-90b0-ded10c048482.png) :::note[Aborting a hanging build automatically] Compared to [setting a time limit for Steps](/bitrise-ci/workflows-and-pipelines/steps/setting-a-time-limit-for-steps), the **No Output Timeout** function only aborts a build no output log is generated for a set amount of time. Any log output will reset the timeout. This can result in a Step running longer than the value you set in `BITRISE_NO_OUTPUT_TIMEOUT`. ::: 1. Click **Save**. You can check the Build log of your build to determine if the function is enabled. ![step-force-output.png](/img/_paligo/uuid-dc3bfafa-9720-8935-557a-97c317a8a624.png) And that's it! From now on, whenever a Step does not produce an output log for the number of seconds you set in `BITRISE_NO_OUTPUT_TIMEOUT` , your build automatically aborts with the message: `Abort via Bitrise CLI (no output timeout)`. :::tip[Disabling the No Output Timeout function for a specific Step] If you enabled the **No Output Timeout** function globally and want to disable it for specific Steps, you can add the `no_output_timeout: 0` Step property just above the `inputs:` part of the chosen Step(s) in the `bitrise.yml`. For example: ```yaml steps: - virtual-device-testing-for-ios@1: no_output_timeout: 0 inputs: - zip_path: "$BITRISE_PROJECT_PATH" ``` ::: ### Enabling the No Output Timeout function for specific Steps :::important[Bitrise 1.50.0 or newer is required] You must use Bitrise 1.50.0 or a newer version to use the **No Output Timeout** function. ::: You can enable the **No Output Timeout** function for specific Steps by adding the `no_output_timeout` Step property below a Step in your bitrise.yml file. To do so with the Workflow Editor: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Go to the **bitrise.yml** tab. 1. Search for the Step(s) where you would like to use the function. 1. Insert `no_output_timeout: 12` Step property and value just above the `inputs:` part of the chosen Step(s) to automatically abort a build if the Step does not produce an output log for 12 seconds. :::tip[Setting the `no_output_timeout` Step property to 0] You can disable the **No Output Timeout** function for a Step by setting the `no_output_timeout` Step property to 0. ::: Let's look at an example where a Script Step will always be aborted automatically: ```ruby output_slows_down: steps: - script@1: title: Output is slower and slower no_output_timeout: 12 inputs: - content: |- #!/usr/bin/env bash for i in {1..5} do DURATION=$((5*i)) echo "🏃‍step output (sleeping ${DURATION}s)" sleep $DURATION done ``` And that's it! Now, if your Step hangs and does not produce a single output log for the number of seconds you specified in the `no_output_timeout` Step property, the build will be aborted automatically. --- ## Disabling third-party Steps in a workspace You can configure your workspace to only allow official Bitrise Steps in its projects. By default, you can place any Step in your Workflows, including community Steps and custom Steps. However, you can disable third-party Steps, including: - [Verified Steps](/bitrise-ci/workflows-and-pipelines/developing-your-own-bitrise-step/verified-steps) - Community Steps ![settings-third-party-steps.png](/img/_paligo/uuid-f06634d9-f49d-0cc1-0c09-3d660920c3ba.png) ### Third-party Step restrictions If you disable third-party Steps: - If your configuration YAML is [stored on bitrise.io](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository), builds with third‑party Steps will start, but you can't save Workflow changes until the Steps are removed. - If your configuration YAML is [stored in the repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository), we cannot validate it and builds won’t start. - Script Steps are still present and can run arbitrary code, including [third-party tooling](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions). - When using the Workflow Editor on Bitrise, you won't be able to select third-party Steps, only Steps maintained by Bitrise. ### Disabling third-party Steps To disable third-party Steps: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Select **Security**. 1. Select the **Build policies** tab. 1. Optionally, request a report of Workflows using third-party Steps by clicking **Request report**. 1. Toggle **Allow third-party Steps** to off. ### Requesting an email report of third-party Steps You can request a usage report of third-party Steps: it contains all occurrences of third-party Steps in all Workflows, Step bundles, and Pipelines in a CSV file, sent via email. To request a usage report: 1. Open the **Workspace settings** page. 1. Select **Security**. 1. Select the **Build policies** tab. 1. Request a report of Workflows using third-party Steps by clicking **Request report**. --- ## Enabling or disabling a Step conditionally You can enable or disable a Step in any given Workflow, and you can also set conditions for Steps. You can do it either on your own computer with the Bitrise CLI, or by using the YAML editor in the Workflow Editor. We mostly use `run_if` expressions to do these things. Check out the examples for possible template expressions: [Examples of run_if expressions](#examples-of-run_if-expressions). You can also view the examples on GitHub: [Template expression examples](https://github.com/bitrise-io/bitrise/blob/master/_examples/experimentals/templates/bitrise.yml). :::note[A `run_if` can be any valid Go template] A `run_if` can be any valid [Go template](https://golang.org/pkg/text/template/), as long as it evaluates to `true` or `false` (or any of the String representation, for example `True`, `t`, `yes` or `y` are all considered to be `true`). If the template evaluates to `true`, the Step will run, otherwise it won’t. ::: An example `run_if` to check a custom [Environment Variable](/bitrise-ci/configure-builds/environment-variables): ```yaml run_if: |- {{enveq "CUSTOM_ENV_VAR_KEY" "test value to test against"}} ``` This `run_if` will skip the Step if the value of `CUSTOM_ENV_VAR_KEY` is not `test value to test against`. ### Disabling a Step If you do not want to remove a Step from your Workflow but you don’t want it to run, you can disable it, using a `run_if` expression. :::tip[Experimenting with Workflows] To experiment with different configurations for a Workflow, without removing or disabling Steps, we recommend cloning the Workflow. You can modify the cloned Workflow as much as you wish without changing anything in the original. ::: **Workflow Editor** 1. Open the Workflow you need. 1. Find the Step that you want to disable. 1. In the **Additional run conditions** input, type **false**. :::tip[Conditionals] Any condition that evaluates to false works, too. ::: **Configuration YAML** 1. Open your project’s configuration YAML file. 1. Find the Step that you want to disable. 1. Add `run_if: false` to it. :::tip[Conditionals] Any condition that evaluates to false works, too. ::: ```yaml - script: run_if: false inputs: - content: |- #!/bin/bash echo "This will never run, because of run_if:false" ``` ### Running a Step only in a CI environment Running a Step only in a CI environment means your build will skip that particular Step for local builds. Like disabling Steps, you can do this with a `run_if` expression. Use this to debug builds locally. :::tip[Enabling CI mode locally] CI mode can be enabled on your own Mac/PC by setting the `CI` environment to `true` (for example, run `export CI=true` in your Bash Terminal), or by running `bitrise run` with the `--ci` flag: `bitrise --ci run ...`. ::: **Workflow Editor** 1. Open the Workflow you need. 1. Find the Step you need. 1. In the **Additional run conditions** input, type `.IsCI`. **Configuration YAML** 1. Open your project’s configuration YAML file. 1. Find the Step you need. 1. Add `run_if: .IsCI` to its properties: ```yaml - script: run_if: .IsCI inputs: - content: |- #!/bin/bash echo "This will only ever run in a CI environment because run_if: IsCI" ``` ### Running a Step only if the build failed It is possible to run a Step ONLY if the build failed before it got to that particular Step. In addition to `run_if`, you will need to use the `is_always_run` property as well. **Workflow Editor** 1. Open the Workflow you need. 1. Find the Step that you want to disable. 1. In the **Additional run conditions** input, type `.IsBuildFailed`. 1. Make sure the **Run even if previous Step(s) failed** option is toggled on. **Configuration YAML** 1. Open your project’s configuration YAML file. 1. Find the Step that you want to disable. 1. Add `run_if: .IsBuildFailed` to it. 1. Add `is_always_run: true` to it. This enables the Step to run even if a previous Step failed. ```yaml - script: is_always_run: true run_if: .IsBuildFailed inputs: - content: |- #!/bin/bash echo "Build Failed!" ``` ### Ignoring a failed Step without failing the build Usually, when a Step fails during a build, the build itself fails, too. Cache, notification, and status reporting Steps (for example, **Save Cache** and **Slack**) are often configured by default to allow the build to continue even if they fail. You can also configure any other Step to ensure their failure doesn't fail the build. **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Click the Step you want to configure. 1. Under **When to run**, enable the **Continue build even if this Step fails** toggle. **Configuration YAML** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Switch to **YAML** at the top of the Workflow Editor. 1. Find the Step you need. 1. Add the `is_skippable` flag to it and set it to `true`: ```yaml - script: is_skippable: true inputs: - content: |- #!/bin/bash echo "Failing Step." exit 1 # exit 1 would mark this step as Failed, but it won't break the Build # because of the is_skippable: true flag / property ``` ### Setting up run_if conditions with Script Steps Sometimes the conditions required to determine whether a Step should run or not are complex and multi-layered. If so, using a complex chain of Go templates in a `run_if` expression can be overwhelming, especially if you prefer other languages instead of Go. In such cases, we recommend using a workaround: add a **Script** Step in your Workflow, and write a script that evaluates to a certain value. Store that value in an Environment Variable, and then the Step with the conditional expression only needs to check that value. **Using a non-Go script for a run_if expression** In this example, we'll create a simple Bash script and store its value, then check whether it matches a preset value. First, we add a Script Step, and in the script content, we define a value. Once the value is defined, we use `[envman](https://github.com/bitrise-io/envman/)` to store it in an Environment Variable. In this particular case, we define a variable in Bash, and use that variable as the value for our Env Var: ```yaml workflows: example: steps: - script@1: title: Do anything with Script step inputs: - content: |- #!/usr/bin/env bash # fail if any commands fails set -e # debug log set -x # creating the variable and storing it as an Env Var my_variable='This is the value we need!' envman add --key OUR_CONDITION --value "$my_variable" ``` We then create a simple `run_if` expression for the Step for which we need a condition. In this case, our Step is the **Save cache** Step, and we'll check if the value of the OUR_CONDITION variable matches the value stored in the previous Bash variable: ```yaml - save-cache@1: run_if: |- {{getenv "OUR_CONDITION" | eq "This is the value we need!"}} ``` Since the values match, the **Save cache** Step will run. ### Examples of run_if expressions There are many different ways of using a `run_if` expression. The following Workflow contains examples for most of them, with commented explanations. The expressions are used with **Script** Steps that, when successfully running, print that the used expression was true. All expressions are valid Go templates. To learn about Go templates, check out the documentation: [Go template docs](https://pkg.go.dev/text/template). ```yaml workflows: primary: steps: # # Check if an Environment Variable's value is equal to a given string - script: title: Run-If expression run_if: |- {{getenv "TEST_KEY" | eq "test value"}} inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # # Use the enveq function to check if an Env Var's value is equal to a given string - script: title: Run-If expression run_if: '{{enveq "TEST_KEY" "test value"}}' inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # Use envcontain to check if the value of an Env Var contains a given string. It works on the level of Pipelines, too - script: title: Run-If expression run_if: '{{envcontain "TEST_KEY" "test value"}}' inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # # Check if a given Env Var is NOT empty - script: title: Run-If expression run_if: '{{getenv "TEST_KEY" | ne ""}}' inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # # Check if two Env Vars have the same value - script: title: Run-If expression run_if: '{{getenv "TEST_KEY_1" | eq (getenv "TEST_KEY_2")}}' inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # # Use the available expression data properties # like IsCI (checks if the build runs in a CI environment) or IsBuildFailed (checks if the build has failed) directly - script: title: Run-If expression run_if: |- {{.IsCI}} inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # # You don't have to wrap the expression in {{...}} if it's a simple # oneliner - script: title: Run-If expression run_if: $.IsCI inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # # You can even remove the $ sign, it's optional in a simple # expression like this - script: title: Run-If expression run_if: .IsCI inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # # If-Else condition, in this example the Step will run if the build runs in a CI environment - script: title: Run-If expression run_if: |- {{if .IsCI}} true {{else}} false {{end}} inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # # You can use multiple conditions - script: title: CI and Not Failed run_if: |- {{.IsCI | and (not .IsBuildFailed)}} inputs: - content: |- #!/bin/bash echo "RunIf expression was true" # # Check if the build is a pull request or not - script: title: Only if NOT a pull request run_if: not .IsPR inputs: - content: |- #!/bin/bash echo "RunIf expression was true" - script: title: Only if it was a Pull Request run_if: .IsPR inputs: - content: |- #!/bin/bash echo "Pull Request ID: ${PULL_REQUEST_ID}" ``` --- ## Setting a time limit for Steps Ensure that your builds do not exceed the time limit by setting up Step timeout for Steps that might cause builds to hang. A Step timeout, defined in seconds, sets a maximum time a Step is allowed to run. If the Step exceeds that limit, it is marked as failed and the build fails. Steps with **Run even if previous Step(s) failed** enabled will still run. This is useful if, for example, your builds hang for not immediately obvious reasons — you can set timeouts for the Step or Steps which are suspected to have caused the problem. 1. Find the Step in the `bitrise.yml` file. You can edit the file locally, or in the YAML editor in the Workflow Editor. 1. Add a `timeout` property before the other Step inputs and specify its value in seconds: ```yaml - xcode-test@1.18.14: timeout: 120 inputs: - project_path: "$BITRISE_PROJECT_PATH" - scheme: "$BITRISE_SCHEME" ``` --- ## Skipping Steps You can configure a Step to run even if a previous Step in the Workflow failed. For example, if the [**Bitrise.io Cache:Pull**](https://github.com/bitrise-steplib/steps-cache-pull.git) Step fails, there is no reason not to run the subsequent Steps. :::note[Enabling a Step conditionally] You can also configure Steps to run only in certain conditions: [Enabling or disabling a Step conditionally](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally). ::: To set a given Step to run even if a previous Step failed: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Select the Step you want to configure to always run. 1. On the right, find and open the **When to run** section and toggle the **Run even if previous Step(s) failed** option. ![run-if-previous-failed.png](/img/_paligo/uuid-26832e7b-a5be-8098-d683-cd04a9d2cc04.png) --- ## Step bundles Step bundles allow you to group multiple Steps into a single unit. With Step bundles, you can reuse Steps and sequences of Steps without manually copying and pasting from a YAML configuration file. Step bundles are configured with a root level entity called `step_bundles`. You can insert Step bundles into any Workflow. Unlike utility Workflows and [Workflow chaining](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#chaining-workflows-together), Step Bundles can be placed anywhere in a Workflow. When running a build, each Step within the bundle will run at the position the bundle is inserted. ### Creating a Step bundle **Workflow Editor** 1. Open the Workflow Editor. 1. On the left, select **Step bundles**. 1. Click **Create Step bundle** if you don't have any bundles. If you already have at least one Step bundle, open the dropdown menu in the middle and click **Create Step bundle**. ![create-step-bundle.png](/img/_paligo/uuid-955d7e00-c03b-fa26-f239-dcf2f2b2708a.png) 1. In the dialog, provide an ID for your bundle. ![Create Step bundle dialog](/img/workflows-and-pipelines/2026-07-06-create-step-bundle-dialog.png) 1. If you have existing Step bundles, you can select one from the dropdown menu: your new Step bundle will be a copy of the existing one. 1. When done, click **Create Step bundle**. 1. Add your first Step by clicking **Add Step or Step bundle**. Adding a Step bundle within another Step bundle is called nesting: [Nested Step bundles](/bitrise-ci/workflows-and-pipelines/steps/step-bundles#nested-step-bundles). 1. Add additional Steps or bundles by hovering above or under an already added Step or bundle and clicking on the plus sign. 1. Configure new bundle inputs under the **Configuration** tab by clicking **+ Add input**. In the **New bundle input**dialog you can define input variables to manage multiple Steps within a bundle. Reference their keys in Steps and assign custom values for each Workflow. ![bundleinput.png](/img/_paligo/uuid-b51f2636-2f9d-89c2-595e-db6ab80d5416.png) **Configuration YAML** 1. [Open the configuration YAML of your project](/bitrise-ci/configure-builds/configuration-yaml/editing-an-app-s-bitrise-yml-file). 1. Add a `step_bundles` entity to the top level of the YAML file and give it a name. You will refer to the bundle by this name. ```yaml format_version: 11 step_bundles: install_deps: ``` 1. Add a `steps` property under your bundle and add the Steps you want to run. You can [reference Steps](/bitrise-ci/references/steps-reference/step-reference-id-format) here the same way as in a Workflow. In this example, we add the *restore-cache* Step and an `npm` Step. ```yaml format_version: 11 step_bundles: install_deps: steps: - restore-cache@1: {} - npm@1: {} ``` 1. Add your Step bundle to an existing Workflow. The syntax works like this: `bundle::`. ```yaml workflows: ci: steps: - git-clone@8.1: {} - bundle::install_deps: {} - deploy-to-bitrise-io@2: {} ``` ### Creating a Step bundle based on a utility Workflow You can create a Step bundle based on a [utility Workflow](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#utility-workflows). The bundle will contain all the Steps that were part of the utility Workflow. But unlike a utility Workflow, you can place the Step bundle anywhere within another Workflow. 1. Open the Workflow Editor. 1. On the left, select **Step bundles**. 1. From the **Based on** dropdown menu, choose a utility Workflow. ![Screenshot_2025-03-25_at_09_59_54.png](/img/_paligo/uuid-8b6d8a17-8028-3064-a48d-9a43b0328391.png) 1. Click **Create Step bundle**. ### Naming Step bundle instances You can add optional metadata fields to Step bundle instances to make your Workflow configs and build logs easier to read in Workflows. :::note[Step bundle instance] Step bundles are reusable config blocks - you define them once and can use them (instantiate them) across Workflows or in the same Workflow. ::: You can set three optional metadata fields: **title**, **summary** and **description** in your Step bundle. These attributes override the generic information from the bundle's definition for that specific instance only, giving you granular control over how it's displayed in a particular Workflow. If you use these attributes, you don't need to add comments to Step bundles to distinguish two instances from each other. A Step bundle instance can include: - **title**: a human-readable name for this specific usage. - **summary**: a brief description. - **description**: detailed information about what this instance does. ![stepbundleinstance.png](/img/_paligo/uuid-9cf7ca34-d643-d13c-d241-42cefd6dc847.png) These fields show up in the Bitrise UI and build logs, making it immediately clear what each instance is doing. ```yaml - step-bundle-id: title: "A clear, human-readable title for this instance" summary: "A short summary of what this instance does." description: "A more detailed markdown-supported description if needed." inputs: - ... ``` **Additional attributes for Step bundle instances** Let's say you have a Step bundle defined with the ID `run-my-tests` that builds and tests a specific scheme. You want to use it twice in your primary Workflow: once for unit tests on an iPhone simulator, and again for UI tests on an iPad simulator. ```yaml workflows: primary: steps: - run-my-tests: title: "Run unit tests on iPhone" summary: Runs the UnitTests test plan. inputs: - scheme: "MyApp" - destination: "platform=iOS Simulator,name=iPhone 14" - test_plan: "UnitTests" - run-my-tests: title: "Run UI tests on iPad" summary: Runs the UITests test plan. inputs: - scheme: "MyApp" - destination: "platform=iOS Simulator,name=iPad Pro (12.9-inch)" - test_plan: "UITests" ``` The build log and Workflow editor now displays `"Run unit tests on iPhone"` and `"Run UI tests on iPad"` as the Step titles. If the UI tests fail, you'll know immediately without having to inspect the logs. ### Nested Step bundles Step bundles allow nesting: you can add a Step bundle within another Step bundle. This allows you to create large, complex configurations with easily replaceable parts. You can add as many Step bundles within another Step bundles as you want. **Workflow Editor** 1. Open the Workflow Editor. 1. On the left, select **Step bundles**. 1. Select a Step bundle from the dropdown menu in the middle. 1. If it's an empty bundle, click **Add Step or Step bundle**. If the bundle already has Steps in it, hover between Steps and click the plus sign. ![add-bundle-to-bundle.png](/img/_paligo/uuid-e4db471e-3219-872f-8c6f-7aa194b7f156.png) 1. In the dialog, go to the **Step bundle** tab. ![bundle-tab.png](/img/_paligo/uuid-68c17140-7ed7-eae8-4101-12d403bee8e4.png) 1. Select a bundle to add it to the original bundle. 1. Use drag-and-drop to move it within the bundle. 1. When done, click **Save changes** **Configuration YAML** 1. In the configuration YAML file, define the Step bundle you want to nest within a `step_bundles` property. ```yaml step_bundles: initialize: steps: - activate-ssh-key: {} - git-clone: {} ``` 1. Nest this bundle within another one by using the `bundles` property. ```yaml step_bundles: initialize: steps: - activate-ssh-key: {} - git-clone: {} deploy_bundle: steps: - bundle::initialize: {} - deploy-to-bitrise-io: {} ``` ### Step bundle inputs In any Step bundle, a list of inputs can be defined under the `inputs` key. These are the only inputs you can set for a Step bundle: you can't define additional inputs outside the bundle definition. You can, however, set values for the predefined inputs of a Step bundle outside the bundle definition: [Configuring Step bundle inputs](#configuring-step-bundle-inputs). Step bundle inputs share the same model as Step inputs. You can read more about Step inputs and their format: [Step inputs reference](/bitrise-ci/references/steps-reference/step-inputs-reference). 1. In your configuration YAML file, add the `inputs` property to your Step bundle. ```yaml format_version: 11 step_bundles: install_deps: inputs: ``` 1. Under `inputs`, add key-value pairs that will be used for Step inputs. ```yaml format_version: 11 step_bundles: install_deps: inputs: - cache_key: "npm-cache-{{ checksum "package-lock.json" }}" - npm_command: install ``` 1. Add the keys to the appropriate Step inputs. In our example, we configured default inputs for the `key` input of the `restore-cache` Step and the `command` input of the `npm` Step. ```yaml format_version: 11 step_bundles: install_deps: inputs: - cache_key: "npm-cache-{{ checksum "package-lock.json" }}" - npm_command: install steps: - restore-cache@1: inputs: - key: $cache_key - npm@1: {} inputs: - command: $npm_command ``` ### Configuring Step bundle inputs You define Step bundle inputs in the Step bundle definition and you can't add new inputs outside the definition. You can set new values for Step bundle inputs defined in the Step bundle in the Step list of the Workflow: 1. In your configuration YAML file, find your Workflow and the Step bundle in its `steps` list. 1. Add an `inputs` property where your Step bundle is referenced, and add a key-value pair to it. In this example, we set a new value of the `cache_key` input instead of its default value defined in the Step bundle. When the Workflow runs, the `restore-cache` Step will use the `npm-cache` value instead of `npm-cache-{{ checksum "package-lock.json" }}`. ```yaml format_version: 11 step_bundles: install_deps: inputs: - cache_key: "npm-cache-{{ checksum "package-lock.json" }}" - npm_command: install steps: - restore-cache@1: inputs: - key: $cache_key - npm@1: inputs: - command: $npm_command workflows: ci: steps: - git-clone@8: {} - bundle::install_deps: inputs: - cache_key: "npm-cache" - deploy-to-bitrise-io@2: {} ``` ### Step bundle outputs Steps can generate output variables. When Steps are included in a Step bundle, their output variables are available to all Steps in the Workflow after the Step bundle. For example, if the Step bundle used in the Workflow uses the `xcode-archive` Step, the next Steps after the bundle will have access to the BITRISE_IPA_PATH output variable which is exposed by the Step. ### Step Bundle conditional execution with run_if Using `run_if` condition with Step bundles allows you to conditionally execute entire bundles based on Environment Variables or other criteria. When you apply `run_if` directly to Step bundle calls in your workflow, the condition is evaluated before the bundle executes. If it evaluates to false, the entire bundle and all its Steps are skipped. The `run_if` syntax works the same as it does for individual Steps. All the `run_if` [template expressions and custom template functions](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally#examples-of-run_if-expressions), for example, `getenv`, `enveq`, and `envcontain` are supported for Steps. **Skip deployment bundles for draft PRs** In this example, the `deploy-to-staging` bundle would run only if the PR is not a draft PR. Similarly, the `notify-slack` bundle would run only if it is a successful build. ```yaml workflows: deploy: steps: - bundle::build-and-test: {} - bundle::deploy-to-staging: run_if: '{{ not (envcontain "BITRISE_GIT_MESSAGE" "[draft]") }}' - bundle::notify-slack: run_if: '{{ not .IsBuildFailed }}' ``` 1. Open your project's Workflow Editor. 1. Click **Step bundles** on the left. 1. Select the **Configuration** tab and enter a value under **Additional run conditions**. ![2025_08_15_step_bundle_conditional_execution_runif.png](/img/_paligo/uuid-d84d9f1d-68d7-2706-a7cb-b2023ffe96a5.png) You can specify a `run_if` in the definition or in the Step bundle instance as well: - When the `run_if` is in the definition, then it serves as the default run_if for all instances. - When the `run_if` is in the instance, it overrides the definition, and that single instance will have the `run_if`. If a Step bundle is usually executed conditionally, it is better to define `run_if` on the definition, so that all instances will get the sensible default `run_if` . Like a repo clone and setup bundle that usually only make sense in a CI environment (that's why the git-clone Step itself has a `run_if: .IsCI`). Learn more about how to [enable/disable and set conditions for a Step](/bitrise-ci/workflows-and-pipelines/steps/enabling-or-disabling-a-step-conditionally#examples-of-run_if-expressions) with `run_if` expressions. #### Migration If you currently have identical `run_if` conditions on multiple Steps within a bundle, here is how you can streamline your workflow with `run_if` on Step bundles. Before: ```yaml workflows: test: steps: - bundle::my-test-suite: {} step_bundles: my-test-suite: steps: - script: run_if: '{{ enveq "RUN_TESTS" "true" }}' # ... - gradle-runner: run_if: '{{ enveq "RUN_TESTS" "true" }}' # ... - deploy-to-bitrise-io: run_if: '{{ enveq "RUN_TESTS" "true" }}' # ... ``` After: ```yaml workflows: test: steps: - bundle::my-test-suite: run_if: '{{ enveq "RUN_TESTS" "true" }}' step_bundles: my-test-suite: steps: - script: # ... - gradle-runner: # ... - deploy-to-bitrise-io: # ... ``` --- ## Step inputs Step inputs are the way to configure the Steps for your build. Steps have required inputs that must have a valid value and optional inputs that provide more options to customize your build. Click on a Step to bring up its input variables on the right of the currently selected Workflow. Required inputs are marked as such in the Workflow Editor. If required inputs do not have valid values, the Step will fail. ![Step input fields with Insert variable button](/img/workflows-and-pipelines/2026-07-06-step-input-insert-variable.png) Modify a Step input by either: - Clicking into the input field. - Clicking the **Insert variable** button next to the input field to insert an Environment Variable as the value. You can also use [Environment Variables (Env Vars) as Step inputs.](/bitrise-ci/configure-builds/environment-variables#using-an-env-var-in-a-step-input) --- ## Step versions Bitrise Step versions follow semantic versioning: a version number looks like MAJOR.MINOR.PATCH. For example, version 3.2.1 is the first patch of the second minor version of the third major version. You can use any existing version of a Step in your Workflows, and different versions of the same Step in different Workflows. We regularly update our Steps to make sure they are fully equipped for our users’ needs. However, you don’t have to use the latest version if you don’t want to: if an old version is stable and compatible with your build, feel free to continue using that, or roll back to it any time. ### Locking a Step to a major or minor version On the graphical UI of the Workflow Editor, you can choose between locking a Step to either a major version or a minor version in any of your Workflows. This determines what version of the Step your Workflow will use. Locking a Step to a version means that your Workflow is automatically updated to use the latest release of the Step’s selected version type, either major or minor, but it won’t get updated if a different major or minor version is released. - If a Step is locked to a major version, it is automatically updated if a new minor version or a new patch for that major version is released. If a new major version is released, it won’t be updated. - If a Step is locked to a minor version, it is automatically updated only if a new patch for that minor version is released. If a new minor or major version is released, it won’t be updated. **Version locking** The Example Step’s current version in the Workflow is 2.3.3. A new minor version comes out: 2.4.0. - If the Step is locked to major version 2.x.x, the Step is updated to 2.4.0. - If the Step is locked to minor version 2.3.x, the Step is NOT updated to 2.4.0. Now let’s say the Example Step gets a new major version: 3.0.0! In that case, the Step will not be automatically updated either way. If you want to use the new version, you need to lock the Step to either major version 3.x.x or minor version 3.0.x. This way you can be sure that a new update will not break your builds. To set the update policy for a Step: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Select the Step. 1. Go to the **Properties** tab. 1. Open the **Version** dropdown menu, and select your version. ![Step Version dropdown in the Properties tab](/img/workflows-and-pipelines/2026-07-06-step-version-dropdown.png) ### Using a specific Step version You have the option of using a specific, static Step version. For example, version 3.2.2. This means that no matter what new versions are released for the Step, your Step version will not be updated in the Workflow. :::important[YAML mode only!] Please note that you cannot set a specific Step version on the graphical UI: you can only lock the Step to either a major or minor version. Setting a specific Step version is only possible in YAML mode. ::: To set a specific Step version, you need to add that version to the Step reference in your app’s configuration YAML file: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Switch to **YAML** at the top of the Workflow Editor. 1. Find the Workflow and the Step you need. 1. Set the Step version as part of the Step reference. In this example, we're setting the **Activate SSH key** Step of the **primary** Workflow to version 4.0.3: ```yaml workflows: primary: steps: - activate-ssh-key@4.0.3: ``` ### Using the latest available version of the Step Locking on to the latest release of a Step means that if a new version of the Step is released, the user’s Workflow is updated to use that. This includes automatic update to a new major version, potentially breaking the build. So be careful! To make sure your Workflow will always use the latest available version of a given Step, all you have to do is remove any version information from the Step reference in the `bitrise.yml` file of your app: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Switch to **YAML** at the top of the Workflow Editor. 1. Find the Workflow and the Step you need. 1. Make sure the Step has no version information: In this example, we're setting the **Activate SSH key** Step of the **primary** Workflow to the latest version: ```yaml workflows: primary: steps: - activate-ssh-key: ``` --- ## Steps overview Steps are the heart of Bitrise. A Step is a build task: for example, the [**Git Clone Repository**](https://github.com/bitrise-steplib/steps-git-clone) Step clones your Git repository at the start of a build while the [**Google Play Deploy**](https://github.com/bitrise-io/steps-google-play-deploy) Step can deploy your finished app to the Play Store. A Step contains the code that performs the build task. You can configure the inputs and parameters that define the task, and view and reuse the outputs a Step generates. Reusing the output means that another Step can use it as the value of one of its inputs. Our Steps are defined in YAML format, and written in either bash or Go. You can find a list of our Steps in: - [The Integrations page](https://www.bitrise.io/integrations). - [The Bitrise StepLib](https://github.com/bitrise-io/bitrise-steplib). - The Workflow Editor. You can also create and run any custom script you want as part of your Bitrise build using the [**Script**](https://github.com/bitrise-io/steps-script) Step. All you need to do is specify the script runner (the default is bash), add the script, and run a build. For more information on how to set up these custom scripts, check out [Bitrise Script Step - Running (Bash, Python, NodeJS, Ruby, Swift, Kotlin)](https://support.bitrise.io/hc/en-us/articles/8932506599955-Bitrise-Script-Step-Running-Bash-Python-NodeJS-Ruby-Swift-Kotlin-). For the purposes of your builds, Steps can be managed directly from the Workflow Editor. You can rearrange them, set their versions, add or remove Steps at any time. ### Types of Steps Bitrise has over 400 Steps in its [Step Library (StepLib)](https://github.com/bitrise-steplib) which third-party companies or open-source teams can enrich with Steps based on their services/tools. There are three different types of Steps at Bitrise. You can identify each one based on their labels on our GUI: - **Official Bitrise Steps**: These Steps are created and maintained by Bitrise. These Steps are labeled by a green badge and a "B". - **Verified Steps**: These Steps are created and maintained by the community, but they are owned by a service or tool or an open-source team that guarantees secure, maintained, consistent, and high-quality performance for any Bitrise user. These Steps are labeled by a blue badge and a check mark. For more information about Verified Steps, check out [our guide](/bitrise-ci/workflows-and-pipelines/developing-your-own-bitrise-step/verified-steps#about-verified-steps). - **Community Steps**: These Steps can be created by anyone in the community. These Steps are not labeled and don't have a badge. If you would like to learn how to develop Steps and share them with the Bitrise community, check out [Developing a new Step](/bitrise-ci/workflows-and-pipelines/developing-your-own-bitrise-step/developing-a-new-step). ![StepTypes.png](/img/_paligo/uuid-5b243f17-057e-1324-1fd8-31305be6c08c.png) --- ## Copying Workflows from one app to another If you have a lot of projects, you might not want to spend time with setting up Workflows for each and every one of them separately, especially if there’s little difference between the Workflows you want to run for them. If so, the easiest thing to do is to simply copy an existing Workflow. :::important[YAML mode only] Copying a Workflow to another project is only possible in YAML mode. [You can create a new Workflow based on an existing one](/bitrise-ci/workflows-and-pipelines/workflows/creating-a-workflow) but only for the same app. ::: You can copy a Workflow from any [configuration YAML file](/bitrise-ci/configure-builds/configuration-yaml/configuration-yaml-overview), including your local files. To copy an existing Workflow from one Bitrise project to another on our website: 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Switch to **YAML** at the top of the Workflow Editor. 1. Select the Workflow you want and copy it. 1. Open the project you want to copy it to. 1. Go to **Workflows** and switch to **YAML** at the top of the Workflow Editor. 1. Paste the Workflow under the `workflows` property. --- ## Creating a Workflow :::note[Workflows in YAML] This guide is about creating a Workflow in the Workflow Editor. For YAML configuration syntax, check out [Workflow level properties](/bitrise-ci/references/configuration-yaml-reference#workflow-level-properties). ::: It’s very simple to create your own Workflow with the Workflow Editor. You can create new Workflows based on any of the existing ones, or you can simply create an empty Workflow and add the Steps yourself. :::tip[Work on your configuration locally] The [offline Workflow Editor](/bitrise-ci/bitrise-cli/installing-and-upgrading-the-offline-workflow-editor) runs on your own computer: you can edit your project's configuration YAML file without logging in to [bitrise.io](https://www.bitrise.io/), and your configuration never leaves your network. It offers most features of the Workflow Editor. ::: If, for example, you create a Workflow based on your **primary** one, it means that it will be created with the exact same Steps and input values as the **primary** Workflow. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Open the Workflow selector dropdown and click **Create Workflow**. ![Workflow selector dropdown with Create Workflow button](/img/workflows-and-pipelines/2026-07-06-create-workflow-dropdown.png) 1. In the dialog, give your Workflow an ID. The ID can only contain the following characters: `A-Za-z0-9-_.` ![Create Workflow dialog with ID field](/img/workflows-and-pipelines/2026-07-06-create-workflow-dialog.png) 1. From the dropdown menu labeled **Based on**, select the Workflow you want to use as the basis for the new one. Alternatively, choose the **An empty workflow** option to create an empty Workflow. 1. Add the Steps you need to your Workflow. Click the **+** (**Add Step or Step bundle**) symbol between two Steps to insert a Step at that position. Remove Steps you do not need by clicking on the Step, opening the three-dot menu, and selecting **Delete item**. 1. Click **Save changes** in the top right corner. --- ## Default Workflows When you add a new project on [bitrise.io](https://www.bitrise.io), we create initial Pipelines and Workflows for you. These are called default Pipelines and Workflows. A default Pipeline consists of default Workflows. You can use these to run your tests or create installable binaries such as IPAs or APKs. Feel free to modify the default Pipelines and Workflows to suit your needs. :::tip[Default Pipelines] We also create default Pipelines: [Default Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/default-pipelines). ::: ### Default Workflows for an iOS project For a new iOS project, Bitrise automatically generates several Workflows. You can customize these Workflows or [create new ones](/bitrise-ci/workflows-and-pipelines/workflows/creating-a-workflow) based on them. | Workflow ID | Workflow summary | Workflow description | | --- | --- | --- | | `run_tests` | Run your Xcode tests and get the test report. | The Workflow clones your Git repository, caches and installs your project’s dependencies if any, runs your Xcode tests and saves the test results. | | `build_for_testing` | Builds your Xcode project ready for testing. | The Workflow clones your Git repository, builds your app ready for testing, apportions tests into each test shard and deploys the app plus tests to Bitrise so they can be used in subsequent Workflows. This Workflow is part of a default Pipeline. | | `test_without_building` | Tests your iOS app without needing to rebuild it. | Retrieves the app and tests from the preceding Workflow in a Pipeline and tests compiled bundles using Xcode’s `test_without_building` command. This Workflow is part of a default Pipeline. | | `archive_and_export_app` | Run your Xcode tests and create an IPA file to install your app on a device or share it with your team. | The Workflow clones your Git repository, caches and installs your project’s dependencies if there are any, runs your Xcode tests, and [exports an IPA file from the project](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). | | `build` | Builds your Xcode project. This Workflow is generated only if the project scanner didn't find any tests configured in your Xcode project. | The Workflow clones your Git repository, caches and installs your project’s dependencies if there are any, and builds your project. It uses Xcode's [build for testing](/bitrise-ci/testing/testing-ios-apps/building-an-ios-app-for-testing) action. | ### Default Workflows for an Android project For a new Android project, Bitrise automatically generates three new Workflows. You can customize these Workflows or [create new ones](/bitrise-ci/workflows-and-pipelines/workflows/creating-a-workflow) based on them. | Workflow ID | Workflow summary | Workflow description | | --- | --- | --- | | `run_tests` | Run your Android unit tests and get the test report. | The Workflow clones your Git repository, [caches your Gradle dependencies](/bitrise-ci/dependencies-and-caching/android-dependencies), installs Android tools, runs your [Android unit tests](/bitrise-ci/testing/testing-android-apps/android-unit-tests) and saves the [test report](/bitrise-ci/testing/deploying-and-viewing-test-results). | | `build_apk` | Run your Android unit tests and create an APK file to install your app on a device or share it with your team. | The Workflow clones your Git repository, installs Android tools, [sets the project’s version code based on the build number](/bitrise-ci/run-and-analyze-builds/build-numbering-and-app-versioning#setting-up-app-versioning-automatically-on-bitrise), [runs Android lint](/bitrise-ci/testing/testing-android-apps/running-lint-for-your-android-apps) and unit tests, builds the project’s APK file and save it. | | `run_instrumented_tests` | Run your Android instrumented tests with test sharding and get a test report. | The Workflow clones your Git repository, [caches your Gradle dependencies](/bitrise-ci/dependencies-and-caching/android-dependencies), installs Android tools, boots up an Android emulator to run your Android instrumented tests and saves the [test report](/bitrise-ci/testing/deploying-and-viewing-test-results). This Workflow is part of a default Pipeline which utilizes [parallelism](/bitrise-ci/workflows-and-pipelines/build-pipelines/configuring-a-bitrise-pipeline#running-variations-of-the-same-workflow): it runs multiple copies of the Workflow to shard instrumented tests. | ### Default Workflows for a Node.js project Bitrise generates one default Workflow for a Node.js project: a Workflow to run your project's lint and test scripts. You can customize this Workflow or create new ones based on it. | Workflow ID | Workflow summary | Workflow description | | --- | --- | --- | | `run_tests` | Run your project’s tests. | The Workflow clones your Git repository, selects and installs the Node version, installs the `npm` packages, and, depending on the available scripts in your `package.json` file, runs the lint and test scripts. The Workflow also supports `node_modules` caching for better performance. The `lint` and `test` steps use npm or Yarn depending on which package manager was detected. If neither lock file is present, the user selects the package manager interactively during setup. | ### Default Workflows for a Kotlin Multiplatform project Bitrise generates three default Workflows for a Kotlin Multiplatform project: one to run tests, one to build an Android app, and one to build an iOS app. | Workflow ID | Workflow summary | Workflow description | | --- | --- | --- | | `run_tests` | Run your project’s tests. | The Workflow clones your Git repository, runs the `test` Gradle task using the **Gradle Unit Test** Step, and caches your Gradle task outputs. | | `android_build` | Builds and signs an Android app from your Kotlin project. | The Workflow clones your Git repository, builds your app using the **Android Build** Step, [signs](/bitrise-ci/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step) it with **Android Sign**, and caches your Gradle task outputs. It produces a downloadable APK file. | | `ios_build` | Builds and signs an iOS app from your Kotlin project. | The Workflow clones your Git repository, builds and [signs](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) your app using the **Xcode Archive & Export for iOS** Step, and caches your Gradle task outputs. It produces a downloadable IPA file. | ### Default Workflows for a Java project The project scanner can detect Java projects and create default Workflows for them. A new project is considered a generic Java project if: - It uses Gradle (the code contains the usual Gradle configuration files and a Gradle Wrapper script in the project root directory) and it doesn't use Android or Kotlin Multiplatform required dependencies. - It uses Maven with a `POM.xml` project configuration file in the root directory, and has a Maven Wrapper script. For a generic Java project, Bitrise generates default Workflows based on the build tool. | Workflow ID | Workflow summary | Workflow description | | --- | --- | --- | | `run_tests` | Run your projects tests. | The Workflow clones your Git repository and runs tests by using the **Run Gradle Tests** Step which runs the `test` Gradle task. | | Workflow ID | Workflow summary | Workflow description | | --- | --- | --- | | `run_tests` | Run your projects tests. | The Workflow clones your Git repository and runs tests by using a Script step, running the Maven Wrapper’s test command: `./mvnw test`. | ### Default Workflows for a Ruby project | Workflow ID | Workflow summary | Workflow description | | --- | --- | --- | | `run_tests` | Run your project’s tests. | The Workflow clones your Git repository and restores your gem cache with the `gem-{{ checksum "Gemfile.lock" }}` caching key. It installs dependencies depending on signals in your codebase: - If MySQL gem is detected, it installs system dependencies. - If Bundler is detected, it installs dependencies with `bundle install`. If a relation database gem is detected, it performs database setup: `db:create db:schema:load`. If a test framework or a Rakefile is detected, the Workflow runs your tests. The Workflow always saves the Ruby gem cache and includes the **Deploy to Bitrise.io** Step. | ### Default Workflows for a Python project For Python, a single `run_tests` Workflow is generated. The included Steps depend on the detected package manager and whether `pytest` was found in the project. | Workflow ID | Workflow summary | Workflow description | | --- | --- | --- | | `run_tests` | Run your project’s tests. | The Workflow clones your Git repository and installs Python based on the detected version. If no version is detected, the stack's default Python version is used. Installs dependencies: the exact command used depends on the detected package manager. If `pytest` is detected, the Workflow runs your tests. | ### Default Workflows for a Flutter project For Flutter projects, Bitrise creates two default Workflows: a `run_tests` Workflow and a `build_app` Workflow. The exact Steps included in these default Workflows depend on the project type. However, the main goals of the two Workflows are the same, regardless of project type: | Workflow ID | Workflow summary | Workflow description | | --- | --- | --- | | `run_tests` | Run your project’s tests. | The Workflow clones your Git repository, installs Flutter with the **Flutter Installer** Step, runs **Restore Dart cache** to pull your Dart cache. It runs: - The **Flutter Test** Step when there is a `test/` directory in the project. - The **Flutter Analyze** Step when there is no `test/` directory in the project. After running the tests, it saves the Dart cache and runs the **Deploy to Bitrise.io** Step to deploy any artifacts. | | `build_app` | Builds both the iOS and the Android app from the Flutter project. | This Workflow is only generated when the project has an iOS or Android sub-project. For web projects, this Workflow is not generated. The Workflow clones your Git repository, installs your code signing certificate for the iOS project, installs Flutter, runs the **Flutter Analyze** Step. It also runs the **Flutter Test** Step when a `test/` directory is present. It builds the app with the **Flutter Build** Step. It builds all detected platforms. | --- ## Managing Workflows You can chain multiple Workflows and rearrange the order of Workflows in a chain in the Bitrise Workflow Editor. Take advantage of utility Workflows to reuse components in multiple different contexts. :::tip[Work on your configuration locally] The [offline Workflow Editor](/bitrise-ci/bitrise-cli/installing-and-upgrading-the-offline-workflow-editor) runs on your own computer: you can edit your project's configuration YAML file without logging in to [bitrise.io](https://www.bitrise.io/), and your configuration never leaves your network. It offers most features of the Workflow Editor. ::: ### Chaining Workflows together You can set up multiple Workflows to run in succession. The order of these Workflows can be rearranged, new Workflows can be added to the chain and existing Workflows can be removed from it at any time. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Hover over the Workflow card and click the **Chain Workflows** icon button that appears. ![Workflow card with the Chain Workflows icon button highlighted](/img/workflows-and-pipelines/2026-07-06-chain-workflows-button.png) 1. In the **Chain Workflows** drawer, select a Workflow from the list and click **Add before** or **Add after**. 1. Click **Save changes** in the top right corner. **Chaining Workflows in YAML** In this example, we're chaining together three Workflows: `test`, `deploy`, and `ci`, using the before_run and after_run parameters. ```yaml workflows: test: envs: - IS_TEST: "true" steps: # test Steps to run deploy: before_run: - test steps: # steps to deploy ci: before_run: - test after_run: - deploy ``` For more information on how to manage Workflows directly in the `bitrise.yml` file, check [Workflow level properties](/bitrise-ci/references/configuration-yaml-reference#workflow-level-properties). ### Rearranging chained Workflows Once you have a chain, you can easily rearrange the order of Workflows in a drag-and-drop menu. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the Workflow card, hold down the drag handle on the left side of a chained Workflow and drag it to the desired position. ![Chained Workflow card with the drag handle on the left side](/img/workflows-and-pipelines/2026-07-06-chain-workflows-drag-handle.png) 1. Click **Save changes** in the top right corner. ### Workflow priority You can set a priority for each individual Workflow. The priority setting determines the position of a standalone build of the Workflow in the build queue: the higher the priority, the sooner the Workflow's build will run. You can assign a priority either in the Workflow Editor or in the configuration YAML file of your project. The priority is always an integer between -100 and 100: the higher the number, the higher the priority. The default priority is 0. For more information about build priority, and the order of precedence between different types of priorities, check out [Build priority](/bitrise-ci/configure-builds/configuring-build-settings/build-priority). ### Utility Workflows :::important[Step bundles] Instead of utility Workflows, we strongly recommend using [Step bundles](/bitrise-ci/workflows-and-pipelines/steps/step-bundles). They allow you to group multiple Steps into a single unit and reuse them at any point of a Workflow. ::: Bitrise supports a special type of Workflow called a utility Workflow. A utility Workflow's ID always starts with an underscore character: for example, `_setup`. They are usually used to perform tasks that are required either at the start or at the end of several different Workflows: for example, you can separate git cloning and activating your SSH key into a utility Workflow instead of adding those Steps to every Workflow of an app. You can create a utility Workflow [the exact same way](/bitrise-ci/workflows-and-pipelines/workflows/creating-a-workflow) as you create a regular one. To denote it as a utility Workflow, you just need to prefix the name with an underscore. :::important[Utility Workflows cannot run alone] Utility Workflows cannot be run as standalone Workflows. They need to be chained together with a normal Workflow, either before or after the Workflow: [Chaining Workflows together](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#chaining-workflows-together). ::: **Utility Workflow in YAML** In this example, we have two utility Workflows, called `_setup` and `_send-notifications`. They are chained together with two Workflows called `test` and `ci` using the before_run and after_run parameters. ```yaml workflows: _send-notifications: steps: # send notifications _setup: steps: # setup Steps to run test: before_run: - _setup envs: - IS_TEST: "true" steps: # test Steps to run ci: before_run: - test after_run: - _send-notifications ``` For more information on how to manage Workflows directly in the `bitrise.yml` file, check [Workflow level properties](/bitrise-ci/references/configuration-yaml-reference#workflow-level-properties). --- ## Workflows overview A Bitrise Workflow is a collection of Steps. When a build of a project is running, each Step will be executed in the order that is defined in the Workflow. Workflows can be created, defined and modified in two ways: - Using the graphical Workflow Editor on [bitrise.io](https://www.bitrise.io), or [the offline version on your own device](/bitrise-ci/bitrise-cli/installing-and-upgrading-the-offline-workflow-editor). - Directly editing the `bitrise.yml` file of your project. Ultimately, both methods modify the `bitrise.yml` file - the **Workflow Editor** is simply a friendlier way of doing so! By default, a single build is a single Workflow. But you can also chain Workflows together so they run in succession, as well as to trigger multiple Workflow to run simultaneously. Workflows can also be arranged into [Pipelines](/bitrise-ci/workflows-and-pipelines/build-pipelines/pipelines-with-stages/configuring-a-pipeline-with-stages). A Pipeline consists of multiple Stages and each Stage consists of one or more Workflows which run in parallel. --- ## Accounts overview When you sign up for Bitrise, you create your own individual user account. By itself, having a user account isn’t enough to add projects and run builds. For that, you must be part of a workspace or invited to a project as an outside contributor. You can connect your personal account to: - Your Git provider accounts via OAuth, allowing you to log in to Bitrise through your Git provider and to configure repository access for Bitrise CI: [Repository access with OAuth](/bitrise-platform/repository-access/repository-access-with-oauth). - The Bitrise GitHub App, allowing authentication and repository access without the need for SSH keys: [GitHub app integration](/bitrise-platform/repository-access/github-app-integration). - Your Apple ID, allowing you to connect Bitrise projects to an Apple service: [Connecting to an Apple service with Apple ID](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id). ### Account settings page Your Bitrise account is managed from your [Account settings page](http://app.bitrise.io/me/account). From this page, you can: - [Edit your profile](/bitrise-platform/accounts/editing-your-profile-settings), including username, email address, password, and avatar. - Set up [Apple ID connection](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id#adding-apple-id-authentication-data-on-bitrise). - [Enable two-factor authentication](/bitrise-platform/accounts/two-factor-authentication#enabling-two-factor-authentication). - Connect [LaunchDarkly feature flags](/release-management/configuring-connected-apps/integrating-launchdarkly-feature-flags) for Release Management. - Create and manage personal access tokens used to access the [Bitrise API](/bitrise-ci/api/api-overview). - [Register test devices](/bitrise-ci/testing/testing-ios-apps/registering-a-test-device). ### SAML SSO You can log in to Bitrise via SAML SSO. Bitrise supports multiple SAML identity providers. To log in via SAML SSO: - Your workspace must have SAML SSO enabled. - Make sure the email address belonging to your personal Bitrise account is also registered to your SAML identity provider. For detailed information on how to set it up, see: [Configuring SAML SSO on Bitrise](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise). --- ## Deleting your Bitrise account We’re always sad to see you go but if you wish to delete your Bitrise account, it’s quite simple. :::caution[Workspace ownership] If you are the only confirmed owner of a Workspace, you must transfer the ownership of the Workspace to another account, or delete it before deleting your account. ::: 1. 1. Log in to Bitrise and click the profile image in the upper right corner to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. On the bottom of the **Profile** page, click the **Delete account** button and follow the instructions. --- ## Editing your profile settings On the **Profile settings** page, you can: - Change your username and associated email address. - Change your password. - Update your personal and company information. ### Changing your Bitrise username, email, and password 1. Log in to Bitrise, and select **Bitrise CI** from the left navigation menu. 1. In the upper right corner, click the profile image to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. Find the **Account details** section, and click **Edit**. 1. Enter your current password when prompted, and click **Done**. 1. To change your username, type in the new username in the **Username** field. 1. To change your email, type in a new email address in the **Email** field. 1. To change your password, type in a new password in the **New password** field, and then type it again in the **Confirm new password** field. 1. When done, click **Confirm changes**. ### Adding an avatar to your account You can add your own personalized avatar to your Bitrise account. 1. Log in to Bitrise, and select **Bitrise CI** from the left navigation menu. 1. In the upper right corner, click the profile image to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. Scroll down to your avatar below the **Account details** section, and click **Edit**. 1. In the **Change avatar** dialog, drag and drop your new avatar, or select a file from your computer. 1. Click **Save changes**. ### Unselecting notification preferences By default Bitrise sends newsletters and platform updates to the email address you provide under your **Profile**. You can unselect this setting with 3 simple steps: 1. Click **Profile settings** under your avatar. 1. Click **Notification** on the left menu bar. You can see that Newsletters and Platform updates are both enabled by default. 1. If you wish to rather not get any or one of the two, notifications, untick the relevant checkbox/es. --- ## GitHub token scanning Bitrise is a partner of [GitHub's secret scanning program](https://docs.github.com/en/code-security/secret-scanning/secret-scanning-partnership-program/secret-scanning-partner-program): GitHub scans repositories for known secret formats to prevent fraudulent use of credentials that were committed accidentally. Bitrise uses this scanning to look for your [personal access tokens](/bitrise-platform/accounts/personal-access-tokens) and [Workspace API tokens](/bitrise-platform/workspaces/workspace-api-token) in your repositories. If a scan finds either type of token committed to your repository, Bitrise sends you both an email and an in-app notification to remove it for security reasons. Scanning is automatically turned on if your tokens are in the correct format. No configuration is required. :::important[Regenerating tokens] If you generated your tokens before November 2024, regenerate them to make sure they are in the correct format. We recommend regenerating your tokens if you encounter any other issues, too. - [Regenerating a personal access token](/bitrise-platform/accounts/personal-access-tokens#regenerating-a-personal-access-token). - [Regenerating a Workspace API token](/bitrise-platform/workspaces/workspace-api-token#regenerating-a-workspace-api-token). ::: --- ## Personal access tokens You can use a personal access token to authenticate to the Bitrise API. You can create a new personal access token at any time but once you created it, you can never view or copy its value again. ### Creating a personal access token To create a new personal access token: 1. Log in to Bitrise, and select **Bitrise CI** from the left navigation menu. 1. In the upper right corner, click the profile image to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. On the left, select the **Security** tab. 1. Scroll down to the **Personal access tokens** section, and click on **Create token**. 1. Fill out the **Name** field and select an expiration option for your token. 1. Click **Next**. 1. In the **Personal Access token** pop-up window, you can see your newly generated token. 1. Click **Copy and close** to store token in the clipboard so you can paste it somewhere safe, and to finalize. ### Regenerating a personal access token You can regenerate an existing personal access token at any time. However, you can't view the value of the previously generated token again, only the new value. 1. Log in to Bitrise, and select **Bitrise CI** from the left navigation menu. 1. In the upper right corner, click the profile image to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. Go to the **Security** tab. 1. Find your token in the **Personal access tokens** section. 1. Click **Edit**. 1. Click **Regenerate token**. 1. Copy the new token, and then click **Copy and close**. --- ## Resetting your password You can log into Bitrise in many ways: - with your Bitrise username and password - with your Gitlab/Github/Bitbucket account - with your Bitrise Workspace name if SAML SSO has been set up to and enforced on your Bitrise Workspace If you try to log in but you forgot your password: 1. Click **Forgot your password** on our [Login page](https://app.bitrise.io/users/sign_in). 1. Provide your **Email** or **Username** so that we know where to send password recovery link. 1. Check your inbox for the **Reset password instructions** sent by letsconnect. 1. Click **Reset Password** or copy the URL into your browser. 1. Add your new password and hit **Change Password**. 1. Once your password has been changed, click **Log in** to access our login page again. 1. Add your **Username** and new **Password** to log into your Bitrise Dashboard. If you failed to log in for an excessive amount of attempts, you will automatically get locked out. Check your inbox for our **Unlock Instructions** email! --- ## Configuring SAML SSO on Bitrise Workspace members can log in to a Bitrise workspace using their own SAML SSO provider’s system. With SAML SSO, workspaces will be able to apply the security guidelines of their SAML SSO provider when accessing their Bitrise workspace. SAML SSO can also be enforced on a workspace: enforcing makes SAML SSO the only way for logging in to the workspace. ### Verifying your domain You can add and verify your corporate domains from where you will manage Bitrise users. You can have multiple verified domains on Bitrise but you can only add one domain at a time. Multiple subdomains of the same domain count as different domains as Bitrise expects an exact match. Verifying your domain is a requirement for configuring SCIM and it makes it much more convenient for users to sign up and log in to Bitrise via SAML SSO. We recommend starting your SAML SSO setup with verifying your domain as the process can take some time. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Single sign-on**. 1. Select the **Domains** tab. 1. In the **Domain control** section, click **Add domain**. 1. Enter your domain name in the dialog box, and click **Next**. :::important[Handling subdomains] Bitrise expects an exact match for the domain names. If you use subdomains, you need to add the full name of the subdomain. For example, if you own mydomain.com and you want to use its subdomain external.mydomain.com, you should write it out the subdomain's name when setting up domain control on Bitrise. ::: 1. You will see a domain verification code. You need to add this code to as a DNS TXT record at your domain provider. 1. Click **Copy and close** to copy the verification code and close the dialog box. After you've added the DNS TXT record at your domain provider, we'll commence domain verification. This can take up to 72 hours. You will receive an email once it is completed. ### Setting up SAML SSO for a Bitrise workspace In this tutorial, we describe how workspace owners can set up their SAML SSO and invite workspace members to set up their own connections. Before connecting SAML SSO to your workspace, you need: - A SAML SSO provider (Identity Provider) that you can connect Bitrise to and the administrator to the SAML SSO provider is at hand. - An [owner or manager of the workspace](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). Workspace members with the role of contributor or viewer can't set up SAML SSO. To start configuring SAML SSO: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Select the **Single Sign-On** tab on the left. 1. Click **Configure SSO**. It opens the **Setup connection** screen. 1. Log in to your SAML SSO provider and add Bitrise as a SAML SSO application, using the values from the **Setup connection** screen in your Bitrise workspace settings: ![sso-setup.png](/img/_paligo/uuid-baadaff0-fbae-febb-cca3-077a707b1676.png) - Copy the **Assertion Consumer Service URL (ACS URL)** by clicking **Copy**. The provider sends the SAML response to the ACS URL. Some providers call it Reply URL, Callback URL, or Single Sign-On URL. - Copy the **Single Logout URL** by clicking **Copy**. The provider sends the SAML logout response to the Single Logout URL. You will receive configuration values from your SAML SSO provider. 1. Add your SAML SSO provider configuration values: - **SSO URL**: Bitrise sends the SAML request to the SSO URL. Some providers call it Login URL. - **SSO Logout URL (optional)**: Bitrise sends the SAML logout request to the SSO Logout URL. - **Application Identifier (optional)**: This is necessary if multiple workspaces use the same identity provider. This may be called Entity ID, Audience URI, or something similar. 1. Upload the SAML SSO provider certificate. You can either upload the file or paste the certificate manually. ![sso-certificate.png](/img/_paligo/uuid-e1e79927-bba9-65ca-01a5-24ef83efe442.png) 1. Click **Save changes**. If you’ve completed the steps, you and workspace members should get a verification email about SAML SSO connected to the respective workspace. ### Checking SAML SSO statuses on Bitrise Now that the Workspace owner has set up SAML SSO for the Workspace, all Workspace members (including the Workspace owner) can check their other Workspace member’s SAML SSO statuses on the **Collaboration** tab. There are two kinds of SAML SSO statuses on Bitrise, shown as an icon in the Members table. Hover over the icon to see its status as a tooltip: - **SAML is enabled:** Login via SAML SSO is enabled. - **SAML is disabled:** The Workspace member has not enabled the SAML SSO connection yet. To enable it, the Workspace member has to follow the instructions in the verification email from Bitrise. 1. Go to your Workspace’s profile page. 1. Select **Collaboration** from the left menu. 1. Go to the Members tab to check the Workspace member’s SAML status. ![saml_status.png](/img/_paligo/uuid-38cefb5d-2dc6-7a86-98cd-d1dac6484ded.png) ### Enforcing SAML SSO on a Workspace Enforcing SAML SSO on your Workspace provides an extra layer of security: you can enforce your own security guidelines to your Bitrise Workspace (for example, password format requirements, two-factor authentication). :::warning[Enforced SAML SSO] Enforcing SAML SSO in your Workspace makes SAML SSO the only way for logging in/signing up to the Workspace. ::: :::caution[One Workspace only] You cannot be a member in two Workspaces that enforced SAML SSO on Bitrise. ::: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Go to your Workspace’s **Single Sign On** tab. 1. Check the **Enforce SAML SSO** checkbox to enforce SAML SSO. ![enforce_saml.png](/img/_paligo/uuid-642c1745-3bb7-c296-bd5a-35a2368a3945.png) :::note[Unable to enforce SAML SSO] A Workspace owner cannot enforce SAML SSO on the Workspace if Workspace members have not enabled their SAML SSO connection yet or they enabled SAML SSO with another Workspace that enforces SAML SSO. ::: 1. Click **Save changes**. Now Workspace members can only log in via SAML SSO. ### Adding a new user to a workspace with enforced SAML SSO You can add new users to a workspace with enforced SAML SSO. There are three cases: - The workspace has a verified domain: [Verified domain](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise#verifying-your-domain). You can invite users with the same email domain as you would to any other workspace: [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). - The workspace doesn't have a verified domain and you want to invite a user who hasn't registered a Bitrise account yet: invite the user as you would to any other workspace. - The workspace doesn't have a verified domain and you want to invite a user with an existing Bitrise account: turn off [enforced SAML SSO](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise#enforcing-saml-sso-on-a-workspace), invite the user, and turn enforcement back on. | Domain verification status | New user | Existing user | | --- | --- | --- | | Verified domain | Simple invite | Simple invite | | Non-verified domain | Simple invite | Turn off SAML SSO enforcement Invite the user Turn on SAML SSO enforcement again | ### Disabling a Workspace's SAML SSO If you disable SAML SSO, Workspace members will be able to sign in with the regular sign-in procedure. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Go to the **Single Sign-On** tab. 1. If SAML SSO has been enforced on the Workspace before, toggle **Enforce** under **Enforce SAML SSO** off. 1. Click **Disable SSO**. A confirmation pop-up appears where you can confirm/cancel your action. Please note that by clicking the **Disable SSO** button, you will disable SAML SSO for all Workspace members. Once it’s done, Workspace members will be able to log in through their normal Bitrise credentials. ![disable_sso.png](/img/_paligo/uuid-ea11f723-edcb-2e88-0d83-c4c60f1cb794.png) You will receive an **SSO has been disabled** email from Bitrise (letsconnect@bitrise.io) which confirms the disabled SAML SSO for the Workspace. ### Disabling a Workspace member's SAML SSO If you are a Workspace owner, you can disable a Workspace member’s SAML SSO connection to the Workspace on Bitrise. There are two ways to do so: - Remove the user from the Workspace. - Remove the user from the SAML SSO provider which means the user would not be able to log in with SAML SSO any more. ### Updating SAML SSO configuration You can update a Workspace’s configured SAML SSO using the **Configure SAML SSO provider** button on the **Single Sign-On** page. This comes in handy if your SAML SSO provider’s certificate has expired and you wish to insert the new certificate on Bitrise. Another use case is, for example, if SAML SSO has been configured a while ago and now you wish to check the current configuration details. :::important[Accessing the Update SSO button] As with other SAML SSO configurations, only the Workspace owner can access and use the Update SSO button. ::: 1. As the owner of the Workspace, click your Workspace’s **Single Sign-On** tab. 1. Click the **Configure SAML SSO provider** button. Now you can access the configuration details of Workspace’s SAML SSO. ![configure_update_sso.png](/img/_paligo/uuid-2b97d7ef-4512-cf79-868f-bc66e728b509.png) 1. Make the changes and click **Save changes**. From now on any SAML SSO request will use the new configuration automatically. --- ## Configuring SCIM The System for Cross-domain Identity Management (SCIM) specification is designed to make managing user identities in cloud-based applications and services easier. On Bitrise, SCIM provisioning is supported for [Okta](https://www.okta.com/) and [Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/identity/). SCIM provisioning requires a verified domain, and SCIM credentials: a SCIM base URL and an authentication token. The process of configuring these on Bitrise is the same for both Okta and Entra ID. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Single sign-on**. 1. [Set up a verified domain](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise#verifying-your-domain). 1. Select the **SCIM** tab. 1. In the **SCIM credentials** section, click **Connect with IdP** to open the **Connect with IdP** dialog. 1. Save your SCIM credentials. In the dialog, you will see: - Your SCIM base URL. - Your SCIM authentication token. Copy and save both. You need them for SCIM provisioning. Once you've pasted them into your identity provider, select the checkbox confirming this, and click **Done**. For Okta, check out our [SCIM provisioning guide](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-okta-sso-for-bitrise#setting-up-scim-provisioning-in-okta). ### Managing workspace and product roles via SCIM By default, all SCIM-provisioned users receive the Viewer role and no product access. If your IdP supports the SCIM `roles` attribute, you can automate Workspace and product role assignment so that users are provisioned with the correct access from the start. #### Available workspace roles | SCIM value | Workspace role | Description | |---|---|---| | `workspace:workspace_viewer` | Viewer | Default role for new members. Can view Workspace resources but cannot create apps or projects. | | `workspace:workspace_contributor` | Contributor | Can create new apps and projects. Cannot modify Workspace settings or manage members. | | `workspace:workspace_manager` | Manager | Can modify Workspace settings, manage members, and manage integrations and infrastructure. | For a detailed breakdown of permissions, see [Roles and permissions in Workspaces](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces). #### Available product roles | SCIM value | Product role | Description | |---|---|---| | `rde:rde_admin` | RDE User | Can create and manage Remote Dev Environment sessions in the Workspace. | Project-level Bitrise CI and Release Management roles can't be assigned through SCIM. Set those up on the **Collaboration** page instead: [Roles and permissions in Workspaces](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces). #### How role assignment works Each role entry's `value` field uses the format `:`, where the family is either `workspace` or `rde`. Configure your IdP to include the `roles` attribute in SCIM requests using one of the following formats. **User creation and full update (POST and PUT):** Include `roles` as a top-level attribute in the request body: ```json { "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "userName": "user@example.com", "roles": [ { "value": "workspace:workspace_manager" }, { "value": "rde:rde_admin" } ] } ``` **Partial update (PATCH, roles in value object):** Some IdPs, such as Okta, send roles nested inside the `value` object without an explicit `path`: ```json { "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ { "op": "replace", "value": { "roles": [ { "value": "workspace:workspace_contributor" } ] } } ] } ``` **Partial update (PATCH, explicit path):** Other IdPs, such as Microsoft Entra ID, use an explicit `path` field. The `type` field is optional and ignored by Bitrise: ```json { "schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"], "Operations": [ { "op": "replace", "path": "roles", "value": [ { "value": "workspace:workspace_manager" } ] } ] } ``` Bitrise handles all three formats automatically. :::important If the `roles` attribute is present in a SCIM request, Bitrise treats it as the complete role assignment and replaces the user's current roles. This applies to every family, not just the ones you send: a request that lists only a `workspace:` role removes the user's RDE access, and a request that lists only `rde:rde_admin` reverts the user's workspace role to Viewer. Send every role the user should keep. If `roles` is absent from the request entirely, existing role assignments are left untouched. An empty `roles` array reverts the user to the default Viewer role and removes their product access. ::: --- ## Logging in via SAML SSO :::note[Adding new users to workspaces with enforced SAML SSO] This page is for users trying to log in via SAML SSO after getting an invite. For workspace admins looking to add users to workspaces that have SAML SSO enforced, check out [Adding a new user to a Workspace with enforced SAML SSO](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise#adding-a-new-user-to-a-workspace-with-enforced-saml-sso). ::: You can log in via SAML SSO if a workspace with [a working SAML SSO configuration](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise) added you as [a member](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). With a SAML SSO login, you don't need an email address and a password. The exact process depends on how SAML SSO is configured for the workspace and whether the workspace has a [verified domain](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-scim). ### Logging in via SAML for new users 1. Open the Bitrise [sign-up](https://app.bitrise.io/users/sign_up) page and click **Sign up with SSO**. 1. Enter your work email address and click **Continue with SSO**. 1. Follow the instructions: - If your workspace has a [verified domain](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-scim) matching your email's domain, you will be redirected to log in to the identity provider. After logging in, you will be redirected to Bitrise: provide a username and click **Finalize account**. You will receive an email with a confirmation link. - If your workspace doesn't have a verified domain or if it doesn't match your email's domain, you will be asked to check your inbox. An email is sent with a secure login link that contains the available workspaces that use SAML SSO. To finish signing in to the workspaces, click the links in the email. You will be redirected to Bitrise to enter your username and finalize the account. ### Logging in to SAML SSO for existing users If a workspace switches to using SAML SSO to log in, members might need to authorize SAML SSO separately, depending on the workspace configuration. 1. Open the [Bitrise login](https://app.bitrise.io/users/sign_in) page. 1. Click **Continue with SSO**. 1. Enter your email address. 1. Follow the instructions: - If your workspace has a [verified domain](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-scim) matching your email's domain, you will be redirected to the identity provider's site to log in. After successfully logging in, you will be redirected to Bitrise. - If your workspace doesn't have a verified domain or if it doesn't match your email's domain, you will need to authorize SAML SSO before logging in. When the workspace enabled SAML SSO, you received a confirmation email: find this email and click **Authorize SSO access**. Alternatively, if you are already logged in when SAML SSO is enabled, you will see the authorization screen on the website itself. ### Multiple workspaces with the same verified domain When a new user tries to log in via SSO the first time, Bitrise looks for a verified domain matching the user's email domain. If multiple workspaces share the same verified domain, Bitrise might not automatically be able to redirect a new user to the correct workspace. In this case, you will receive an email stating that we couldn't find an existing workspace associated with that address in our system. We recommend one of the following workarounds: - **Launch Bitrise directly from the identity provider's site**: For example, create a tile in Okta for Bitrise and use that to log in. In this way, the user will be redirected to the correct workspace. - **Add the user to the correct Workspace**: A workspace owner should add the user as a member to the workspace they need before attempting to log in: [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). - **Find and copy the login URL from the Workspace settings page**: Open the page, select **Single Sign-on** on the left, and go to the **SAML SSO** tab. Find the **Login URL to the Workspace** and click **Copy**. --- ## AD FS SSO This guide provides step-by-step instructions on setting up SAML SSO using [Microsoft Active Directory Federation Services](https://docs.microsoft.com/en-us/windows-server/identity/active-directory-federation-services) (AD FS). :::caution[SAML SSO restrictions] SAML SSO is only available on select plans. Contact our support to find out if SAML SSO is available on your Workspace's plan. Since the SAML SSO feature is tied to the above plans, if you decide to downgrade to a free plan, you will lose this feature. All Workspace members will receive an email about the downgrade, and you’ll have two weeks to re-upgrade if you wish to use SAML SSO in your Workspace again. ::: Before connecting SAML SSO to your Workspace: - Make sure the AD FS administrator is at hand during the SAML SSO configuration process. - - Be aware that only the Workspace owner can set up SAML SSO to a Bitrise Workspace. - Your account on Bitrise has a Workspace with one of our [paid plans](https://bitrise.io/pricing). In this tutorial we will be jumping back and forth between Bitrise and AD FS so it is recommended that both tools are available during this process. To configure SAML SSO with AD FS, you'll need to: 1. [Add the **Identity provider sign-on URL** from AD FS on Bitrise](#adding-the-identity-provider-sign-on-url). 1. [Export a certificate generated by AD FS and add it on Bitrise](#exporting-an-ad-fs-certificate). 1. [Add Bitrise as a relying party trust to AD FS](#adding-bitrise-as-a-relying-party-trust-to-ad-fs). 1. [Configure claim rules](#configuring-claim-rules). ### Adding the identity provider sign-on URL 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Go to the **Single Sign-on** tab. 1. Add the **Identity provider sign-on URL** from AD FS in the **SSO URL** field. For example, a valid value is `https://.com/adfs/ls`. ### Exporting an AD FS certificate 1. You have to add a certificate generated by AD FS to the **SAML SSO provider certificate** field of the **Single Sign-On** page on Bitrise. If you’ve already created a certificate on AD FS, you can export it in PEM format from the AD FS server. If you haven’t created one yet, follow the instructions: [Obtain and Configure TS and TD Certificates for AD FS](https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/configure-ts-td-certs-ad-fs#:\~:text=Open%20the%20AD%20FS%20Management,certificates%2C%20and%20then%20click%20OK.). 1. In **Server Manager**, click **Tools**, and select **AD FS Management**. 1. Select the **Certificates** folder on the left menu pane. 1. Click a certificate under **Token-signing**. This brings up the **Certificates** window. ![certtoken-1.jpg](/img/_paligo/uuid-cfe05e2a-2027-50fb-e4a8-56ef4164907f.jpg) 1. Click **Details** tab on the **Certificate** page. ![certificate-1.jpg](/img/_paligo/uuid-e960a587-dfa0-3b5d-aad8-6d03208a3ad6.jpg) 1. Hit **Next** on the **Certificate Export Wizard** window. ![certwizard.jpg](/img/_paligo/uuid-0ba8034b-4784-e042-02b9-32087bcde8d4.jpg) 1. Select the **Base-64 encoded X.509 (.CER)** the export file format. Click **Next**. ![baseencoded.jpg](/img/_paligo/uuid-9a300011-7818-826c-5874-c7ba6ade8176.jpg) 1. Give it a name in the **File name** field and hit **Save**. ![filenamesave.jpg](/img/_paligo/uuid-4510e204-8973-1a9a-0c2e-7ffc0c073aad.jpg) 1. Have a final look at your certificate settings. If you need to modify any of those, click the backward arrow next to **Certificate Export Wizard**. Otherwise, click **Finish**. Make sure you leave the AD FS window open as you will need it in a minute. ![completewizard.jpg](/img/_paligo/uuid-eaa066c4-99be-c8a5-9990-fe4a08a4154c.jpg) 1. Open the exported certificate by a text editor and copy/paste its content to the **SAML SSO provider certificate** field or upload the file itself from your local computer. 1. Save the settings by clicking **Configure SSO** on Bitrise. ![saml_sso_setup.png](/img/_paligo/uuid-26ad84be-65c7-1916-f079-6b553b4c436d.png) Let’s continue the SAML SSO configuration on AD FS by adding Bitrise. ### Adding Bitrise as a relying party trust to AD FS Once you are finished with exporting the certificate, you can continue with adding Bitrise as a [relying party trust to AD FS](https://docs.microsoft.com/en-us/windows-server/identity/ad-fs/operations/create-a-relying-party-trust). The Add Relying Party Trust Wizard guides you through the steps. 1. On AD FS, click **Relying Party Trust** on the left menu bar, then click **Relying Party Trust**. 1. Select **Add Relying Party Trust** under **Actions**. ![addreplyingpartytrust.jpg](/img/_paligo/uuid-2e8a2cfc-6fe9-cf2b-9b4a-b4ec2f051568.jpg) 1. On the **Welcome** page, select the **Claims aware** option and hit **Start**. ![claimsaware.jpg](/img/_paligo/uuid-d5eac9a8-1c74-efd6-459a-aaa24af4877a.jpg) 1. On the **Select Data Source** page, click the **Enter data about the relying party manually** option on the bottom of the page. Click **Next**. ![selectdatasource.jpg](/img/_paligo/uuid-7e451b81-22e3-0f16-af91-380ad8026de1.jpg) 1. On the **Specify Display Name** page, add a **Display name,** for example `MyCorp`. Click **Next**. ![specifydisplayname.jpg](/img/_paligo/uuid-a8509ed5-9cc9-8851-c8df-9d298c5ae3bc.jpg) 1. Specify a token encryption certificate on the **Configure Certificate** page is optional. Click **Next**. ![optionalconfigure.jpg](/img/_paligo/uuid-1042aa27-f21e-16e5-4065-4088112ae116.jpg) 1. On the **Configure UR**L page, select **Enable support for the SAML 2.0 WebSSO protocol** and copy paste the **Assertion Consumer Service URL (ACS URL)** from Bitrise to the **Relying party SAML 2. 0 SSO service URL** field on AD FS. Click **Next**. ![configureurl-1.jpg](/img/_paligo/uuid-a40d7228-e976-458e-0508-99ded152069c.jpg) 1. On the **Configure Identifiers** page, add `Bitrise` in the **Relying party trust identifier** field. Click **Add**, then hit **Next**. ![replyingidentifiers2.jpg](/img/_paligo/uuid-c920feb2-3a96-88d7-710a-27d3d4fcba1c.jpg) 1. Do not modify the default access control policy on the **Choose Access Control Policy** page so that everyone can access this SAML SSO connection. Click **Next**. ![permiteveryone.jpg](/img/_paligo/uuid-d6600b5b-3ad8-aee2-a28b-62f4ca2b1394.jpg) 1. On the **Ready to Add Trust** page, review the settings and click **Next**. ![readytoaddtrust.jpg](/img/_paligo/uuid-4033d0af-df38-8e77-9963-4812d259f9ad.jpg) 1. On the **Finish** page, tick the checkbox to edit claims issuance policy for Bitrise. Click **Close**. ![finish.jpg](/img/_paligo/uuid-974f5427-db6a-201d-a112-9bb8fee4ae7f.jpg) 1. On AD FS, click **Relying Party Trust** on the left menu bar, then click **Relying Party Trust**. 1. Select **Add Relying Party Trust** under **Actions**. ![addreplyingpartytrust.jpg](/img/_paligo/uuid-2e8a2cfc-6fe9-cf2b-9b4a-b4ec2f051568.jpg) 1. On the **Welcome** page, select the **Claims aware** option and hit **Start**. ![claimsaware.jpg](/img/_paligo/uuid-d5eac9a8-1c74-efd6-459a-aaa24af4877a.jpg) 1. On the **Select Data Source** page, click the **Enter data about the relying party manually** option on the bottom of the page. Click **Next**. ![selectdatasource.jpg](/img/_paligo/uuid-7e451b81-22e3-0f16-af91-380ad8026de1.jpg) 1. On the **Specify Display Name** page, add a **Display name,** for example `MyCorp`. Click **Next**. ![specifydisplayname.jpg](/img/_paligo/uuid-a8509ed5-9cc9-8851-c8df-9d298c5ae3bc.jpg) 1. Specify a token encryption certificate on the **Configure Certificate** page is optional. Click **Next**. ![optionalconfigure.jpg](/img/_paligo/uuid-1042aa27-f21e-16e5-4065-4088112ae116.jpg) 1. On the **Configure UR**L page, select **Enable support for the SAML 2.0 WebSSO protocol** and copy paste the **Assertion Consumer Service URL (ACS URL)** from Bitrise to the **Relying party SAML 2. 0 SSO service URL** field on AD FS. Click **Next**. ![configureurl-1.jpg](/img/_paligo/uuid-a40d7228-e976-458e-0508-99ded152069c.jpg) 1. On the **Configure Identifiers** page, add `Bitrise` in the **Relying party trust identifier** field. Click **Add**, then hit **Next**. ![replyingidentifiers2.jpg](/img/_paligo/uuid-c920feb2-3a96-88d7-710a-27d3d4fcba1c.jpg) 1. Do not modify the default access control policy on the **Choose Access Control Policy** page so that everyone can access this SAML SSO connection. Click **Next**. ![permiteveryone.jpg](/img/_paligo/uuid-d6600b5b-3ad8-aee2-a28b-62f4ca2b1394.jpg) 1. On the **Ready to Add Trust** page, review the settings and click **Next**. ![readytoaddtrust.jpg](/img/_paligo/uuid-4033d0af-df38-8e77-9963-4812d259f9ad.jpg) 1. On the **Finish** page, tick the checkbox to edit claims issuance policy for Bitrise. Click **Close**. ![finish.jpg](/img/_paligo/uuid-974f5427-db6a-201d-a112-9bb8fee4ae7f.jpg) ### Configuring claim rules 1. On the **Edit Claim** **Issuance Policy** page, click the **Add Rule** button and hit **OK**. ![editclaims.jpg](/img/_paligo/uuid-0a57f576-6cbd-5055-e09e-078920e410ce.jpg) 1. Create a **Send LDAP Attributes as Claims** claim rule and click **Next**. 1. On the **Configure Claim Rule** page: - Add a rule name, for example Send E-mail, in the **Claim rule name** field. - Select an **Attribute Store** which is most likely the Active Directory. - In the **Mapping of LDAP attributes to outgoing claim types** field select E-mail Addresses. 1. Click **Finish**. ![configureclaimrule.jpg](/img/_paligo/uuid-73afe848-4767-6771-43fb-4675ecc1a189.jpg) 1. Add another new rule that turns an E-mail to a formatter NameID. To do so, click **Add rule** in the **Edit Claim** **Issuance Policy** page again. 1. On the **Select Rule Template**, select **Transform an Incoming Claim** option in the **Claim rule template** dropdown. Click **Next**. ![chooseruletype.jpg](/img/_paligo/uuid-0ef22e95-4303-25ce-b8e9-69884bbe7cf7.jpg) 1. Give a name to the new rule, for example, `Transform E-mail`. 1. Select **E-Mail Address** as the **Incoming Claim Type**. 1. Select **NameId** as the **Outgoing claim type.** 1. Choose **Email** as the **Outgoing name ID format**. 1. Hit **OK** to finish the process. ![newrule.jpg](/img/_paligo/uuid-ce7f8183-941b-0b73-92c2-185e235442ee.jpg) --- ## Auth0 SSO This guide provides instructions on setting up SAML SSO using [Auth0](https://auth0.com). :::caution[SAML SSO restrictions] SAML SSO is only available on select plans. Contact our support to find out if SAML SSO is available on your Workspace's plan. Since the SAML SSO feature is tied to the above plans, if you decide to downgrade to a free plan, you will lose this feature. All Workspace members will receive an email about the downgrade, and you’ll have two weeks to re-upgrade if you wish to use SAML SSO in your Workspace again. ::: Before connecting SAML SSO to your Workspace: - An Auth0 administrator who is logged into Auth0 is at hand. - - Be aware that only the Workspace owner can set up SAML SSO to a Bitrise Workspace. - Your account on Bitrise has a Workspace with one of our [paid plans](https://bitrise.io/pricing). You will need to: 1. [Create Bitrise as a web application on Auth0](#creating-bitrise-as-a-web-application-on-auth0). 1. [Retrieve SAML SSO information from Auth0](#retrieving-saml-sso-information-from-auth0). 1. [Setting up a mapping rule for your Bitrise app's Client ID](#setting-up-a-mapping-rule-for-your-bitrise-apps-client-id). ### Creating Bitrise as a web application on Auth0 1. Log into [Auth0](https://auth0.com) as an admin. 1. Click **Applications** on the left menu bar then click the **+ Create Application** button on the right hand side of the **Applications** page. ![authzero_createapp1.png](/img/_paligo/uuid-47aacb1a-a7a9-f93e-8130-83ad51654298.png) 1. On the **Create application** window, type Bitrise in the **Name** field. In the **Choose application type** select **Regular Web Applications**, and click the **Create** button. ![authzero_addappname2.png](/img/_paligo/uuid-fc4a47cb-98f9-e217-042d-73780f712eb2.png) 1. You are landing on your newly created Bitrise app’s **Quick Start** page. Click the **Addons** tab. Toggle the **SAML2 WEB APP**’s switch to the right. This will take to to the **Addon: SAML2 WEB APP** page automatically. ![authzero_addon4.png](/img/_paligo/uuid-bf544047-689a-3954-029d-58b65a35c540.png) 1. Copy the **Assertion Consumer Service URL (ACS URL)** from Bitrise and paste it into the **Application Callback URL** field on the **Settings** tab of the **Addon: SAML2 WEB APP** page. Scroll down to the bottom of the **Addon: SAML2 WEB APP** page and hit **SAVE**. ![authzero_settingsapplicationurl6.png](/img/_paligo/uuid-193b49ae-3ccd-9f68-5288-55ed12c9edb1.png) 1. Go back to the **Addons** page where you can find the switch turned on. ![authzero_samlappenabled8.png](/img/_paligo/uuid-c79c0bb4-943a-7604-d40b-f8478be408bd.png) ### Retrieving SAML SSO information from Auth0 Once you have enabled Bitrise as a web application on Auth0, it’s time to grab the certificate and the Identity provider’s unique login URL to finish up the SAML configuration on Bitrise. 1. On Auth0, go to **Application**, then select the **Addons** tab to find your enabled Bitrise app. 1. Click the **SAML2 WEB APP** web app and select the **Usage** tab. Click on the **Download Auth0 certificate** link next to the **Identity Provider Certificate** label. Open the downloaded certificate file and copy its content into the **SAML SSO provider certificate** field of Bitrise or upload the file itself from your local computer. Go back to Auth0 and copy paste the **Identity Provider Login URL** into Bitrise’s **SSO URL** field. ![saml_sso_setup.png](/img/_paligo/uuid-26ad84be-65c7-1916-f079-6b553b4c436d.png) ![authzero_downloadcertificateusage9.png](/img/_paligo/uuid-e6cb3a32-c73c-f0cb-e7fe-9eab8e908679.png) 1. Click **Configure SSO** button on Bitrise. 1. Now you can close the dialog on Auth0. ### Setting up a mapping rule for your Bitrise app’s Client ID Bitrise authenticates SAML SSO users via email address so before you’d test SAML SSO, make sure you create a new mapping rule on Auth0. This way you map Auth0 Client ID to email for successful SAML authentication on Bitrise. 1. On Auth0, click the **Auth Pipeline** on the left menu bar. Click **Rules**. 1. Click **+ Create** to set up a new mapping rule. 1. On the **Pick a rules template** page, click **<> Empty rule**. 1. Add the following codeblock to the **Script** box: You will need your new Bitrise app’s Client ID which you can get on the **Applications**’ page. ```javascript function mapSamlAttributes(user, context, callback) { if (context.clientID === '{your app's clientID'}') context.samlConfiguration.mappings = { "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "email" }; } callback(null, user, context); } ``` 1. Click **Save changes**. --- ## Azure AD SSO :::caution[SAML SSO restrictions] SAML SSO is only available on select plans. Contact our support to find out if SAML SSO is available on your Workspace's plan. Since the SAML SSO feature is tied to the above plans, if you decide to downgrade to a free plan, you will lose this feature. All Workspace members will receive an email about the downgrade, and you’ll have two weeks to re-upgrade if you wish to use SAML SSO in your Workspace again. ::: Before connecting SAML SSO to your Workspace: - Make sure an Entra ID administrator who is logged into Entra ID is at hand. - - Be aware that only the Workspace owner can set up SAML SSO to a Bitrise Workspace. - Your account on Bitrise has a Workspace with one of our [paid plans](https://bitrise.io/pricing). You will need to: 1. [Add Bitrise to Entra ID as a new application](#adding-bitrise-to-entra-id-as-a-new-application). 1. [Add users and groups to the Bitrise app on Entra ID](#adding-users-groups-to-the-app-on-entra-id). 1. [Set up SAML SSO between Bitrise and Entra ID](#setting-up-saml-sso-between-bitrise-and-entra-id). ### Adding Bitrise to Entra ID as a new application 1. Log into [Microsoft Azure](https://azure.microsoft.com/en-us/) as an admin. 1. Click the **Azure Active Directory** icon on the **Azure services** page. ![azureactivedirstep2-1.jpg](/img/_paligo/uuid-bf8ba810-c8e2-5323-8d6b-30b9a030b59d.jpg) 1. Click **Enterprise applications** under **Manage**. ![enterpriseapps-1.jpg](/img/_paligo/uuid-39f030dd-13a5-7302-6200-44aa39114f17.jpg) 1. Click **New Application** to add Bitrise as a new app to your account. ![newapplication-jpg.jpg](/img/_paligo/uuid-fd697193-d536-bade-12f6-341e9ecb2df9.jpg) 1. Type `Bitrise` in the **What’s the name of your app?** field. The **Integrate any other application you don’t find in the gallery** button should be automatically selected. Hit **Create**. ![createyourownapp-1.jpg](/img/_paligo/uuid-4822cd7c-0379-35e2-9ab3-d483dc8c6355.jpg) You will find your newly created app listed on the **All Applications** page. 1. Click the **Bitrise** app to go to its **Overview** page. 1. Continue with configuring Bitrise as a SAML app. ### Adding users/ groups to the app on Entra ID Before setting up SAML to the app, you have to add all the users/groups to the app in Entra ID who will use SAML SSO to log into the Bitrise Workspace. In other words, every Bitrise Workspace member must be added as user in Entra ID. 1. Select **Users and groups** from the left menu. 1. Click **+ Add user/group**. ![azureuser1-1.jpg](/img/_paligo/uuid-f90189a9-c8f8-0720-69f3-b02983eb74f3.jpg) 1. On the Users page of **Add Assignment**, select users from the list and click **Select**. Once it’s done, you can select a role for users under the **Select a role** dropdown. ![azureuser2-1.jpg](/img/_paligo/uuid-ea5d2cad-6d99-e1e7-e389-6cb1c2170256.jpg) 1. On the **Add Assignment** page, click **Assign** to finish adding users. ![azureuser3b-1.jpg](/img/_paligo/uuid-ee6c9c9d-82a3-5470-9e0d-f5dd4f971414.jpg) ### Setting up SAML SSO between Bitrise and Entra ID 1. Click **Single sign-on** on the left menu. Select **SAML**. ![singlesignonazuread.png](/img/_paligo/uuid-9a20bdb0-2c68-3ce5-1f41-ac710e25b7be.png) 1. You will land on the **Set up Single Sign-On with SAML** page. ![sso2-1.jpg](/img/_paligo/uuid-6b74d41d-4d91-adb5-0d73-17380c293ab9.jpg) 1. Click the pencil symbol at **Basic SAML Configuration** to edit two fields. ![sso2a-1.jpg](/img/_paligo/uuid-954473da-632b-0628-2a76-9ff4471fcc9d.jpg) 1. Add `Bitrise` as the **Identifier (Entity ID)**. Leave this window open! We will come back to it with some information from Bitrise in a second. :::important[Multiple workspaces with the same Entra instance] If more than one Bitrise workspace uses the same EntraID instance, each workspace needs to be configured with its own distinct Entity ID. For each workspace, use its own Entity ID at any subsequent step in the process that requires it. For example, if you have an Alpha workspace and a Beta workspace, you can set **alpha** and **beta** as the Entity IDs. ::: ![sso3-2.jpg](/img/_paligo/uuid-39c02a1a-b3f2-3922-a9d1-fac312c98f92.jpg) 1. Head back to your workspace on Bitrise: open the **Workspace settings** page and go to **Single Sign-On** 1. If you have more than one workspace using the same Entra instance, add its own Entity ID in the **Application identifier** field. 1. Click the **Copy** button to copy the **Assertion Consumer Service URL (ACS URL)** from Bitrise. 1. Let’s head back to the **Basic SAML Configuration** window of Entra ID. 1. Paste the **Assertion Consumer Service URL** from Bitrise to the **Reply URL field on the Basic SAML Configuration** page of Entra ID. 1. Click **Save** and close the **Basic SAML Configuration** window. ![616541a82bf14.jpg](/img/_paligo/uuid-681bee8c-6be9-b47f-06fa-72a587e7add7.jpg) 1. On the **Single sign-on** page of Entra ID, scroll down to the **Set up Bitrise** section. 1. Copy the **Login URL** and paste it to the **SSO URL** field on Bitrise. 1. On the **Single sign-on** page of Entra ID, scroll up a bit to the **SAML Signing Certificate** section. 1. Click **Download** next to **Certificate (Base64)** to download the certificate to your local computer. ![singlesignonsummary.jpg](/img/_paligo/uuid-da7593a8-e6df-1d97-e903-d375dc504b05.jpg) 1. Open the certificate file and copy/paste its content into the **SAML SSO provider certificate** field of Bitrise or you can upload the file itself from your local computer too. (If manually adding the content, you will need the full content (including `----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` as well). 1. Open the **Workspace settings** page on Bitrise and go to **Single Sign-On**. 1. Click **Configure SSO**. You have successfully set up Bitrise as a SAML SSO app on Entra ID. --- ## Entra ID SCIM Bitrise supports automatic user and group provisioning via [SCIM 2.0](https://scim.cloud/) with Microsoft Entra ID. Once configured, Entra ID becomes the authoritative source for workspace membership: users and group assignments are pushed to Bitrise automatically, and removing a user in Entra deactivates their access on Bitrise. ### SCIM requirements - SCIM provisioning requires an **Enterprise plan**. - You must have [SAML SSO configured](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-azure-ad-sso-for-bitrise) between Bitrise and Entra ID before enabling SCIM. - You must have a [verified domain](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise#verifying-your-domain). Domain verification can take up to 72 hours. SCIM credentials cannot be generated until at least one domain is verified. - You will need both the [Bitrise workspace owner](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces) and an Entra ID administrator available during setup. ### Setting up SCIM The setup consists of three steps: 1. [Generating SCIM credentials on Bitrise.](#generating-scim-credentials-on-bitrise) 1. [Configuring SCIM provisioning in Entra ID.](#configuring-scim-provisioning-in-entra-id) 1. [Verifying the connection.](#verifying-the-connection) #### Generating SCIM credentials on Bitrise 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Select **Single sign-on** from the left menu. 1. Select the **SCIM** tab. 1. Click **Connect with IdP**. 1. Copy and save both values shown in the dialog: - **SCIM base URL** - **SCIM authentication token** The token is not displayed again after you close the dialog. If you lose it, you can regenerate it, but doing so immediately invalidates the previous token. #### Configuring SCIM provisioning in Entra ID Bitrise is not a gallery app in Entra ID. Use Microsoft's [tutorial for configuring SCIM with non-gallery applications](https://learn.microsoft.com/en-us/entra/identity/app-provisioning/use-scim-to-provision-users-and-groups) and apply the following Bitrise-specific values: - **Tenant URL:** [your SCIM base URL](#generating-scim-credentials-on-bitrise). - **Secret token:** [your SCIM authentication token](#generating-scim-credentials-on-bitrise). - **Unique identifier field:** `userName` (mapped to the user's email address). When configuring **Provisioning Mode**, select **Automatic**. Use **Sync only assigned users and groups** to control which users and groups are pushed to Bitrise. :::important[Enable Push Groups] Workspace membership on Bitrise is managed through groups. You must enable group provisioning (Push Groups) so that Entra ID can manage group membership in Bitrise. Without it, users will be provisioned but not added to any group. ::: #### Verifying the connection Click **Test Connection** in the Entra ID provisioning configuration. This queries the Bitrise `/ServiceProviderConfig` endpoint and confirms that the credentials are valid. A successful test means Entra ID can reach Bitrise and authenticate correctly. ### Attribute mapping Bitrise implements the SCIM 2.0 Core User Schema and Core Group Schema (RFC 7643/7644). Entra ID's default attribute mapping works without custom transforms. Supported user attributes: - `userName`: unique identifier for the user; Entra ID maps this to the user's User Principal Name (UPN), which typically matches their email address - `emails`: the user's email address(es) - `name.givenName`: first name - `name.familyName`: last name - `active`: whether the user is active; set to `false` to deprovision - `externalId`: the user's stable, opaque ID assigned by Entra ID; remains constant even if the user's UPN changes Supported group attributes: - `displayName`: the group's name in Entra ID - `members`: the list of users in the group For workspace role assignment via the `roles` attribute, see [Managing workspace and product roles via SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-scim#managing-workspace-and-product-roles-via-scim). ### Group behavior **Name matching:** When Entra ID pushes a group, Bitrise links it to an existing group with the same name, or creates a new one. Matching is case-sensitive and exact. `ios_dev` and `iOS Dev` are treated as different groups. Make sure group names in Entra ID match your existing Bitrise group names exactly before enabling sync. **Entra ID becomes authoritative for membership:** Once Entra ID is syncing a group, it controls that group's membership. Any members added manually in Bitrise who are not in the corresponding Entra ID group will be removed on the next sync. **Protected groups:** Global Access groups and SAML default groups cannot be deleted via SCIM. Keep these groups out of Entra ID's sync scope to avoid unintended membership changes. ### User provisioning behavior **No email activation step:** Users provisioned via SCIM on a verified domain are created in a confirmed, active state immediately. They do not receive an email activation link from Bitrise. On first login they are redirected directly to the Entra ID SSO flow. **Default workspace role:** All SCIM-provisioned users receive the Workspace Viewer role by default, which does not include Bitrise CI product access. To assign a different role at provisioning time, configure the `roles` attribute in Entra ID. See [Managing workspace and product roles via SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-scim#managing-workspace-and-product-roles-via-scim). ### Deprovisioning behavior When you remove a user's assignment in Entra ID, or Entra ID sends a `PATCH active:false` or `DELETE` request: - The user is removed from the workspace and from all their groups within it simultaneously. - Their personal access tokens remain active but lose access to all resources in the workspace. - Their workflows and secrets are preserved and not reassigned automatically. - The seat is freed immediately. **Re-provisioning a deprovisioned user:** A deprovisioned user's account is not deleted; they are removed from the workspace. Re-provisioning them via SCIM with the same email is supported, once they are assigned again in Entra ID, it can manage their group membership via SCIM as normal. ### Migrating existing workspace members SCIM is push-based. Bitrise only acts on requests Entra ID sends. Existing workspace members who are not assigned in Entra ID are not touched and remain in the workspace. To migrate an existing workspace with members and groups: 1. Verify all relevant email domains before enabling SCIM. 1. Align Entra ID group names to match your existing Bitrise group names exactly. 1. Enable SCIM with **Sync only assigned users and groups** in Entra ID. 1. Assign a small pilot group first to validate end-to-end, then expand incrementally. There is no dry-run or preview mode. The incremental pilot approach is the practical equivalent. ### Users on unverified domains Users whose email is on a domain that has not been verified in Bitrise cannot be managed via SCIM. Any attempt to provision or modify them will be rejected. Exclude those users from Entra ID's assignment scope until their domain is verified. To verify additional domains, go to Workspace Settings and add each domain under **Domain verification**. Each domain must be verified separately. --- ## Google SSO This guide provides step-by-step instructions on setting up Bitrise as a SAML application on Google Workspace. :::caution[SAML SSO restrictions] SAML SSO is only available on select plans. Contact our support to find out if SAML SSO is available on your Workspace's plan. Since the SAML SSO feature is tied to the above plans, if you decide to downgrade to a free plan, you will lose this feature. All Workspace members will receive an email about the downgrade, and you’ll have two weeks to re-upgrade if you wish to use SAML SSO in your Workspace again. ::: Before connecting SAML SSO to your Workspace: - Make sure you have a Google administrator account where you can add Bitrise as a SAML app. The Google Workspace administrator can help setting up SAML SSO on Google Workspace. - - Be aware that only the Workspace owner can set up SAML SSO to a Bitrise Workspace. - Your account on Bitrise has a Workspace with one of our [paid plans](https://bitrise.io/pricing). You'll need to: 1. [Get configuration information from Google Workspace and Bitrise.](#getting-configuration-information-from-google-workspace-and-bitrise) 1. [Enable the Bitrise app for a group or an organizational unit.](#enabling-bitrise-app-for-a-group-or-an-organizational-unit) ### Getting configuration information from Google Workspace and Bitrise 1. Sign into your Google Admin Console. 1. Select **Apps** on the **Admin Console** page. ![googleadmin-apps.jpg](/img/_paligo/uuid-d00d79a9-94d7-7bf0-fa17-b6e3adab0619.jpg) 1. On the Apps page, click **SAML apps**. ![appsamlapp.jpg](/img/_paligo/uuid-6cf46631-6ee5-1108-8957-9da55ebd564b.jpg) 1. On the **Web and mobile apps** page, click the **Add apps** button, and select the **Add custom SAML app** option from the dropdown. ![addappsaml.jpg](/img/_paligo/uuid-bcfdf2cb-0157-100c-44ed-25e040d82e6b.jpg) 1. On the App details page add `Bitrise` as your app name. Please note it must be `Bitrise` as no other format is accepted. Click **Continue**. ![addappname.jpg](/img/_paligo/uuid-1a730b40-ecbe-d3dd-58a4-c46a0854f63a.jpg) 1. On the **Getting Identity Provider details** page: - Copy the **SSO URL** and paste it on the **SSO URL** field on Bitrise. - Copy the whole content of the **Certificate** field and paste it in the **SAML SSO provider certificate** field of Bitrise. You can upload the **Certificate** from your local computer too. ![identityproviderdetails.jpg](/img/_paligo/uuid-21e11866-5b32-ba61-b232-0336d27e75e9.jpg) 1. While you are in Bitrise, click the **Copy** button to copy the **Assertion Consumer Service URL (ACS URL)**. We will need it on Google Workspace in a second. Let’s NOT click the **Configure SSO** button just now! 1. Let’s head back to the **Getting Identity Provider details** page of Google Workspace. Click **Continue**. 1. On the **Service provider details** page: - Paste the **Assertion Consumer Service URL (ACS URL)** of Bitrise in the **ACS URL** field on Google Workspace. (Remember, we got the link at Step 7.) - Type `Bitrise` in the **Entity ID** field. Please note it must be `Bitrise` as no other format is accepted. - Tick the **Signed response** checkbox under **START URL (optional)**. - Click **CONTINUE**. ![serviceproviderdetails.jpg](/img/_paligo/uuid-dca4e3b0-8c11-d444-23c9-b5ae0f21990d.jpg) 1. Click the **Configure SSO** button on Bitrise. 1. On Google Workspace’s **Attribute mapping** page, click **Finish** - you do not have to configure anything here. ### Enabling Bitrise app for a group or an organizational unit All there is left to do on G Suite is to enable the newly created Bitrise app for a group or organization of your choice. 1. Go to the **Web and mobile apps** page on G Suite and select **Bitrise** from the **Apps** list. 1. Click **User access** to get to the **Service status** page. 1. Select **ON for everyone** and hit **Save**. ![useraccess.jpg](/img/_paligo/uuid-ed1aa9a4-7926-3cfe-bf98-ac0f98a44237.jpg) --- ## Idaptive SAML SSO This guide provides step-by-step instructions on setting up Bitrise as a SAML application on [Idaptive](https://docs.cyberark.com/remote-access-standard/latest/en/content/admin/settings-idaptive.htm). :::caution[SAML SSO restrictions] SAML SSO is only available on select plans. Contact our support to find out if SAML SSO is available on your Workspace's plan. Since the SAML SSO feature is tied to the above plans, if you decide to downgrade to a free plan, you will lose this feature. All Workspace members will receive an email about the downgrade, and you’ll have two weeks to re-upgrade if you wish to use SAML SSO in your Workspace again. ::: Before connecting SAML SSO to your Workspace: - - Be aware that only the Workspace owner can set up SAML SSO to a Bitrise Workspace. - Your account on Bitrise has a Workspace with one of our [paid plans](https://bitrise.io/pricing). - You must be logged into your Admin Portal on [Idaptive](https://docs.cyberark.com/remote-access-standard/latest/en/content/admin/settings-idaptive.htm) to set up Bitrise as a SAML SSO app and establish the connection between Bitrise and Idaptive. If you are using the **User Portal**, **Switch to** **Admin Portal** by clicking your avatar on Idaptive. ![Setting_up_Idaptive_SAML_SSO_for_Bitrise.jpg](/img/_paligo/uuid-27ceb4dd-22a3-a162-b569-73261ba2fef7.jpg) 1. Log into Idaptive as an Admin. 1. Go to **Apps,** then to **Web Apps**. Click the **Add Web Apps** button on the right. ![Setting_up_Idaptive_SAML_SSO_for_Bitrise.png](/img/_paligo/uuid-9d5b8607-e8f3-2fa7-aa78-8891c184533e.png) 1. On the **Custom** tab and select **SAML**, and click **Add**. On the **Add Web App** popup hit **Yes**. **Close** the window. You will be automatically directed to the **Settings** page. ![Setting_up_Idaptive_SAML_SSO_for_Bitrise.png](/img/_paligo/uuid-7389987f-3a26-24d3-6298-787eb51002e0.png) 1. Add Bitrise to the **Name** and **Application ID** fields on the **Settings** page and click **Save**. ![Setting_up_Idaptive_SAML_SSO_for_Bitrise.jpg](/img/_paligo/uuid-81638e95-5198-7da7-ecb8-f2d9835f64be.jpg) ![Setting_up_Idaptive_SAML_SSO_for_Bitrise.jpg](/img/_paligo/uuid-175bfd17-e0a5-d198-a2f9-36dc24735c28.jpg) 1. Click **Trust** on the left menu bar and select the **Manual configuration** under **Identity Provider Configuration**. 1. Click the **Signing Certificate** dropdown and download the certificate. Open it with a text editor so that you can copy the full content of the certificate. You can also upload the file. ![Setting_up_Idaptive_SAML_SSO_for_Bitrise.jpg](/img/_paligo/uuid-904a51d4-081b-8a05-0b56-3522007e3a46.jpg) 1. Insert the content or upload the file itself in the **SAML SSO provider certificate** text box on the **Enable Single Sign-On** page of Bitrise. 1. Copy the **Single Sign On URL** from the **Trust** page of Idaptive. Insert it on the **SSO URL** field on the **Single sign-on** page of Bitrise. 1. While on the **Single Sign-On page** of Bitrise, copy the **Assertion Consumer Service URL (ACS URL)** URL and click **Configure SSO**. 1. Now let’s head back to Idaptive! Under **Service Provider Configuration** click **Manual Configuration**. Type **Bitrise** in the **SP Entity ID / Issuer / Audience** and paste the **Assertion Consumer Service URL (ACS URL)** from Bitrise to the **Assertion Consumer Service (ACS) URL** on Idaptive. ![Setting_up_Idaptive_SAML_SSO_for_Bitrise.jpg](/img/_paligo/uuid-97ca8e78-eae6-ff2b-f6b5-523718161a8e.jpg) 1. Scroll down to **NameID Format** and select **emailAddress**. Click **Save**. ![Setting_up_Idaptive_SAML_SSO_for_Bitrise.jpg](/img/_paligo/uuid-5b529235-9f88-8b16-64c4-9438f3cc9498.jpg) 1. Go to **Permissions** and click the **Add** button. In the **Select User, Group, or Role** popup, type the user name you want to add to the SAML app. Select it and hit **Add**. Save your changes. This will change the status of your Bitrise SAML app to **Deployed**. ![Setting_up_Idaptive_SAML_SSO_for_Bitrise.png](/img/_paligo/uuid-fb6f7300-1ac4-523d-0a04-b6c2850e5621.png) You are now ready to use Idaptive as your SAML SSO provider on Bitrise. --- ## Okta SSO This guide provides step-by-step instructions on setting up Bitrise as a SAML application on [Okta](https://www.okta.com/). :::caution[SAML SSO restrictions] SAML SSO is only available on select plans. Contact our support to find out if SAML SSO is available on your Workspace's plan. Since the SAML SSO feature is tied to the above plans, if you decide to downgrade to a free plan, you will lose this feature. All Workspace members will receive an email about the downgrade, and you’ll have two weeks to re-upgrade if you wish to use SAML SSO in your Workspace again. ::: Before connecting SAML SSO to your Workspace: - Make sure you have an Okta administrator who is logged into Okta at hand. - - Be aware that only the Workspace owner can set up SAML SSO to a Bitrise Workspace. - Your account on Bitrise has a Workspace with one of our [paid plans](https://bitrise.io/pricing). 1. [Add Bitrise to Okta](#adding-bitrise-to-okta). 1. [Configure Bitrise as a SAML app](#configuring-bitrise-as-a-saml-app-for-okta). 1. [Set up SCIM previsioning in Okta](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-okta-sso-for-bitrise#setting-up-scim-provisioning-in-okta). ### Adding Bitrise to Okta Bitrise is not an integrated app in Okta. You have to add Bitrise manually to Okta first, then you can configure SAML SSO on it. We will be jumping back and forth from the Bitrise Workspace account to Okta so make sure both pages are available. In practice this means the Workspace owner should be logged into Bitrise and the Okta admin should be logged into Okta. 1. Log into Okta and click **Admin**. ![okta_2.png](/img/_paligo/uuid-1640f128-3b4d-356a-f7d0-5d40e60fa6b3.png) 1. From the left menu, select **Applications** under the **Applications** section. 1. Click on the **Create App Integration** button. ![app_integration_okta.png](/img/_paligo/uuid-aa579855-a0d6-a545-6a4f-24f543dd36ab.png) This opens the **Create a new app integration** window. 1. Select **SAML 2.0** option as the **Sign-in method** and click **Next**. ![create_new_app_integration.png](/img/_paligo/uuid-a52e93de-ff50-544e-c914-5aa20dbdeadd.png) 1. At the **General Settings** step, type Bitrise into the **App name** field. (Optionally, you can add an app logo if you wish.) Click **Next**. ![general_settings_okta.png](/img/_paligo/uuid-e0ec0de8-1ae0-a3e9-ea57-fb0fa50b58df.png) 1. Head over to your Bitrise Workspace and click the **Single Sign-on** tab on the left menu. 1. Click the **Copy** button to copy the **Assertion Consumer Service URL (ACS URL)**. 1. Head back to Okta’s **Configure SAML** page and paste the copied URL from Step 7. to the **Single sign-on URL** input field. 1. Type Bitrise at the **Audience URI (SP Entity ID)**. You can download the Okta certificate file now, and paste its content or upload the file itself in the **SAML SSO provider certificate** field on your Bitrise Workspace’s **Single Sign-On** page. Even easier if you leave it for later as you will need to fill out the **Assertion Consumer Service URL (ACS URL)** on Bitrise anyway. You will fetch this while configuring Bitrise as a SAML app on Okta. Do not hit **Configure SSO** on the **Single Sign-on** page of Bitrise just yet. 1. Set the **Name ID format** to **EmailAddress**. ![saml_sso_config.png](/img/_paligo/uuid-26903c72-7c1d-66a1-37d7-15be1fbd6379.png) 1. Click **Next**. 1. Fill out the **Feedback** section. Hit **Finish**. 1. In **Applications**, go to the **Sign-on** tab, and click **Edit** next to **Settings**. 1. Scroll down to the **Credential Details** section, and make sure that **Application username format** is set to **Email**. ![credential_details_2.png](/img/_paligo/uuid-23aa2f50-cde3-e87d-c8bd-0c2b1d512540.png) 1. Click **Save**. Congrats! Bitrise has been successfully added to Okta as an app. ### Configuring Bitrise as a SAML app for Okta 1. Click the **Assignments** tab of your Bitrise app. Here you can assign Bitrise to individuals/groups. Make sure you assign Bitrise to all Workspace members who will access the Bitrise Workspace through SAML. ![assignments_okta.png](/img/_paligo/uuid-1c93dfa7-c82d-5694-1717-62b9239fe667.png) 1. Click the **Sign-On** tab of your Bitrise app. You will see that SAML setup is not completed yet. Scroll down, and click **View SAML setup instructions**. ![saml_sso_config_samlsso2.png](/img/_paligo/uuid-22736f46-339f-3986-05c1-cbbcf7eb57f6.png) The **How to Configure SAML 2.0 for Bitrise application** page is displayed. It summarizes all the information you need to set up the SAML connection between Bitrise and Okta. ![configure-bitrise-okta-1.jpg](/img/_paligo/uuid-a01cfa75-834c-9ffe-57bc-0a097a6df676.jpg) 1. Copy the **Identity Provider Single Sign-On URL** and paste it in your Bitrise Workspace’s **SSO URL** field. If you haven’t pasted the Certificate’s content or uploaded the file itself into the **SAML SSO provider certificate** field of your Bitrise Workspace yet, you can do so now. ![saml_sso_url.png](/img/_paligo/uuid-bce20b25-c8cc-fed6-c43c-627647f4c5a4.png) 1. Optionally, fill out the **SSO Logout URL** field, and the **Application Identifier** field if multiple Workspaces use this same Okta instance. 1. Click **Configure SSO** on your Bitrise Workspace. That's it! From now on, whenever you access the **Single Sign-on** page, you can configure the SAML SSO settings. ### Setting up SCIM provisioning in Okta You can set up SCIM provisioning for Bitrise using Okta. :::important[Managing Workspace groups] While SCIM is a great way to manage the access of your users for Bitrise Workspaces, you will have to do some initial configuration for your groups in Bitrise after finishing setting up the SCIM provisioning. For more information about configuring your groups, check out [Adding Workspace groups to a project](/bitrise-platform/projects/managing-user-access-to-a-project#adding-workspace-groups-to-a-project). ::: We will be jumping back and forth from the Bitrise Workspace account to Okta, so make sure both pages are available. In practice, this means the Workspace owner should be logged into Bitrise, and the Okta admin should be logged in to Okta. 1. On Bitrise, [configure domain control and generate your SCIM credentials](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-scim). You need to have: - A verified domain. - An SCIM base URL and an SCIM authentication token. Make sure you save both of these because you will need them during the process later. 1. Log into Okta and click **Admin**. 1. From the left menu, select **Applications** under the **Applications** section. 1. Select your Bitrise app. 1. Click the **General** tab of your Bitrise app. 1. Click **Edit** next to the **App Settings** section and select the **SCIM** option using the radio button next to **Provisioning**. ![scim_setting.png](/img/_paligo/uuid-61cf9962-6cb6-6c24-74d4-132f9a1c066d.png) 1. Click **Save**. A new tab called **Provisioning** will appear. 1. Head back to Okta, and select the **Provisioning** tab, then click on **Edit**. 1. Paste the SCIM base URL you copied from Bitrise in the **SCIM connector base URL** field. 1. Add **userName** in the **Unique identifier field for users** field. ![scim_connection_2.png](/img/_paligo/uuid-96dabdf1-1006-5bdc-4457-92dfb91b8c70.png) 1. Select which provisioning actions you would like to enable using the checkboxes next to **Supported provisioning actions**. :::important[Push Groups are mandatory] Please note that you must enable Push Groups. This is because on Bitrise, Workspace membership works via groups and Okta/SCIM can control our Workspace groups via Push Groups. ::: 1. Select **HTTP Header** from the **Authorization Mode** dropdown menu. 1. Copy and paste your SCIM authentication token in the **Authorization** field. 1. Click **Test Connector Configuration** to test if everything is working correctly. ![test_connector.png](/img/_paligo/uuid-0d2d2b23-f9a9-d57d-3b14-44f085bfcc5f.png) 1. Close the **Test Connector Configuration** window and click **Save**. 1. Click the **Provisioning** tab of your Bitrise app, then click on **Edit** next to the **Provisioning to App** section. ![scim_provisioning.png](/img/_paligo/uuid-87a6ec99-9380-826b-9176-13034fefa22a.png) 1. Select which provisioning options you would like to enable and click **Save**. :::note[Sync password] We recommend keeping the **Sync Password** setting disabled. ::: That's it! You can now use SCIM provisioning in Okta to manage the access of your users to Bitrise. ### Pushing Okta groups to Bitrise using SCIM You can push groups from Okta to Bitrise using SCIM provisioning. Pushing a group either links an Okta group to an existing Bitrise group or creates a new group in your Bitrise Workspace. Either way, by pushing a group, you set up synchronization between an Okta group and a Bitrise group. 1. Log into Okta and click **Admin**. 1. From the left menu, select **Applications** under the **Applications** section. 1. Select your Bitrise app. 1. Click the **Push Groups** tab. 1. Click on **Push Groups** and choose a filtering method. ![push_groups.png](/img/_paligo/uuid-da9ac0ed-a8fe-0d52-3e66-a8195414d1fa.png) 1. Find the group(s) you want to push. 1. You must either create a new group, which will create a brand new group in your Bitrise Workspace or link the Okta group to an existing Bitrise group. You can choose between these methods using the dropdown menu under the **Match result & push action**. :::caution[Linking a group] If you decide to link an Okta group to an existing Bitrise group, keep the following in mind: - If the Okta and Bitrise group names are different, the Bitrise group will be automatically renamed to match the name of the Okta group. - When you manually push a group connected to an existing Bitrise group, if the group had members who were only added on Bitrise and not included in the Okta group, then they will be removed as Okta becomes the single source of truth. ::: ![linkGroup.png](/img/_paligo/uuid-e94688f6-c068-8c29-201a-bba3c7373dca.png) 1. Click **Save**. When the **Push Status** changes to **Active**, the synchronization between Okta and Bitrise is ready. Your group should be updated in a couple of seconds on your Bitrise Workspace as well. ![push_status_active.png](/img/_paligo/uuid-28f245c4-7eb3-89b2-1e4d-18d922bbc0a5.png) ### Synchronizing groups and users between Okta and Bitrise After [pushing Okta groups to Bitrise](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-okta-sso-for-bitrise#pushing-okta-groups-to-bitrise-using-scim), you can synchronize your groups and users between Okta and Bitrise. To do so, you must manage the app integration assignments in Okta: 1. Log into Okta and click **Admin**. 1. From the left menu, select **Applications** under the **Applications** section. 1. Select your Bitrise app. 1. Make sure that **Create Users** and **Deactivate Users** options are enabled on the **Provisioning** tab. ![provisioning_settings.png](/img/_paligo/uuid-d8a157ed-518f-ad9c-67bb-e66a50263ab7.png) :::note[Deprovisioning users] If you deprovision a user with SCIM, the user will be automatically logged off Bitrise and their PATs will be disabled. ::: 1. Go to the **Assignments** tab. 1. Click **Assign** and choose **Assign to People** to synchronize individual users or **Assign to Groups** to synchronize groups. ![assign_people.png](/img/_paligo/uuid-d6dbb0ec-3447-10ab-ba08-1bf5731153be.png) 1. Select the users or groups that you would like to synchronize, then click **Done**. :::important[Domain verification] New users without verified domains will receive an email invitation to join the Workspace. Existing users will also receive a verification email unless you verify your company domain: [Configuring SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-scim). ::: 1. After synchronizing your groups and users, you can check the **Push Groups** tab to see if the synchronization is finished. You can also manually push your updates by clicking on the dropdown menu in the **Push Status** column and selecting **Push now**. ![push_now.png](/img/_paligo/uuid-71166a22-3341-0ee5-6599-6b190f83e717.png) :::caution["Push now" overrides the Bitrise group] Users not included in your Okta group will be automatically removed from the linked Bitrise group. ::: --- ## OneLogin SSO This guide provides step-by-step instructions on setting up Bitrise as a SAML application on [OneLogin](https://www.onelogin.com/). :::caution[SAML SSO restrictions] SAML SSO is only available on select plans. Contact our support to find out if SAML SSO is available on your Workspace's plan. Since the SAML SSO feature is tied to the above plans, if you decide to downgrade to a free plan, you will lose this feature. All Workspace members will receive an email about the downgrade, and you’ll have two weeks to re-upgrade if you wish to use SAML SSO in your Workspace again. ::: Before connecting SAML SSO to your Workspace: - Make sure the administrator to OneLogin is at hand while setting up SAML SSO connection on Bitrise. - - Be aware that only the Workspace owner can set up SAML SSO to a Bitrise Workspace. - Your account on Bitrise has a Workspace with one of our [paid plans](https://bitrise.io/pricing). To configure Bitrise on OneLogin: 1. Log into [OneLogin](https://www.onelogin.com/) as an Administrator. 1. Click **Administration** on the top bar. ![Setting_up_OneLogin_SSO_for_Bitrise.png](/img/_paligo/uuid-e05bd9fd-2b96-f6dd-9d2b-b3ad8ba5510e.png) 1. Select **Applications** and click **Add App**. This will take you to the **Find Applications** page. ![Setting_up_OneLogin_SSO_for_Bitrise.png](/img/_paligo/uuid-90d0f8f9-8de5-2c9c-f8e7-2279dc5d48ef.png) 1. Type `Bitrise` in the search bar and select the **SAML2.0** type from the search results. ![Setting_up_OneLogin_SSO_for_Bitrise.jpg](/img/_paligo/uuid-ba3b2ff2-116c-1ae2-0e8d-72c0e73826ee.jpg) 1. Click the **Configuration** tab on the left sidebar. You can change the icon and add descriptions if you wish. Make sure **Organization (Bitrise)** is ticked. Hit **Save**. ![Setting_up_OneLogin_SSO_for_Bitrise.jpg](/img/_paligo/uuid-97037eee-6e35-4a1f-1e4e-a252c78b2317.jpg) 1. Click the **Configuration** tab again and paste the **Assertion Consumer Service URL (ACS URL)** from your Bitrise Workspace’s **Single Sign-On** tab to the **Single Sign-On URL** field on OneLogin. Hit **Save** in **OneLogin**. ![Setting_up_OneLogin_SSO_for_Bitrise.jpg](/img/_paligo/uuid-74f65dc6-6662-db11-e97a-9ba3d039cea9.jpg) 1. Select **SSO** on the left sidebar. 1. Click the **View details** for the X.509 Certificate. Copy the content of the **X.509 Certificate** and paste it to the **SAML SSO provider certificate** field on the **Enable Single Sign-On** page of Bitrise. 1. Go back to the **SSO** page on OneLogin and copy the **SAML 2.0 Endpoint (HTTP)** link. Paste it in the **SAML SSO provider Single Sign-On URL (SSO URL)** field on Bitrise. 1. Go back to Bitrise and click **Configure SSO**. :::important[Users on OneLogin and Bitrise] Make sure the users in your Bitrise Workspace are all added to the **Users** page on OneLogin. If not, go to **Users**, then **New User** and add the new user. Don’t forget to send out an invite (**More actions** drop-down menu, **Send Invitation**) to a new user so that the user can activate their account on OneLogin. Users must be added to the newly created Bitrise app by clicking **Applications** under **User Info** and clicking the **+** sign. Make sure the added users are all Workspace members on Bitrise. ![application-onelogin.jpg](/img/_paligo/uuid-f6505a6f-5c4e-7cf1-8a81-f8325898b1be.jpg) ::: If you’ve completed setting up Bitrise on OneLogin and connected it with your Bitrise Workspace, then all Workspace members will get an email from Bitrise which contains a link to activate their SSO connection to the Bitrise Workspace. --- ## Ping Identity SSO This guide provides step-by-step instructions on setting up Bitrise as a SAML SSO application in [Ping Identity](https://www.pingidentity.com/en.html). :::caution[SAML SSO restrictions] SAML SSO is only available on select plans. Contact our support to find out if SAML SSO is available on your Workspace's plan. Since the SAML SSO feature is tied to the above plans, if you decide to downgrade to a free plan, you will lose this feature. All Workspace members will receive an email about the downgrade, and you’ll have two weeks to re-upgrade if you wish to use SAML SSO in your Workspace again. ::: Before connecting SAML SSO to your Workspace: - A PingOne administrator who is logged into [PingOne](https://admin.pingone.com/web-portal/login). - - Be aware that only the Workspace owner can set up SAML SSO to a Bitrise Workspace. - Your account on Bitrise has a Workspace with one of our [paid plans](https://bitrise.io/pricing). To add Bitrise to Ping Identity: 1. Click **APPLICATIONS** on the top bar of [PingOne](https://admin.pingone.com/web-portal/login). 1. On **My Applications** tab, make sure **SAML** is selected. Click the **Add Application** drop-down and select **New SAML Application**. ![Setting_up_Ping_Identity_SSO_for_Bitrise.jpg](/img/_paligo/uuid-ba20e7c6-49cf-1ec0-ca6a-5630eb89c357.jpg) 1. At **Application Details,** fill out the required fields and click **Continue to Next Step**. ![Setting_up_Ping_Identity_SSO_for_Bitrise.jpg](/img/_paligo/uuid-6ebb926e-6275-81b7-fdb8-559128c87944.jpg) 1. At **Application Configuration**, leave the **I have the SAML configuration** selected. Fill out the following: - **Assertion Consumer Service (ACS)** field: Insert the **Assertion Consumer Service URL (ACS URL)** link here from your Bitrise Workspace’s **Single Sign-On** tab. - **Entity ID field**: Type `Bitrise`. - **Signing**: Click the **Sign Response** option. Here is an overview of the above settings: ![Setting_up_Ping_Identity_SSO_for_Bitrise.jpg](/img/_paligo/uuid-b3f12826-15e7-22c6-5688-9f3be3f519fd.jpg) 1. Continue to the next step. 1. At **SSO Attribute Mapping**, you don’t have to change anything, proceed to the next step. 1. At **Group Access**, add the group(s) to your application. These groups will be able to access Bitrise through SAML SSO. Continue to the next step. ![Setting_up_Ping_Identity_SSO_for_Bitrise.jpg](/img/_paligo/uuid-cfafb8d7-1a0e-d967-5609-385cc5db90e2.jpg) 1. At the **Review Setup** page, you can doublecheck the details you provided in the previous steps. Make sure you download the following files from this review page: - Click **Download** to get the **Signing Certificate** and **SAML Metadata** files. ![Setting_up_Ping_Identity_SSO_for_Bitrise.jpg](/img/_paligo/uuid-d626ceb8-0cf3-d459-5cd7-9e59e0fef81a.jpg) 1. Click **Finish**. 1. Let’s open the two files. - Copy the entire content of the **SAML Metadata** file and paste it in the **SAML SSO provider** **certificate** field of your Bitrise **Single Sign-On** page. - Open the **Signing Certificate** file and copy the `HTTP-POST` `SingleSignOnService Location` link and paste it in the **SAML SSO provider Single Sign-On URL (SSO URL)** field on Bitrise. 1. Click **Configure SSO** on Bitrise. Now you have set up SAML SSO on your Bitrise Workspace. --- ## Two-factor authentication We provide an extra layer of security to your account if you enable two-factor authentication (2FA) on your Bitrise account. We recommend that you check your connected accounts (GitHub, Bitbucket, GitLab) and enable 2FA if you haven’t already. ### Enabling two-factor authentication 1. Download and install [Google Authenticator](https://support.google.com/accounts/answer/1066447?hl=en) on your phone. 1. Log in to Bitrise, and select **Bitrise CI** from the left navigation menu. 1. In the upper right corner, click the profile image to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. Select **Security** on the left. 1. Click on **2FA is enabled** under **Two-factor authentication**. 1. Open your Google Authenticator and scan the QR-code that appears on your screen. 1. Enter the 6-digit code that was generated. 1. Once you have activated your 2FA and saved your recovery codes, you will receive a confirmation email from **letsconnect@bitrise.io**. ### Disabling two-factor authentication Follow this procedure to disable two-factor authentication (2FA) if you are already logged into Bitrise. 1. Log in to Bitrise, and select **Bitrise CI** from the left navigation menu. 1. In the upper right corner, click the profile image to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. Select **Security** on the left. 1. Click on **2FA is enabled** under **Two-factor authentication**. 1. Provide your Bitrise login password in the pop-up window. ![edit-2fa.png](/img/_paligo/uuid-bd209862-be8e-f0b7-c8c6-23b6f23d2329.png) ### Have you lost your authenticator and recovery codes? 2FA protects your account from unwanted login attempts (for example, with a stolen password) by providing an extra security step during the login flow. This also means that if you lose the device with the authenticator app, and you lose your recovery codes, you won't be able to access your account and Bitrise Support will not be able to remove the activated 2FA from your account. However, if there has been any third-party service (for example, GitLab, GitHub or Bitbucket) connected to your account before, you can try to log in through that. In the absence of a connected third-party account, we recommend you to create a new account on Bitrise. In very special cases, Bitrise can remove 2FA from your account. Please note that Bitrise can only disable the activated 2FA on your account if there is a Git provider account already connected to Bitrise. 1. Contact our Support Team using the email address you provided when signing up to Bitrise. 1. Explain why you’re requesting us to remove 2FA. Our Support Team will ask you to create a new public repo on your git account with the title: `bitrise_verification` 1. Send the link of the created repo to our Support Team. Please note that our Support Team can deny your request if they find removing 2FA from the account might pose a security risk on your Bitrise account. --- ## AI FAQ – How Bitrise leverages AI technologies in its features and services As AI technologies are getting more and more popular, we collected answers of the most frequent questions on how Bitrise is leveraging these technologies. In this article, you can find detailed information on how AI and LLM tools are supported across Bitrise features and services. ### At a glance Artificial Intelligence (AI) and more specifically large language models (LLMs) are rapidly becoming essential tools across the tech industry. Bitrise is actively investing in these new technologies that can enhance our platform and deliver smarter, more efficient solutions to our customers. Security and reliability are paramount at Bitrise. We are dedicated to ensuring that our products or features using AI, like all our technologies, are employed responsibly and adhere to the industry standards. This document should help understand how Bitrise implements AI, how Customer Content (defined below) is categorized and how customers can make choices whether to use or not use the features where AI functions are implemented. Below we collected the most frequent questions we have received on how Bitrise is using AI technologies. We will update this document as we receive additional questions from customers. ### How is Customer data used with AI on Bitrise? Bitrise classifies Customer data into the following Customer Content categories: | **Customer content category** | **Description** | | --- | --- | | **Customer Sensitive Content** | Content that must be handled with strict access controls and cannot be used for training, fine-tuning, or other secondary purposes, without explicit customer consent and appropriate privacy protections. | | **Customer Non-Sensitive Data** | Data that can be handled with standard operational controls and which may be used for service improvement, analytics, and operational purposes without requiring explicit customer consent. Includes Customer Non-Sensitive Content. | Customer Sensitive Content and Non-sensitive Data shall be further classified as non-anonymizable, anonymizable, and directly useable, and may be processed as described below based on such classification: | Type of Customer Content | Processing category | | --- | --- | | **Non-Anonymizable (Customer Sensitive Content)** | Non-Anonymized:  Must be handled in original form or not at all. | | **Anonymizable (Customer Sensitive Content)** | Anonymized:  Can be processed/aggregated with PII/sensitive details removed and Sensitive Customer Content is Anonymized. | | **Directly Useable (Customer Non-Sensitive data)** | Directly Used:  Can be used as-is for operational purposes. | ![ai-faq-data.png](/img/_paligo/uuid-70109545-5b55-93cb-dfa6-20a62c0cccdb.png) #### Data classification details - **Customer Sensitive Content**: This is Customer Content that customer inputs into the Bitrise Services that is confidential or proprietary to the customer, or that if otherwise is exposed or mishandled, could cause harm, competitive disadvantage, or a breach of the customer's confidentiality. This typically includes: - Proprietary information (that is, source code, configuration secrets, business logic). - Personal or identifying information that cannot be anonymized. - Data subject to specific regulatory or contractual protection requirements. - **Customer Non-Sensitive Data:** This is Customer data that provides information about the customer’s usage of the Bitrise Services or non-sensitive content input from the customer that, if exposed, would not cause business harm, competitive disadvantage, or breach of the customer’s confidentiality. This typically includes: - Aggregated metrics and operational statistics. - Non-identifying technical telemetry. - Public information or data the customer has made publicly available. - System performance data that doesn't reveal proprietary information. The following table lists specific content types, their content classifications, and the type of processing they may be permitted  (or in the case of Non-Anonymizable, which is not permitted): | Data Type | Classification | Processing | | --- | --- | --- | | Customer’s source code | Customer Sensitive Content | Non-Anonymizable | | Environment variables | Customer Sensitive Content | Non-Anonymizable | | Secrets for builds | Customer Sensitive Content | Non-Anonymizable | | Auth secrets for third party integrations | Customer Sensitive Content | Non-Anonymizable | | Artifacts | Customer Sensitive Content | Non-Anonymizable | | Build cache blobs | Customer Sensitive Content | Non-Anonymizable | | Connected Git accounts (for example, GitHub username, organization) | Customer Sensitive Content | Non-Anonymizable | | Outgoing webhook URLs they set up | Customer Sensitive Content | Non-Anonymizable | | Users and groups | Customer Sensitive Content | Non-Anonymizable | | Connected SAML accounts | Customer Sensitive Content | Non-Anonymizable | | App release metadata (Release Management) | Customer Sensitive Content | Non-Anonymizable | | Generic files (required for builds) | Customer Sensitive Content | Non-Anonymizable | | Code signing related files (test device data, UUIDs) | Customer Sensitive Content | Non-Anonymizable | | Build Insights data (build failures over time, build duration over time, flaky tests, utilization, Git statistics and so on) | Customer Sensitive Content | Anonymizable | | Pipeline configuration (bitrise.yml) | Customer Sensitive Content | Anonymizable | | Test reports | Customer Sensitive Content | Anonymizable | | Build logs | Customer Sensitive Content | Anonymizable | | Access log (IP address) | Customer Sensitive Content | Anonymizable | | List of third party tools customers use | Customer Sensitive Content | Anonymizable | | Usage data, like: build count, build length, error rate, cache hit rate, bytes transferred, CLI and Step telemetry | Customer Non-Sensitive Data | Directly Useable | | Document center search query | Customer Non-Sensitive Data | Directly Useable | | Marketing analytics (Google Analytics, and so on) | Customer Non-Sensitive Data | Directly Useable | | Infrastructure related data: VM load (CPU and memory), datacenter location, and so on. | Customer Non-Sensitive Data | Directly Useable | | Website analytics | Customer Non-Sensitive Data | Directly Useable | ### Does Bitrise retain Customer data for training? Customer data is classified into several categories of customer content. The Customer Content is then handled as follows: - **Non-Anonymizable Customer Sensitive Content** is never retained for training or fine-tuning purposes. For example, source code is never retained for any training/refining or any other purposes, whether or not such other purposes could lead Customer source code to leak into foundational or derivative models. - A**nonymized Customer Sensitive Content** and **Customer Non-Sensitive Data** may be retained for use cases like fine tuning, predicting load, and to improve performance and reliability. ### Where does Bitrise run its LLM inference? Bitrise differentiates between the following **Inference Locations** (where the model is used and meets Customer data). Not all models are available at all Inference Locations. | Inference Location | Deployment / Inference Location | | --- | --- | | "Local" | On-device, where the service is running – for example, on the same server where the build/test process is happening | | "Bitrise-hosted GPU" | Inside Bitrise-managed VPC and servers | | "Bitrise-controlled CSP account" | For example, AWS Bedrock, GCP Vertex AI | | "Third-party API vendor" | For example, OpenAI, Anthropic | ### Which large language models (LLMs) does Bitrise use? Bitrise utilizes the following model families, with their Inference Location indicating where each model is used and interacts with Customer data. | Model name / Provider | Deployment / Inference Location | Data RetentionThe Data Retention is set by the LLM service provider for regulatory/safety compliance. Bitrise does not retain data and works with LLM service providers to set Zero Data Retention wherever possible. by the service provider | | --- | --- | --- | | Gemini models (proprietary models) | GCP Vertex AI | Zero Data Retention | | OpenAI models (proprietary models) | OpenAI hosted API endpoints | Ephemeral <30 days | | Anthropic models (proprietary models) | Anthropic hosted API endpoints | Zero Data Retention | | Anthropic models (proprietary models) | AWS Bedrock | Zero Data Retention | | Grok models | X.ai hosted API endpoints | Zero Data Retention | ### How often does Bitrise update its AI models? Bitrise is continuously working to enhance AI features by testing and updating models regularly as they become available. These updates are designed to improve accuracy, security, and performance while respecting your data privacy and without interrupting your workflows. Models go through rigorous evaluations before they are elevated to production use. ### Which Bitrise features use AI/LLMs? | Feature | Type of Customer data involved | Allowed Inference Locations | Allowed Models | | --- | --- | --- | --- | | Code reviewer | - Parts of Customer’s source code (diff hunks, changed files, and so on) | all | all | | Bitrise Coding Agent | - Customer’s source code - Environment variables - Secrets for builds | all | all | | Compare invocations / analysis | - Usage data: build count, build length, error rate, cache hit rate, bytes transferred, etc. - Infrastructure related data: VM load (CPU and memory) and related telemetry, datacenter location - Environment variables - Parts of customer’s source code | all | all | | AI Assistant | - Parts of Customer's build log (failed Step log chunks) - Build metadata like: Step title, stack name, machine type, Git branch name, commit messages. | all | all | ### Who owns the intellectual property generated by LLMs? Ownership follows the same data‑classification logic we apply throughout this FAQ: the more closely a piece of AI output can be traced back to your original, non‑anonymizable material, the more completely it belongs to you. Everything else remains ours. | Category of input data that produced the AI output | Who owns the output? | Rationale | | --- | --- | --- | | **Non-Anonymizable Customer Sensitive Content** (for example, your source code, build secrets, etc.) | **Customer** (you) | This output is effectively an extension of content you already own and that we commit never to retain or use for secondary purposes. | | **Anonymized Customer Sensitive Content** (for example, anonymized build logs, failure statistics, etc.) | **Bitrise** | Once sensitive fields are stripped, the output no longer carries proprietary customer information. We may reuse it to improve the service. | | **Customer Non-Sensitive Data** (for example, telemetry, publicly available metadata, search input string, etc.) | **Bitrise** | These inputs are either non-sensitive in nature, or generated by or already belong to Bitrise. | #### What you can do with Bitrise‑owned output Bitrise-owned outputs that are made available to you as part of the Bitrise Services are available for you to use together with the Bitrise Services that you are otherwise licensed to use. #### What Bitrise can do with customer‑owned output If the output is derived from your Non‑Anonymizable Sensitive Content, Bitrise keeps no rights beyond those needed to generate and display it back to you. We do not reuse or re‑train models on that output without your explicit permission and all intellectual property rights remain with you. For example, if a coding agent operated by Bitrise generates code changes based on your source code, you fully own the generated code. ### Is it possible to disable AI features on Bitrise? Yes. Customers may disable AI features at: - Feature level - Workspace level Please [contact our support team](https://support.bitrise.io/en/articles/11689194-how-to-submit-a-ticket-to-bitrise-support) if you want to disable or enable any or all AI assisted features. ### How does Bitrise approach using AI-capabilities in their services? When implementing AI in features, Bitrise aims to abide by the following: - AI suggestions are always recommendations, never irreversible actions. - AI augments, but never replaces human judgment in decision making. - AI decisions must be explainable in clear, non‑technical language where feasible. - Critical flows (for example, deployment, billing, etc.) always require explicit human confirmation. - Bitrise is committed to transparent incident investigation and timely corrective action through our internal policies. ### Further questions in Compliance and Security? [Find out more here](https://bitrise.io/platform/devops/security). --- ## AI features on Bitrise :::tip[AI FAQ] This page offers a short summary of the available AI features on Bitrise. For a detailed breakdown of how Bitrise uses AI and how we handle customer data related to AI features, see the [AI FAQ](/bitrise-platform/ai/ai-faq---how-bitrise-leverages-ai-technologies-in-its-features-and-services). ::: Bitrise offers multiple AI features to help enhance your Mobile DevOps processes. You can enable or disable any individual feature, or completely disable AI features altogether: [Enabling AI features on Bitrise](/bitrise-platform/ai/enabling-ai-features-on-bitrise). The following features are available: ### Code reviewer The AI [code reviewer](/bitrise-platform/integrations/ai-code-reviewer) creates a comment every time a new pull request is opened on GitHub, and every time a user adds a new commit to the pull request. It can provide: - A summary: Highlights key code changes and their potential impact. - Walkthrough: Generates context-aware documentation to help team members quickly understand code changes. - Code review: Detects potential issues, suggests improvements, and enhances code quality. The code reviewer only works with a GitHub connection, either via the Bitrise GitHub app or an OAuth connection. :::note[Code reviewer and credit usage] You can enable the code reviewer on three projects if you have the [Pro or the Enterprise plans](https://bitrise.io/pricing). Running the code reviewer consumes one AI credit per review. If you need more projects or AI credits, go to **Workspace settings** →**Plan and billing** →**Bitrise AI** and subscribe to the add-on. For example, if you subscribe for an extra project, you will have 4 projects and an extra 100 AI credits along with your base plan AI credit. ::: ### AI build summary The [AI build summary](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/ai-build-summary) gives you a summary of why a CI build failed and suggests the fix right there on the build page. You can turn off the feature at any time. ![Bitrise AI panel with Failure details, Reason, and Suggested solution](/img/run-and-analyze-builds/2026-07-14-bitrise-ai-failure-details-panel.png) ### AI build fixer If you have a failed build, the [AI build fixer](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/ai-build-fixer) corrects it right on the build’s details page without you having to switch to other tools and processes. The AI build fixer executes the suggested code changes and pushes a PR to your GitHub repository. You can check the changes through a link to the repo. Based on your configured build triggers, Bitrise kicks off a new CI build to validate the AI changes. This means less fragmented work and quicker debugging. The AI build fixer requires the AI build summary to be enabled first. ### AI configuration assistant The [AI configuration assistant](/bitrise-ci/workflows-and-pipelines/ai-configuration-assistant) is a chat-based assistant built into the Workflow Editor. You describe what you want in plain language and the assistant produces a working Workflow or Pipeline in validated YAML, which you can refine further, either with the assistant or manually. The assistant can also: - Explain any existing Workflow or Pipeline in plain language, including what each Step does. - Suggest improvements to an existing configuration. The AI configuration assistant requires the **Configuration generator** feature to be enabled for each project in **Project settings > Bitrise AI**. ### Bitrise MCP The [Bitrise Model Context Protocol (MCP) Server](/bitrise-platform/ai/bitrise-mcp) lets you talk to Bitrise via an AI client of your choice. It enables seamless interaction with your existing CI setup. - Troubleshoot issues by directly asking about failure reasons. The AI analyzes logs and configurations, providing actionble recommendations. - Optimize configurations by instructing the AI to suggest improvements. You will receive instant insights and practical suggestions. - Automate manual tasks such as handling permissions, inviting members to a project, or looking for old builds. Tell the AI agent about your requirements: it will send you the proposed steps for review and ask for permission before executing each action. You can review the results at each step of the process. Bitrise MCP supports multiple AI clients, including Claude, Cursor, VS Code, Windsurf, Gemini CLI, and AWS Kiro. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) for the full list of supported clients and setup instructions. --- ## Bitrise MCP The Bitrise Model Context Protocol (MCP) Server lets you talk to Bitrise via an AI client of your choice. It enables seamless interaction with your existing CI setup: - Troubleshoot issues by directly asking about failure reasons. The AI analyzes logs and configurations, providing actionable recommendations. - Optimize configurations by instructing the AI to suggest improvements. You will receive instant insights and practical suggestions. - Automate manual tasks such as handling permissions, inviting members to a project, or looking for old builds. Tell the AI agent about your requirements: it will send you the proposed steps for review and ask for permission before executing each action. You can review the results at each step of the process. The remote MCP server is hosted at mcp.bitrise.io. Most MCP clients (Claude Code, Cursor, VS Code, and others) authenticate via OAuth: point them at the URL and they'll prompt you to sign in to Bitrise on first use. Clients that don't yet support MCP OAuth can still authenticate by passing a Personal Access Token in an HTTP header `Authorization: Bearer `. You can find [the Bitrise MCP repository on GitHub](https://github.com/bitrise-io/bitrise-mcp). Among other things, it includes: - Install guides for specific MCP clients. The currently supported clients are: VS Code, GitHub Copilot in other IDEs, Claude Applications (Desktop and Code CLI), Cursor, Windsurf, AWS Kiro, and Gemini CLI. - How to use a local MCP server instead of the remote one. - What tools are available and how you can limit their usage. --- ## Install Bitrise MCP Server in Claude Applications ### Claude Code CLI #### Prerequisites - Claude Code CLI installed (recent version, with MCP OAuth support) - A Bitrise account - Open Claude Code inside the directory for your project (recommended for best experience and clear scope of configuration) #### Remote Server Setup (Streamable HTTP) — Recommended The remote server uses OAuth to authenticate you against your Bitrise account. No token to copy or paste. 1. Add the server: ```bash claude mcp add --transport http bitrise https://mcp.bitrise.io ``` 2. Restart Claude Code. 3. On the first tool use, Claude Code will open your browser to sign in. Log in to Bitrise (or confirm your existing session) and approve the consent screen. 4. Run `claude mcp list` to confirm the server is configured. ##### Fallback: PAT-based authentication If you're on a Claude Code version without MCP OAuth support, or you'd prefer to use a Personal Access Token: 1. [Create a Bitrise API Token](https://devcenter.bitrise.io/api/authentication) under [Account Settings → Security](https://app.bitrise.io/me/account/security). 2. Add the server with the token as a Bearer header: ```bash claude mcp add --transport http bitrise https://mcp.bitrise.io -H "Authorization: Bearer YOUR_BITRISE_PAT" ```
Storing Your PAT Securely For security, avoid hardcoding your token. One common approach: 1. Store your token in `.env` file ``` BITRISE_PAT=your_token_here ``` 2. Add to .gitignore ```bash echo -e ".env\n.mcp.json" >> .gitignore ``` 3. Reference it when adding: ```bash claude mcp add --transport http bitrise https://mcp.bitrise.io -H "Authorization: Bearer $(grep BITRISE_PAT .env | cut -d '=' -f2)" ```
#### Local Server Setup (Go required) The local server runs in stdio mode and authenticates with a Personal Access Token (no browser OAuth flow in stdio mode). Prerequisites: [Go](https://go.dev/) (>=1.25) installed and a Bitrise PAT. 1. Run: ```bash claude mcp add bitrise -e BITRISE_TOKEN=YOUR_BITRISE_PAT -- go run github.com/bitrise-io/bitrise-mcp/v2@v2 ``` With an environment variable: ```bash claude mcp add bitrise -e BITRISE_TOKEN=$(grep BITRISE_PAT .env | cut -d '=' -f2) -- go run github.com/bitrise-io/bitrise-mcp/v2@v2 ``` 2. Restart Claude Code. 3. Run `claude mcp list` to see if the Bitrise server is configured. #### Verification ```bash claude mcp list claude mcp get bitrise ``` ### Claude Desktop #### Prerequisites - Claude Desktop installed (latest version) - A Bitrise account #### Configuration File Location - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` - **Linux**: `~/.config/Claude/claude_desktop_config.json` #### Remote Server setup (Streamable HTTP) — Recommended Recent Claude Desktop versions support MCP OAuth natively. See [Claude | Connecting to a Remote MCP Server](https://modelcontextprotocol.io/docs/develop/connect-remote-servers#connecting-to-a-remote-mcp-server). On first connection, Claude Desktop opens your browser to authenticate with Bitrise — no token needed. If your Claude Desktop version doesn't yet support remote MCP servers natively, you can use [mcp-remote](https://www.npmjs.com/package/mcp-remote) as an adapter: ```json { "mcpServers": { "bitrise": { "command": "npx", "args": [ "mcp-remote", "https://mcp.bitrise.io" ] } } } ``` `mcp-remote` will handle the OAuth flow on your behalf. If your version of `mcp-remote` doesn't yet support OAuth, you can fall back to providing a PAT: ```json { "mcpServers": { "bitrise": { "command": "npx", "args": [ "mcp-remote", "https://mcp.bitrise.io", "--header", "Authorization: Bearer YOUR_BITRISE_PAT" ] } } } ``` Save the config file and restart Claude Desktop. If everything is set up correctly, you should see a hammer icon next to the message composer. In case `npx` is not found by Claude (`ENOENT`), specify the path to the `npx` binary in the `env` section: ```json { "mcpServers": { "bitrise": { ... "env": { "PATH": "PATH to bin of npx" } } } } ``` #### Local Server Setup (Go required) The local server uses stdio with a Personal Access Token: ```json { "mcpServers": { "bitrise": { "command": "go", "args": [ "run", "github.com/bitrise-io/bitrise-mcp/v2@v2" ], "env": { "BITRISE_TOKEN": "YOUR_BITRISE_PAT", "PATH": "PATH to bin directory of go:PATH to directory of git", "GOPATH": "your GOPATH", "GOCACHE": "your GOCACHE" } } } } ``` #### Manual Setup Steps 1. Open Claude Desktop 2. Go to Settings → Developer → Edit Config 3. Paste the code block above in your configuration file 4. If you're navigating to the configuration file outside of the app: - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` 5. Open the file in a text editor 6. Paste one of the code blocks above, based on your chosen configuration (remote or local) 7. Save the file 8. Restart Claude Desktop 9. If using OAuth: complete the sign-in flow in your browser the first time you use a tool #### Advanced configuration See [Tools](/bitrise-platform/ai/bitrise-mcp/tools) for enabling/disabling specific API groups. ### Troubleshooting **OAuth flow doesn't open browser:** - Make sure your Claude version supports MCP OAuth (recent builds only) - Try falling back to PAT-based authentication **Authentication Failed:** - For OAuth: re-authenticate via `/mcp` command in Claude Code, or by deleting and re-adding the server - For PAT: check token hasn't expired or been revoked **Remote Server:** - Verify URL: `https://mcp.bitrise.io` **Server Not Starting / Tools Not Showing:** - Run `claude mcp list` to view currently configured MCP servers - Validate JSON syntax - Restart Claude Code and check `/mcp` command - Delete the Bitrise server by running `claude mcp remove bitrise` and repeating the setup process with a different method - Check logs: - Claude Code: Use `/mcp` command - Claude Desktop: `ls ~/Library/Logs/Claude/` and `cat ~/Library/Logs/Claude/mcp-server-*.log` (macOS) or `%APPDATA%\Claude\logs\` (Windows) ### Important Notes - Remote server requires Streamable HTTP support (check your Claude version). OAuth requires a more recent build than basic Streamable HTTP. - Configuration scopes for Claude Code: - `-s user`: Available across all projects - `-s project`: Shared via `.mcp.json` file - Default: `local` (current project only) --- ## Install Bitrise MCP Server in Cursor ### Prerequisites 1. [Cursor](https://cursor.com/download) IDE installed (latest version, with MCP OAuth support — Cursor v0.48.0+ for Streamable HTTP, recent builds for OAuth) 2. A Bitrise account 3. For local setup: [Go](https://go.dev/) (>=1.25) installed and a Bitrise PAT ### Remote Server Setup (Recommended) Recent Cursor versions support MCP OAuth — on first tool use Cursor opens your browser to sign in to Bitrise; no token to paste. #### Install steps 1. Open your global MCP configuration file at `~/.cursor/mcp.json` (or use a project-local `.cursor/mcp.json`) and add the configuration below 2. Save the file 3. Restart Cursor 4. On first tool invocation, complete the browser-based sign-in flow #### Streamable HTTP Configuration ```json { "mcpServers": { "bitrise": { "url": "https://mcp.bitrise.io" } } } ``` #### Fallback: PAT-based authentication If your Cursor version doesn't yet support MCP OAuth, you can use a Personal Access Token. [Create one](https://devcenter.bitrise.io/api/authentication) under [Account Settings → Security](https://app.bitrise.io/me/account/security), then: ```json { "mcpServers": { "bitrise": { "url": "https://mcp.bitrise.io", "headers": { "Authorization": "Bearer YOUR_BITRISE_PAT" } } } } ``` ### Local Server Setup The local Bitrise MCP server runs via Go and uses a Personal Access Token (stdio mode, no OAuth). [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=bitrise&config=eyJlbnYiOnsiQklUUklTRV9UT0tFTiI6IllPVVJfQklUUklTRV9QQVQifSwiY29tbWFuZCI6ImdvIHJ1biBnaXRodWIuY29tL2JpdHJpc2UtaW8vYml0cmlzZS1tY3AvdjJAdjIifQo%3D) #### Install steps 1. Click the install button above and follow the flow, or open `~/.cursor/mcp.json` and add the configuration below 2. In Tools & Integrations > MCP tools, click the pencil icon next to "bitrise" 3. Replace `YOUR_BITRISE_PAT` with your actual Personal Access Token 4. Save the file 5. Restart Cursor #### Local Configuration ```json { "mcpServers": { "bitrise": { "command": "go", "args": [ "run", "github.com/bitrise-io/bitrise-mcp/v2@v2" ], "env": { "BITRISE_TOKEN": "YOUR_BITRISE_PAT" } } } } ``` ### Configuration Files - **Global (all projects)**: `~/.cursor/mcp.json` - **Project-specific**: `.cursor/mcp.json` in project root ### Verify Installation 1. Restart Cursor completely 2. Check for green dot in Settings → Tools & Integrations → MCP Tools 3. In chat/composer, check "Available Tools" 4. Test with: "List my Bitrise apps" (the first tool call will trigger the OAuth flow if you're not already signed in) ### Advanced configuration See [Tools](/bitrise-platform/ai/bitrise-mcp/tools) for enabling/disabling specific API groups. ### Troubleshooting #### Remote Server Issues - **OAuth flow doesn't open browser**: Update Cursor to a recent build. Older builds with Streamable HTTP but without OAuth support can use the PAT-based fallback above. - **Streamable HTTP not working**: Ensure you're using Cursor v0.48.0 or later - **Connection errors**: Check firewall/proxy settings #### General Issues - **MCP not loading**: Restart Cursor completely after configuration - **Invalid JSON**: Validate that json format is correct - **Tools not appearing**: Check server shows green dot in MCP settings - **Check logs**: Look for MCP-related errors in Cursor logs ### Important Notes - **Cursor specifics**: Supports both project and global configurations, uses `mcpServers` key --- ## Install Bitrise MCP Server in Google Gemini CLI ### Prerequisites 1. The latest version of Google Gemini CLI installed (see [official Gemini CLI documentation](https://github.com/google-gemini/gemini-cli)) 2. A Bitrise account 3. For local setup: [Go](https://go.dev/) (>=1.25) installed and a Bitrise PAT ### Bitrise MCP Server Configuration MCP servers for Gemini CLI are configured in its settings JSON under an `mcpServers` key. - **Global configuration**: `~/.gemini/settings.json` where `~` is your home directory - **Project-specific**: `.gemini/settings.json` in your project directory You may need to restart the Gemini CLI for changes to take effect. #### Method 1: Gemini Extension (Recommended) The simplest way is to use Bitrise's hosted MCP server via our Gemini extension: ``` gemini extensions install https://github.com/bitrise-io/bitrise-mcp ``` The extension handles the OAuth flow automatically on first use — you'll be prompted to sign in to Bitrise in your browser. #### Method 2: Remote Server You can also connect to the hosted MCP server directly: ```json // ~/.gemini/settings.json { "mcpServers": { "bitrise": { "httpUrl": "https://mcp.bitrise.io" } } } ``` On first tool use, Gemini CLI will open your browser for the Bitrise OAuth sign-in. ##### Fallback: PAT-based authentication For Gemini CLI builds that don't yet support MCP OAuth, [create a Bitrise PAT](https://devcenter.bitrise.io/api/authentication) and pass it as a header: ```json // ~/.gemini/settings.json { "mcpServers": { "bitrise": { "httpUrl": "https://mcp.bitrise.io", "headers": { "Authorization": "Bearer $BITRISE_PAT" } } } } ```
Storing Your PAT Securely For security, avoid hardcoding your token. Create or update `~/.gemini/.env` (where `~` is your home or project directory) with your PAT: ```bash # ~/.gemini/.env BITRISE_PAT=your_token_here ```
#### Method 3: Local Server Setup (Go Required) The local server uses stdio with a Personal Access Token: ```json // ~/.gemini/settings.json { "mcpServers": { "bitrise": { "command": "go", "args": [ "run", "github.com/bitrise-io/bitrise-mcp/v2@v2" ], "env": { "BITRISE_TOKEN": "$BITRISE_PAT" } } } } ``` ### Verification To verify that the Bitrise MCP server has been configured, start Gemini CLI in your terminal with `gemini`, then: 1. **Check MCP server status**: ``` /mcp list ``` ``` ℹ Configured MCP servers: 🟢 bitrise - Ready (62 tools) - abort_build - abort_pipeline - add_member_to_group ... ``` 2. **Test with a prompt** ``` List my Bitrise apps ``` The first tool call will trigger the OAuth sign-in flow if you're using the remote server without a PAT. ### Advanced configuration See [Tools](/bitrise-platform/ai/bitrise-mcp/tools) for enabling/disabling specific API groups. You can find more MCP configuration options for Gemini CLI here: [MCP Configuration Structure](https://google-gemini.github.io/gemini-cli/docs/tools/mcp-server.html#configuration-structure). For example, bypassing tool confirmations or excluding specific tools. ### Troubleshooting #### Authentication Issues - **OAuth flow doesn't open**: Update Gemini CLI to a recent build, or fall back to PAT-based auth - **Token expired (PAT)**: Generate a new Bitrise token #### Configuration Issues - **Invalid JSON**: Validate your configuration: ```bash cat ~/.gemini/settings.json | jq . ``` - **MCP connection issues**: Check logs for connection errors: ```bash gemini --debug "test command" ``` --- ## Install Bitrise MCP Server in AWS Kiro ### Prerequisites - AWS Kiro IDE installed ### Authentication Kiro currently uses environment-variable-based authentication for MCP servers, so the standard Power installation uses a Bitrise Personal Access Token (PAT). [Create a Bitrise API Token](https://devcenter.bitrise.io/api/authentication) under [Account Settings → Security](https://app.bitrise.io/me/account/security). If you're running a Kiro build that supports MCP OAuth and prefer to use it, see the [OAuth-based Kiro configuration](#oauth-based-configuration-experimental) section below. ### Installation via Kiro Power AWS Kiro supports installing the Bitrise MCP server as a Power, which provides automatic activation based on context and keywords. #### Steps 1. **Open the Powers Panel** - In Kiro IDE, open the Powers panel from the sidebar 2. **Add Power from GitHub** - Click on "Add power from GitHub" 3. **Enter the Repository URL** ``` https://github.com/bitrise-io/bitrise-mcp/tree/main/kiro-powers/bitrise-ci ``` 4. **Set Up Authentication** - Before starting Kiro, set the `BITRISE_TOKEN` environment variable in your shell profile (`.zshrc` or `.bashrc`): ```bash export BITRISE_TOKEN="your-actual-token-here" ``` - Restart your terminal or run `source ~/.zshrc` (or `source ~/.bashrc`) - Start Kiro - it will read the environment variable on startup - When Kiro starts, a popup may ask if you trust the environment variable - accept it to allow access 5. **Verify Installation** - The Bitrise Power should now appear in your Powers list - It will automatically activate when you mention keywords like "bitrise", "build", "ci", "cd", "mobile", "ios", "android", etc. ### Usage Once installed, the Bitrise Power will automatically activate when relevant. You can: - Manage Bitrise apps - Trigger and monitor builds - Handle build artifacts - Manage workspaces and teams - Configure pipelines - Set up release management The power provides access to all 63 Bitrise tools. For a complete list of available tools and their parameters, refer to the [tools documentation](/bitrise-platform/ai/bitrise-mcp/tools). ### OAuth-based Configuration (experimental) For Kiro builds that support MCP OAuth, you can drop the `BITRISE_TOKEN` requirement entirely. Edit `~/.kiro/settings/mcp.json` (user level) or `.kiro/settings/mcp.json` (workspace level) and remove the `headers` block: ```json { "mcpServers": { "bitrise": { "type": "http", "url": "https://mcp.bitrise.io" } } } ``` On first tool use, Kiro will open your browser for the Bitrise sign-in flow. ### Advanced Configuration You can limit the tools exposed by configuring API groups. This is useful for optimizing token usage or focusing on specific functionality. Available API groups: - `apps` - App management - `builds` - Build operations - `artifacts` - Artifact management - `workspaces` - Workspace management - `pipelines` - Pipeline operations - `outgoing-webhooks` - Webhook configuration - `cache-items` - Cache management - `release-management` - Release and distribution - `group-roles` - Role management - `account` - User account operations - `read-only` - Read-only operations By default, all groups are enabled. To customize, modify the Power configuration after installation. ### Troubleshooting #### Environment Variable Not Working Kiro IDE can only read environment variables that are set in your shell profile (`.zshrc` or `.bashrc`) **before** Kiro starts. Unlike VS Code, Kiro does not prompt you to enter the token value - it expects the environment variable to already be available. **Option 1: Set in Shell Profile (Recommended)** 1. Add the export to your shell profile: ```bash # Add to ~/.zshrc or ~/.bashrc export BITRISE_TOKEN="your-actual-token-here" ``` 2. Restart your terminal or source the profile: `source ~/.zshrc` 3. **Restart Kiro** - this is required for Kiro to pick up the new environment variable 4. When prompted, accept the popup asking if you trust the environment variable **Option 2: Manual Configuration** If the environment variable approach doesn't work, you can hardcode the token: 1. Open `~/.kiro/settings/mcp.json` (user level) or `.kiro/settings/mcp.json` (workspace level) 2. Find the Bitrise server entry 3. Replace `${BITRISE_TOKEN}` with your actual token value 4. Save the file and restart Kiro **Option 3: Use OAuth** If your Kiro build supports MCP OAuth, see the [OAuth-based Configuration](#oauth-based-configuration-experimental) section above. **Note on Environment Variable Syntax** The syntax for environment variables differs between Kiro CLI and IDE: - **Kiro CLI**: Use `${env:BITRISE_TOKEN}` (with `env:` prefix) - **Kiro IDE**: Use `${BITRISE_TOKEN}` (without prefix) This inconsistency is a known issue. The Power is configured with `${BITRISE_TOKEN}` which works for the IDE. #### Power Not Activating - Ensure you've entered the correct repository URL with `/tree/main/power` path - Check that your `BITRISE_TOKEN` is valid - Try mentioning explicit keywords like "bitrise" in your conversation #### Authentication Issues - Verify your Personal Access Token is still valid - Check token permissions in your Bitrise account settings - Regenerate the token if necessary #### Connection Problems - The power connects to `https://mcp.bitrise.io` - Ensure you have internet connectivity - Check if there are any firewall restrictions ### Additional Resources - [Bitrise API Documentation](https://devcenter.bitrise.io/api/api-index/) - [Kiro Powers Documentation](https://kiro.dev/docs/powers/) - [MCP Protocol Documentation](https://modelcontextprotocol.io/) --- ## Install Bitrise MCP Server in Copilot IDEs Quick setup guide for the Bitrise MCP server in GitHub Copilot across different IDEs. For VS Code instructions, refer to the [Install Bitrise MCP Server in VS Code](/bitrise-platform/ai/bitrise-mcp/installing-the-bitrise-mcp-server/install-vscode) #### Requirements: 1. GitHub Copilot License: Any Copilot plan (Free, Pro, Pro+, Business, Enterprise) for Copilot access 2. Bitrise Account: Bitrise account for Bitrise MCP server access 3. MCP Servers in Copilot Policy: Organizations assigning Copilot seats must enable this policy for all MCP access in Copilot for VS Code and Copilot Coding Agent – all other Copilot IDEs will migrate to this policy in the coming months 4. For local setup: [Go](https://go.dev/) (>=1.23) installed and a Bitrise Personal Access Token The remote setups below use OAuth — your IDE opens a browser on first tool use, you sign in to Bitrise, no token to paste. For older Copilot IDE builds without MCP OAuth, a PAT-based fallback configuration is included for each IDE. ### Visual Studio Requires Visual Studio 2022 version 17.14.9 or later. #### Remote Server (Recommended) The remote Bitrise MCP server is hosted by Bitrise and provides automatic updates with no local setup required. ##### Configuration 1. Create an `.mcp.json` file in your solution or %USERPROFILE% directory. 2. Add this configuration: ```json { "servers": { "bitrise": { "url": "https://mcp.bitrise.io" } } } ``` 3. Save the file. Wait for CodeLens to update to offer a way to authenticate to the new server, activate that and complete the Bitrise sign-in in your browser. 4. In the GitHub Copilot Chat window, switch to Agent mode. 5. Activate the tool picker in the Chat window and enable one or more tools from the "bitrise" MCP server. ##### Fallback: PAT-based authentication ```json { "servers": { "bitrise": { "url": "https://mcp.bitrise.io", "headers": { "Authorization": "Bearer YOUR_BITRISE_PAT" } } } } ``` [Create a PAT](https://devcenter.bitrise.io/api/authentication) under [Account Settings → Security](https://app.bitrise.io/me/account/security). #### Local Server (Go required) ##### Configuration 1. Create an `.mcp.json` file in your solution or %USERPROFILE% directory. 2. Add this configuration: ```json { "servers": { "bitrise": { "type": "stdio", "command": "go", "args": ["run", "github.com/bitrise-io/bitrise-mcp/v2@v2"], "env": { "BITRISE_TOKEN": "YOUR_BITRISE_PAT" } } } } ``` 3. Save the file. Wait for CodeLens to update to offer a way to provide user inputs, activate that and paste in a PAT you generate from your [Bitrise Account Settings/Security](https://app.bitrise.io/me/account/security). 4. In the GitHub Copilot Chat window, switch to Agent mode. 5. Activate the tool picker in the Chat window and enable one or more tools from the "bitrise" MCP server. **Documentation:** [Visual Studio MCP Guide](https://learn.microsoft.com/visualstudio/ide/mcp-servers) ### JetBrains IDEs Agent mode and MCP support available in public preview across IntelliJ IDEA, PyCharm, WebStorm, and other JetBrains IDEs. #### Remote Server (Recommended) ##### Configuration Steps 1. Install/update the GitHub Copilot plugin 2. Click **GitHub Copilot icon in the status bar** → **Edit Settings** → **Model Context Protocol** → **Configure** 3. Add configuration: ```json { "servers": { "bitrise": { "url": "https://mcp.bitrise.io" } } } ``` 4. Press `Ctrl + S` or `Command + S` to save, or close the `mcp.json` file. On first tool use the IDE will open your browser for Bitrise sign-in. ##### Fallback: PAT-based authentication ```json { "servers": { "bitrise": { "url": "https://mcp.bitrise.io", "requestInit": { "headers": { "Authorization": "Bearer YOUR_BITRISE_PAT" } } } } } ``` #### Local Server (Go required) ```json { "servers": { "bitrise": { "command": "go", "args": [ "run", "github.com/bitrise-io/bitrise-mcp/v2@v2" ], "env": { "BITRISE_TOKEN": "YOUR_BITRISE_PAT" } } } } ``` **Documentation:** [JetBrains Copilot Guide](https://plugins.jetbrains.com/plugin/17718-github-copilot) ### Xcode Agent mode and MCP support now available in public preview for Xcode. #### Remote Server (Recommended) ##### Configuration Steps 1. Install/update [GitHub Copilot for Xcode](https://github.com/github/CopilotForXcode) 2. Open **GitHub Copilot for Xcode app** → **Agent Mode** → **🛠️ Tool Picker** → **Edit Config** 3. Configure your MCP servers: ```json { "servers": { "bitrise": { "url": "https://mcp.bitrise.io" } } } ``` 4. On first tool use, complete the Bitrise sign-in flow in your browser. ##### Fallback: PAT-based authentication ```json { "servers": { "bitrise": { "url": "https://mcp.bitrise.io", "requestInit": { "headers": { "Authorization": "Bearer YOUR_BITRISE_PAT" } } } } } ``` #### Local Server (Go required) ```json { "servers": { "bitrise": { "command": "go", "args": [ "run", "github.com/bitrise-io/bitrise-mcp/v2@v2" ], "env": { "BITRISE_TOKEN": "YOUR_BITRISE_PAT" } } } } ``` **Documentation:** [Xcode Copilot Guide](https://devblogs.microsoft.com/xcode/github-copilot-exploring-agent-mode-and-mcp-support-in-public-preview-for-xcode/) ### Eclipse MCP support available with Eclipse 2024-03+ and latest version of the GitHub Copilot plugin. #### Remote Server (Recommended) ##### Configuration Steps 1. Install GitHub Copilot extension from Eclipse Marketplace 2. Click the **GitHub Copilot icon** → **Edit Preferences** → **MCP** (under **GitHub Copilot**) 3. Add Bitrise MCP server configuration: ```json { "servers": { "bitrise": { "url": "https://mcp.bitrise.io" } } } ``` 4. Click the "Apply and Close" button. On first tool use, complete the Bitrise sign-in in your browser. ##### Fallback: PAT-based authentication ```json { "servers": { "bitrise": { "url": "https://mcp.bitrise.io", "requestInit": { "headers": { "Authorization": "Bearer YOUR_BITRISE_PAT" } } } } } ``` #### Local Server (Go required) ```json { "servers": { "bitrise": { "command": "go", "args": [ "run", "github.com/bitrise-io/bitrise-mcp/v2@v2" ], "env": { "BITRISE_TOKEN": "YOUR_BITRISE_PAT", "PATH": "PATH to bin directory of go:PATH to directory of git" } } } } ``` **Documentation:** [Eclipse Copilot plugin](https://marketplace.eclipse.org/content/github-copilot) ### Usage After setup: 1. Restart your IDE completely 2. Open Agent mode in Copilot Chat 3. Try: *"List my Bitrise apps"* — first call triggers OAuth sign-in for the remote server 4. Copilot can now access Bitrise data and perform operations ### Advanced configuration See [Tools](/bitrise-platform/ai/bitrise-mcp/tools) for enabling/disabling specific API groups. ### Troubleshooting - **OAuth flow doesn't open browser**: Make sure your Copilot integration is on a build that supports MCP OAuth. Fall back to PAT-based auth in older versions. - **Connection issues**: Verify IDE version compatibility - **Authentication errors**: Check if your organization has enabled the MCP policy for Copilot - **Tools not appearing**: Restart IDE after configuration changes and check error logs --- ## Install Bitrise MCP Server in VS Code ### Prerequisites - [VS Code](https://code.visualstudio.com/Download) installed (recent version, with MCP OAuth support) - A Bitrise account - For local setup: [Go](https://go.dev/) (>=1.25) installed and a Bitrise PAT ### Remote Server Setup (Streamable HTTP) — Recommended VS Code's MCP integration handles OAuth automatically. On first connection it'll open your browser to sign you in to Bitrise — no token needed. Follow [VS Code | Add an MCP server](https://code.visualstudio.com/docs/copilot/customization/mcp-servers#_add-an-mcp-server) and add the following to your settings: ```json { "servers": { "bitrise": { "type": "http", "url": "https://mcp.bitrise.io" } } } ``` Save the configuration. VS Code will recognize the change, prompt you to sign in via your browser on first tool use, and load the tools into Copilot Chat. #### Fallback: PAT-based authentication If your VS Code build doesn't support MCP OAuth yet, you can use a Personal Access Token: ```json { "servers": { "bitrise": { "type": "http", "url": "https://mcp.bitrise.io", "headers": { "Authorization": "Bearer ${input:bitrise-token}" } } }, "inputs": [ { "id": "bitrise-token", "type": "promptString", "description": "Bitrise token", "password": true } ] } ``` [Create a Bitrise API Token](https://devcenter.bitrise.io/api/authentication) under [Account Settings → Security](https://app.bitrise.io/me/account/security) when prompted. ### Local Server Setup (Go required) Local stdio mode authenticates with a Personal Access Token: ```json { "servers": { "bitrise-local": { "type": "stdio", "command": "go", "args": [ "run", "github.com/bitrise-io/bitrise-mcp/v2@v2" ], "env": { "BITRISE_TOKEN": "${input:bitrise-token}" } } }, "inputs": [ { "id": "bitrise-token", "type": "promptString", "description": "Bitrise token", "password": true } ] } ``` ### Advanced configuration See [Tools](/bitrise-platform/ai/bitrise-mcp/tools) for enabling/disabling specific API groups. --- ## Install Bitrise MCP Server in Windsurf ### Prerequisites 1. [Windsurf IDE](https://windsurf.com/) installed (latest version) 2. A Bitrise account 3. For local setup: [Go](https://go.dev/) (>=1.25) installed and a Bitrise PAT ### Remote Server Setup (Recommended) The remote Bitrise MCP server is hosted by Bitrise at `https://mcp.bitrise.io` and supports Streamable HTTP. Recent Windsurf builds support MCP OAuth — the first tool use opens your browser to sign in to Bitrise; no token to paste. #### Streamable HTTP Configuration ```json { "mcpServers": { "bitrise": { "serverUrl": "https://mcp.bitrise.io" } } } ``` #### Fallback: PAT-based authentication If your Windsurf build doesn't yet support MCP OAuth, [create a Bitrise PAT](https://devcenter.bitrise.io/api/authentication) under [Account Settings → Security](https://app.bitrise.io/me/account/security) and add it as a header: ```json { "mcpServers": { "bitrise": { "serverUrl": "https://mcp.bitrise.io", "headers": { "Authorization": "Bearer YOUR_BITRISE_PAT" } } } } ``` ### Local Server Setup (Go required) ```json { "mcpServers": { "bitrise": { "command": "go", "args": [ "run", "github.com/bitrise-io/bitrise-mcp/v2@v2" ], "env": { "BITRISE_TOKEN": "YOUR_BITRISE_PAT" } } } } ``` ### Installation Steps #### Manual Configuration 1. Click the hammer icon (🔨) in Cascade 2. Click **Configure** to open `~/.codeium/windsurf/mcp_config.json` 3. Add your chosen configuration from above 4. Save the file 5. Click **Refresh** (🔄) in the MCP toolbar 6. On the first tool call, complete the browser-based sign-in flow (OAuth setup only) ### Configuration Details - **File path**: `~/.codeium/windsurf/mcp_config.json` - **Scope**: Global configuration only (no per-project support) - **Format**: Must be valid JSON (use a linter to verify) ### Verification After installation: 1. Look for "1 available MCP server" in the MCP toolbar 2. Click the hammer icon to see available Bitrise tools 3. Test with: "List my Bitrise apps" (first call triggers OAuth sign-in if using the remote server) 4. Check for green dot next to the server name ### Advanced configuration See [Tools](/bitrise-platform/ai/bitrise-mcp/tools) for enabling/disabling specific API groups. ### Troubleshooting #### Remote Server Issues - **OAuth flow doesn't open browser**: Update Windsurf to a recent build. Fall back to PAT-based auth in older versions. - **Authentication failures (PAT)**: Verify the PAT hasn't expired or been revoked - **Connection errors**: Check firewall/proxy settings for HTTPS connections - **Streamable HTTP not working**: Ensure you're using the correct `serverUrl` field format #### General Issues - **Invalid JSON**: Validate with [jsonlint.com](https://jsonlint.com) - **Tools not appearing**: Restart Windsurf completely - **Check logs**: `~/.codeium/windsurf/logs/` ### Important Notes - **Windsurf limitations**: No environment variable interpolation, global config only --- ## Tools ### Advanced configuration You can limit the number of tools exposed to the MCP client. This is useful if you want to optimize token usage or your MCP client has a limit on the number of tools. Tools are grouped by their "API group", and you can pass the groups you want to expose as tools. Possible values: `apps, builds, workspaces, outgoing-webhooks, artifacts, group-roles, cache-items, pipelines, account, read-only, release-management, configuration, release-management-code-push`. We recommend using the `release-management` API group separately to avoid any confusion with the `apps` API group. By default, all API groups are enabled. You can specify which groups to enable using the `ENABLED_API_GROUPS` environment variable for local (stdio) servers or the `x-bitrise-enabled-api-groups` HTTP header for remote (Streamable HTTP) servers with a comma-separated list of group names. #### Apps 1. `list_apps` - List all the apps available for the authenticated account - Arguments: - `sort_by` (optional): Order of the apps: last_build_at (default) or created_at - `next` (optional): Slug of the first app in the response - `limit` (optional): Max number of elements per page (default: 50) 2. `register_app` - Add a new app to Bitrise - Arguments: - `repo_url`: Repository URL - `is_public`: Whether the app's builds visibility is "public" - `organization_slug`: The organization (aka workspace) the app to add to - `project_type` (optional): Type of project (ios, android, etc.) - `provider` (optional): github 3. `finish_bitrise_app` - Finish the setup of a Bitrise app - Arguments: - `app_slug`: The slug of the Bitrise app to finish setup for - `project_type` (optional): The type of project (e.g., android, ios, flutter, etc.) - `stack_id` (optional): The stack ID to use for the app - `mode` (optional): The mode of setup - `config` (optional): The configuration to use for the app 4. `get_app` - Get the details of a specific app - Arguments: - `app_slug`: Identifier of the Bitrise app 5. `delete_app` - Delete an app from Bitrise - Arguments: - `app_slug`: Identifier of the Bitrise app 6. `update_app` - Update an app - Arguments: - `app_slug`: Identifier of the Bitrise app - `is_public`: Whether the app's builds visibility is "public" - `project_type`: Type of project - `provider`: Repository provider - `repo_url`: Repository URL 7. `get_bitrise_yml` - Get the current Bitrise YML config file of a specified Bitrise app - Arguments: - `app_slug`: Identifier of the Bitrise app 8. `update_bitrise_yml` - Update the Bitrise YML config file of a specified Bitrise app - Arguments: - `app_slug`: Identifier of the Bitrise app - `bitrise_yml_as_json`: The new Bitrise YML config file content 9. `list_branches` - List the branches with existing builds of an app's repository - Arguments: - `app_slug`: Identifier of the Bitrise app 10. `register_ssh_key` - Add an SSH-key to a specific app - Arguments: - `app_slug`: Identifier of the Bitrise app - `auth_ssh_private_key`: Private SSH key - `auth_ssh_public_key`: Public SSH key - `is_register_key_into_provider_service`: Register the key in the provider service 11. `register_webhook` - Register an incoming webhook for a specific application - Arguments: - `app_slug`: Identifier of the Bitrise app #### Builds 12. `list_builds` - List all the builds of a specified Bitrise app or all accessible builds - Arguments: - `app_slug` (optional): Identifier of the Bitrise app - `sort_by` (optional): Order of builds: created_at (default), running_first - `branch` (optional): Filter builds by branch - `workflow` (optional): Filter builds by workflow - `status` (optional): Filter builds by status (0: not finished, 1: successful, 2: failed, 3: aborted, 4: in-progress) - `next` (optional): Slug of the first build in the response - `limit` (optional): Max number of elements per page (default: 50) 13. `trigger_bitrise_build` - Trigger a new build/pipeline for a specified Bitrise app - Arguments: - `app_slug`: Identifier of the Bitrise app - `branch` (optional): The branch to build (default: main) - `pipeline_id` (optional): The pipeline to build - `workflow_id` (optional): The workflow to build - `pipeline_id` (optional): The pipeline to build - `commit_message` (optional): The commit message for the build - `commit_hash` (optional): The commit hash for the build - `stack` (optional): Stack to run the build on, overriding the workflow's `meta.bitrise.io.stack` for this build only (e.g. "osx-xcode-16.0.x") - `environments` (optional): Custom environment variables for the build (array of objects with `mapped_to`, `value`, and optional `is_expand` properties) 14. `get_build` - Get a specific build of a given app - Arguments: - `app_slug`: Identifier of the Bitrise app - `build_slug`: Identifier of the build 15. `abort_build` - Abort a specific build - Arguments: - `app_slug`: Identifier of the Bitrise app - `build_slug`: Identifier of the build - `reason` (optional): Reason for aborting the build 16. `get_build_log` - Get the build log of a specified build of a Bitrise app - Arguments: - `app_slug`: Identifier of the Bitrise app - `build_slug`: Identifier of the Bitrise build 17. `get_build_bitrise_yml` - Get the bitrise.yml of a build - Arguments: - `app_slug`: Identifier of the Bitrise app - `build_slug`: Identifier of the build 18. `list_build_workflows` - List the workflows of an app - Arguments: - `app_slug`: Identifier of the Bitrise app 19. `get_build_steps` - Get step statuses of a specific build of a given app - Arguments: - `app_slug`: Identifier of the Bitrise app - `build_slug`: Identifier of the build #### Artifacts 20. `list_artifacts` - Get a list of all build artifacts - Arguments: - `app_slug`: Identifier of the Bitrise app - `build_slug`: Identifier of the build - `next` (optional): Slug of the first artifact in the response - `limit` (optional): Max number of elements per page (default: 50) 20. `get_artifact` - Get a specific build artifact - Arguments: - `app_slug`: Identifier of the Bitrise app - `build_slug`: Identifier of the build - `artifact_slug`: Identifier of the artifact 21. `delete_artifact` - Delete a build artifact - Arguments: - `app_slug`: Identifier of the Bitrise app - `build_slug`: Identifier of the build - `artifact_slug`: Identifier of the artifact 22. `update_artifact` - Update a build artifact - Arguments: - `app_slug`: Identifier of the Bitrise app - `build_slug`: Identifier of the build - `artifact_slug`: Identifier of the artifact - `is_public_page_enabled`: Enable public page for the artifact #### Outgoing Webhooks 24. `list_outgoing_webhooks` - List the outgoing webhooks of an app - Arguments: - `app_slug`: Identifier of the Bitrise app 25. `delete_outgoing_webhook` - Delete the outgoing webhook of an app - Arguments: - `app_slug`: Identifier of the Bitrise app - `webhook_slug`: Identifier of the webhook 26. `update_outgoing_webhook` - Update an outgoing webhook for an app - Arguments: - `app_slug`: Identifier of the Bitrise app - `webhook_slug`: Identifier of the webhook - `events`: List of events to trigger the webhook - `url`: URL of the webhook - `headers` (optional): Headers to be sent with the webhook 27. `create_outgoing_webhook` - Create an outgoing webhook for an app - Arguments: - `app_slug`: Identifier of the Bitrise app - `events`: List of events to trigger the webhook - `url`: URL of the webhook - `headers` (optional): Headers to be sent with the webhook #### Cache Items 28. `list_cache_items` - List the key-value cache items belonging to an app - Arguments: - `app_slug`: Identifier of the Bitrise app 29. `delete_all_cache_items` - Delete all key-value cache items belonging to an app - Arguments: - `app_slug`: Identifier of the Bitrise app 30. `delete_cache_item` - Delete a key-value cache item - Arguments: - `app_slug`: Identifier of the Bitrise app - `cache_item_id`: Identifier of the cache item 31. `get_cache_item_download_url` - Get the download URL of a key-value cache item - Arguments: - `app_slug`: Identifier of the Bitrise app - `cache_item_id`: Identifier of the cache item #### Pipelines 32. `list_pipelines` - List all pipelines and standalone builds of an app - Arguments: - `app_slug`: Identifier of the Bitrise app 33. `get_pipeline` - Get a pipeline of a given app - Arguments: - `app_slug`: Identifier of the Bitrise app - `pipeline_id`: Identifier of the pipeline 34. `abort_pipeline` - Abort a pipeline - Arguments: - `app_slug`: Identifier of the Bitrise app - `pipeline_id`: Identifier of the pipeline - `reason` (optional): Reason for aborting the pipeline 35. `rebuild_pipeline` - Rebuild a pipeline - Arguments: - `app_slug`: Identifier of the Bitrise app - `pipeline_id`: Identifier of the pipeline #### Group Roles 36. `list_group_roles` - List group roles for an app - Arguments: - `app_slug`: Identifier of the Bitrise app - `role_name`: Name of the role 37. `replace_group_roles` - Replace group roles for an app - Arguments: - `app_slug`: Identifier of the Bitrise app - `role_name`: Name of the role - `group_slugs`: List of group slugs #### Workspaces 38. `list_workspaces` - List the workspaces the user has access to 39. `get_workspace` - Get details for one workspace - Arguments: - `workspace_slug`: Slug of the Bitrise workspace 40. `get_workspace_groups` - Get the groups in a workspace - Arguments: - `workspace_slug`: Slug of the Bitrise workspace 41. `create_workspace_group` - Create a group in a workspace - Arguments: - `workspace_slug`: Slug of the Bitrise workspace - `group_name`: Name of the group 42. `get_workspace_members` - Get the members in a workspace - Arguments: - `workspace_slug`: Slug of the Bitrise workspace 43. `invite_member_to_workspace` - Invite a member to a workspace - Arguments: - `workspace_slug`: Slug of the Bitrise workspace - `email`: Email address of the user 44. `add_member_to_group` - Add a member to a group - Arguments: - `group_slug`: Slug of the group - `user_slug`: Slug of the user #### Account 45. `me` - Get info from the currently authenticated user account #### Release Management 46. `create_connected_app` - Add a new Release Management connected app to Bitrise. - Arguments: - `platform`: The mobile platform for the connected app (ios/android). - `store_app_id`: The app store identifier for the connected app. - `workspace_slug`: Identifier of the Bitrise workspace. - `id`: (Optional) An uuidV4 identifier for your new connected app. - `manual_connection`: (Optional) Indicates a manual connection. - `project_id`: (Optional) Specifies which Bitrise Project to associate with. - `store_app_name`: (Optional) App name for manual connections. - `store_credential_id`: (Optional) Selection of credentials added on Bitrise. 47. `list_connected_apps` - List Release Management connected apps available for the authenticated account within a workspace. - Arguments: - `workspace_slug`: Identifier of the Bitrise workspace. - `items_per_page`: (Optional) Maximum number of connected apps per page. - `page`: (Optional) Page number to return. - `platform`: (Optional) Filter for a specific mobile platform. - `project_id`: (Optional) Filter for a specific Bitrise Project. - `search`: (Optional) Search by bundle ID, package name, or app title. 48. `get_connected_app` - Gives back a Release Management connected app for the authenticated account. - Arguments: - `id`: Identifier of the Release Management connected app. 49. `update_connected_app` - Updates a connected app. - Arguments: - `connected_app_id`: The uuidV4 identifier for your connected app. - `store_app_id`: The store identifier for your app. - `connect_to_store`: (Optional) Check validity against the App Store or Google Play. - `store_credential_id`: (Optional) Selection of credentials added on Bitrise. 50. `list_installable_artifacts` - List Release Management installable artifacts of a connected app. - Arguments: - `connected_app_id`: Identifier of the Release Management connected app. - `after_date`: (Optional) Start of the interval for artifact creation/upload. - `artifact_type`: (Optional) Filter for a specific artifact type. - `before_date`: (Optional) End of the interval for artifact creation/upload. - `branch`: (Optional) Filter for the Bitrise CI branch. - `distribution_ready`: (Optional) Filter for distribution ready artifacts. - `items_per_page`: (Optional) Maximum number of artifacts per page. - `page`: (Optional) Page number to return. - `platform`: (Optional) Filter for a specific mobile platform. - `search`: (Optional) Search by version, filename or build number. - `source`: (Optional) Filter for the source of installable artifacts. - `store_signed`: (Optional) Filter for store ready installable artifacts. - `version`: (Optional) Filter for a specific version. - `workflow`: (Optional) Filter for a specific Bitrise CI workflow. 51. `generate_installable_artifact_upload_url` - Generates a signed upload URL for an installable artifact to be uploaded to Bitrise. - Arguments: - `connected_app_id`: Identifier of the Release Management connected app. - `installable_artifact_id`: An uuidv4 identifier for the installable artifact. - `file_name`: The name of the installable artifact file. - `file_size_bytes`: The byte size of the installable artifact file. - `branch`: (Optional) Name of the CI branch. - `with_public_page`: (Optional) Enable public install page. - `workflow`: (Optional) Name of the CI workflow. 52. `get_installable_artifact_upload_and_processing_status` - Gets the processing and upload status of an installable artifact. - Arguments: - `connected_app_id`: Identifier of the Release Management connected app. - `installable_artifact_id`: The uuidv4 identifier for the installable artifact. 53. `set_installable_artifact_public_install_page` - Changes whether public install page should be available for the installable artifact. - Arguments: - `connected_app_id`: Identifier of the Release Management connected app. - `installable_artifact_id`: The uuidv4 identifier for the installable artifact. - `with_public_page`: Boolean flag for enabling/disabling public install page. 54. `list_build_distribution_versions` - Lists Build Distribution versions available for testers. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `items_per_page`: (Optional) Maximum number of versions per page. - `page`: (Optional) Page number to return. 55. `list_build_distribution_version_test_builds` - Gives back a list of test builds for the given build distribution version. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `version`: The version of the build distribution. - `items_per_page`: (Optional) Maximum number of test builds per page. - `page`: (Optional) Page number to return. 56. `create_tester_group` - Creates a tester group for a Release Management connected app. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `name`: The name for the new tester group. - `auto_notify`: (Optional) Indicates automatic notifications for the group. 57. `notify_tester_group` - Notifies a tester group about a new test build. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `id`: The uuidV4 identifier of the tester group. - `test_build_id`: The unique identifier of the test build. 58. `add_testers_to_tester_group` - Adds testers to a tester group of a connected app. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `id`: The uuidV4 identifier of the tester group. - `user_slugs`: The list of users identified by slugs to be added. 59. `update_tester_group` - Updates the given tester group settings. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `id`: The uuidV4 identifier of the tester group. - `auto_notify`: (Optional) Setting for automatic email notifications. - `name`: (Optional) The new name for the tester group. 60. `list_tester_groups` - Gives back a list of tester groups related to a specific connected app. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `items_per_page`: (Optional) Maximum number of tester groups per page. - `page`: (Optional) Page number to return. 61. `get_tester_group` - Gives back the details of the selected tester group. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `id`: The uuidV4 identifier of the tester group. 62. `get_potential_testers` - Gets a list of potential testers who can be added to a specific tester group. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `id`: The uuidV4 identifier of the tester group. - `items_per_page`: (Optional) Maximum number of potential testers per page. - `page`: (Optional) Page number to return. - `search`: (Optional) Search for testers by email or username. 63. `get_testers` - Gets a list of testers that have been associated with a tester group related to a specific connected app. - Arguments: - `connected_app_id`: The uuidV4 identifier of the connected app. - `tester_group_id`: (Optional) The uuidV4 identifier of a tester group. If given, only testers within this specific tester group will be returned. - `items_per_page`: (Optional) Maximum number of testers per page (default: 10). - `page`: (Optional) Page number to return (default: 1). #### Configuration 64. `validate_bitrise_yml` - Validate a Bitrise YML config file. This endpoint checks if the provided bitrise.yml is valid. - Arguments: - `bitrise_yml`: The Bitrise YML config file content to be validated. It must be a string. - `app_slug` (optional): Slug of a Bitrise app. Specifying this value allows for validating the YML against workspace-specific settings like available stacks, machine types, license pools etc. 65. `step_search` - Find steps for building workflows or step bundles in a Bitrise YML config file. Finds steps based on name, description, tags or maintainers. - Arguments: - `query`: The phrase to search steps for like `clone`, `npm`, `deploy` etc. - `categories` (optional): Categories to filter steps. Available values: `build`, `code-sign`, `test`, `deploy`, `notification`, `access-control`, `artifact-info`, `installer`, `dependency`, `utility` - `maintainers` (optional): Filter steps by maintainers. Available values: `bitrise`, `verified`, `community` 66. `step_inputs` - List inputs of a step with their defaults, allowed values etc. - Arguments: - `step_ref`: Step reference formatted as `step_lib_source::step_id@version`. `step_id` and an exact `version` are required, `step_lib_source` is only necessary for custom step sources. 67. `list_available_stacks` - List available stacks with their machine configurations and version information. When a workspace_slug is provided, returns stacks available for that workspace including any custom stacks. When omitted, returns globally available stacks. - Arguments: - `workspace_slug` (optional): Slug of the Bitrise workspace. When provided, lists stacks available for that workspace (including custom stacks). When omitted, lists globally available stacks. #### CodePush 68. `codepush_list_deployments` - List CodePush deployments for a Bitrise app. - Arguments: - `app_id`: Identifier of the Bitrise app. - `search`: (Optional) Search deployments by name. The filter is case-sensitive. - `items_per_page`: (Optional) Maximum number of deployments per page (default: 10). - `page`: (Optional) Page number to return (default: 1). 69. `codepush_get_deployment` - Get a specific CodePush deployment by its ID. - Arguments: - `id`: Identifier (UUID) of the CodePush deployment. 70. `codepush_create_deployment` - Create a new CodePush deployment for a Bitrise app. - Arguments: - `name`: Name for the new deployment. - `app_id`: Identifier of the Bitrise app. - `key`: (Optional) Deployment key. Auto-generated if not provided. 71. `codepush_update_deployment` - Update the name of an existing CodePush deployment. - Arguments: - `id`: Identifier (UUID) of the CodePush deployment. - `name`: New name for the deployment. 72. `codepush_delete_deployment` - Delete a CodePush deployment. This action is irreversible. - Arguments: - `id`: Identifier (UUID) of the CodePush deployment to delete. 73. `codepush_promote_deployment` - Promote a package from a source deployment to a target deployment. The most recent package in the source deployment is promoted unless package_id is specified. - Arguments: - `id`: Identifier (UUID) of the source deployment. - `target_deployment_id`: Identifier (UUID) of the target deployment. - `package_id`: (Optional) UUID of a specific package to promote. Defaults to most recent. - `app_version`: (Optional) Semver app version constraint for the promoted package. - `description`: (Optional) Description for the promoted package. - `disabled`: (Optional) If true, clients will not download this update. - `mandatory`: (Optional) If true, clients must install immediately. - `rollout`: (Optional) Percentage (0-100) of users who receive this update. 74. `codepush_rollback_deployment` - Rollback a CodePush deployment to its previous version. - Arguments: - `id`: Identifier (UUID) of the CodePush deployment to rollback. - `package_id`: (Optional) UUID of a specific package to rollback to. Defaults to the previous package. 75. `codepush_list_updates` - List CodePush updates for a specific deployment. - Arguments: - `deployment_id`: Identifier (UUID) of the CodePush deployment. - `search`: (Optional) Search updates by label or description. The filter is case-sensitive. - `items_per_page`: (Optional) Maximum number of updates per page (default: 10). - `page`: (Optional) Page number to return (default: 1). 76. `codepush_get_update` - Get a specific CodePush update by its ID. - Arguments: - `id`: Identifier (UUID) of the CodePush update. 77. `codepush_patch_update` - Patch a CodePush update to change its disabled state, mandatory flag, or rollout percentage. Only include fields you want to change — omitted fields are left unchanged. - Arguments: - `id`: Identifier (UUID) of the CodePush update. - `disabled`: (Optional) Set to 'true' to disable or 'false' to re-enable. - `mandatory`: (Optional) Set to 'true' to make mandatory or 'false' to make optional. - `rollout`: (Optional) Percentage (0-100) of users who receive this update. 78. `codepush_delete_update` - Delete a CodePush update. This action is irreversible. - Arguments: - `id`: Identifier (UUID) of the CodePush update to delete. 79. `codepush_get_update_status` - Get the processing status of a CodePush update (e.g. pending, ready, failed). - Arguments: - `id`: Identifier (UUID) of the CodePush update. 80. `codepush_generate_update_upload_url` - Generate a signed upload URL (valid 1 hour) for uploading a CodePush update bundle. The response contains the URL, HTTP method, and headers needed for a direct upload. After uploading, check status with `codepush_get_update_status`. - Arguments: - `id`: Client-generated UUID for the new update. - `deployment_id`: Identifier (UUID) of the deployment this update belongs to. - `app_version`: Semver version of the app this update targets (e.g. '1.2.3'). - `file_name`: File name of the update bundle to be uploaded (with extension). - `file_size_bytes`: Byte size of the update bundle file as a string. - `description`: (Optional) Description for this update. - `disabled`: (Optional) If true, clients will not download this update after upload. - `mandatory`: (Optional) If true, clients must install this update immediately. - `rollout`: (Optional) Percentage (0-100) of users who receive this update. Defaults to 100. 81. `codepush_get_metrics` - Get workspace-level CodePush usage metrics including data transfer, storage, and monthly active users, along with their limits and billing cycle information. - Arguments: - `workspace_slug`: Slug of the Bitrise workspace. ### API Groups The Bitrise MCP server organizes tools into API groups that can be enabled or disabled via command-line arguments. The table below shows which API groups each tool belongs to: | Tool | apps | builds | workspaces | outgoing-webhooks | artifacts | group-roles | cache-items | pipelines | account | read-only | release-management | configuration | release-management-code-push | |------|------|--------|------------|-------------------|-----------|-------------|-------------|-----------|---------|-----------|--------------------|--------------|------------------------------| | list_apps | ✅ | | | | | | | | | ✅ | | | | | register_app | ✅ | | | | | | | | | | | | | | finish_bitrise_app | ✅ | | | | | | | | | | | | | | get_app | ✅ | | | | | | | | | ✅ | | | | | delete_app | ✅ | | | | | | | | | | | | | | update_app | ✅ | | | | | | | | | | | | | | get_bitrise_yml | ✅ | | | | | | | | | ✅ | | | | | update_bitrise_yml | ✅ | | | | | | | | | | | | | | list_branches | ✅ | | | | | | | | | ✅ | | | | | register_ssh_key | ✅ | | | | | | | | | | | | | | register_webhook | ✅ | | | | | | | | | | | | | | list_builds | | ✅ | | | | | | | | ✅ | | | | | trigger_bitrise_build | | ✅ | | | | | | | | | | | | | get_build | | ✅ | | | | | | | | ✅ | | | | | abort_build | | ✅ | | | | | | | | | | | | | get_build_log | | ✅ | | | | | | | | ✅ | | | | | get_build_bitrise_yml | | ✅ | | | | | | | | ✅ | | | | | list_build_workflows | | ✅ | | | | | | | | ✅ | | | | | get_build_steps | | ✅ | | | | | | | | ✅ | | | | | list_artifacts | | | | | ✅ | | | | | ✅ | | | | | get_artifact | | | | | ✅ | | | | | ✅ | | | | | delete_artifact | | | | | ✅ | | | | | | | | | | update_artifact | | | | | ✅ | | | | | | | | | | list_outgoing_webhooks | | | | ✅ | | | | | | ✅ | | | | | delete_outgoing_webhook | | | | ✅ | | | | | | | | | | | update_outgoing_webhook | | | | ✅ | | | | | | | | | | | create_outgoing_webhook | | | | ✅ | | | | | | | | | | | list_cache_items | | | | | | | ✅ | | | ✅ | | | | | delete_all_cache_items | | | | | | | ✅ | | | | | | | | delete_cache_item | | | | | | | ✅ | | | | | | | | get_cache_item_download_url | | | | | | | ✅ | | | ✅ | | | | | list_pipelines | | | | | | | | ✅ | | ✅ | | | | | get_pipeline | | | | | | | | ✅ | | ✅ | | | | | abort_pipeline | | | | | | | | ✅ | | | | | | | rebuild_pipeline | | | | | | | | ✅ | | | | | | | list_group_roles | | | | | | ✅ | | | | ✅ | | | | | replace_group_roles | | | | | | ✅ | | | | | | | | | list_workspaces | | | ✅ | | | | | | | ✅ | | | | | get_workspace | | | ✅ | | | | | | | ✅ | | | | | get_workspace_groups | | | ✅ | | | | | | | ✅ | | | | | create_workspace_group | | | ✅ | | | | | | | | | | | | get_workspace_members | | | ✅ | | | | | | | ✅ | | | | | invite_member_to_workspace | | | ✅ | | | | | | | | | | | | add_member_to_group | | | ✅ | | | | | | | | | | | | me | | | | | | | | | ✅ | ✅ | | | | | create_connected_app | | | | | | | | | | | ✅ | | | | list_connected_apps | | | | | | | | | | ✅ | ✅ | | | | get_connected_app | | | | | | | | | | ✅ | ✅ | | | | update_connected_app | | | | | | | | | | | ✅ | | | | list_installable_artifacts | | | | | | | | | | ✅ | ✅ | | | | generate_installable_artifact_upload_url | | | | | | | | | | | ✅ | | | | get_installable_artifact_upload_and_processing_status | | | | | | | | | | ✅ | ✅ | | | | set_installable_artifact_public_install_page | | | | | | | | | | | ✅ | | | | list_build_distribution_versions | | | | | | | | | | ✅ | ✅ | | | | list_build_distribution_version_test_builds | | | | | | | | | | ✅ | ✅ | | | | create_tester_group | | | | | | | | | | | ✅ | | | | notify_tester_group | | | | | | | | | | | ✅ | | | | add_testers_to_tester_group | | | | | | | | | | | ✅ | | | | update_tester_group | | | | | | | | | | | ✅ | | | | list_tester_groups | | | | | | | | | | ✅ | ✅ | | | | get_tester_group | | | | | | | | | | ✅ | ✅ | | | | get_potential_testers | | | | | | | | | | ✅ | ✅ | | | | get_testers | | | | | | | | | | ✅ | ✅ | | | | validate_bitrise_yml | | | | | | | | | | ✅ | | ✅ | | | step_search | | | | | | | | | | ✅ | | ✅ | | | step_inputs | | | | | | | | | | ✅ | | ✅ | | | list_available_stacks | | | | | | | | | | ✅ | | ✅ | | | codepush_list_deployments | | | | | | | | | | ✅ | ✅ | | ✅ | | codepush_get_deployment | | | | | | | | | | ✅ | ✅ | | ✅ | | codepush_create_deployment | | | | | | | | | | | ✅ | | ✅ | | codepush_update_deployment | | | | | | | | | | | ✅ | | ✅ | | codepush_delete_deployment | | | | | | | | | | | ✅ | | ✅ | | codepush_promote_deployment | | | | | | | | | | | ✅ | | ✅ | | codepush_rollback_deployment | | | | | | | | | | | ✅ | | ✅ | | codepush_list_updates | | | | | | | | | | ✅ | ✅ | | ✅ | | codepush_get_update | | | | | | | | | | ✅ | ✅ | | ✅ | | codepush_patch_update | | | | | | | | | | | ✅ | | ✅ | | codepush_delete_update | | | | | | | | | | | ✅ | | ✅ | | codepush_get_update_status | | | | | | | | | | ✅ | ✅ | | ✅ | | codepush_generate_update_upload_url | | | | | | | | | | | ✅ | | ✅ | | codepush_get_metrics | | | | | | | | | | ✅ | ✅ | | ✅ | --- ## Enabling AI features on Bitrise To enable AI features: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **AI settings**. 1. Toggle **Enable AI features**. --- ## Onboarding for agents Bitrise is mobile-focused CI/CD and app distribution for iOS and Android, including Flutter and React Native. If you work through an AI agent such as Claude Code, Cursor, or VS Code with GitHub Copilot, it can connect you to Bitrise without leaving the chat, using the [Bitrise MCP server](/bitrise-platform/ai/bitrise-mcp). The first time your agent needs access, your client prompts you to authorize it and starts a Bitrise sign-in in your browser. You sign in — or create an account — once, approve the connection, and your agent is authorized. The same sign-in also logs you into the Bitrise website, so there's nothing to set up twice. ### When to use this You want to use Bitrise for CI/CD, app distribution, or getting a local build onto devices, and one of the following is true: - You don't have a Bitrise account yet, so you create one during the browser sign-in — with GitHub, Bitbucket, Google, another social SSO, or an email and password. - You already have an account, so you just sign in and approve the connection. Either way it's the same flow: your agent points you at a browser page, and you finish there. If you'd rather not use an agent, you can also [sign up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) in the browser. ### Connecting through the MCP The MCP server uses OAuth: it tells your client that it needs authorization, and your client runs the browser sign-in for you. You never copy or paste a token. #### Step 1: Get an AI client that supports MCP You need an AI client that supports MCP. Each step below gives the configuration for the most common clients: Claude Code, Cursor, VS Code, and Claude Desktop. Bitrise MCP also supports [Windsurf](/bitrise-platform/ai/bitrise-mcp/installing-the-bitrise-mcp-server/install-windsurf), the [Google Gemini CLI](/bitrise-platform/ai/bitrise-mcp/installing-the-bitrise-mcp-server/install-gemini-cli), [AWS Kiro](/bitrise-platform/ai/bitrise-mcp/installing-the-bitrise-mcp-server/install-kiro), and [other Copilot IDEs](/bitrise-platform/ai/bitrise-mcp/installing-the-bitrise-mcp-server/install-other-copilot-ides). See each install guide for client-specific details. #### Step 2: Connect the MCP server Point your client at the remote server with **no token**. The server tells your client it's OAuth-protected, and your client handles authorization from there. After editing the config, reload the client so the change takes effect (see [Reconnecting the MCP client](#reconnecting-the-mcp-client)). **Claude Code** ```bash claude mcp add --transport http bitrise https://mcp.bitrise.io ``` Full setup: [Claude Applications](/bitrise-platform/ai/bitrise-mcp/installing-the-bitrise-mcp-server/install-claude). **Cursor** ```json { "mcpServers": { "bitrise": { "url": "https://mcp.bitrise.io" } } } ``` Full setup: [Cursor](/bitrise-platform/ai/bitrise-mcp/installing-the-bitrise-mcp-server/install-cursor). **VS Code** ```json { "servers": { "bitrise": { "type": "http", "url": "https://mcp.bitrise.io" } } } ``` Full setup: [VS Code](/bitrise-platform/ai/bitrise-mcp/installing-the-bitrise-mcp-server/install-vscode). **Claude Desktop** ```json { "mcpServers": { "bitrise": { "command": "npx", "args": ["mcp-remote", "https://mcp.bitrise.io"] } } } ``` Full setup: [Claude Applications](/bitrise-platform/ai/bitrise-mcp/installing-the-bitrise-mcp-server/install-claude). #### Step 3: Sign in or create your account The server requires authorization, so it won't connect anonymously — your agent can't sign you in on its own. When your client connects (after the reload in Step 2), it detects that Bitrise needs authorization and starts the sign-in in your browser. How you start it differs by client — in Claude Code, run `/mcp`, select **bitrise**, and start the sign-in. On the Bitrise sign-in page: 1. **Sign in or sign up.** Choose **GitHub**, **Bitbucket**, **Google**, or another social provider, or use an **email and password**. You can create a brand-new account right here — there's no separate website sign-up. 2. **Approve the connection.** Bitrise shows a consent screen naming the application that's asking for access. Approve it to continue. When you approve, your browser hands the authorization back to your agent automatically. There's nothing to copy or paste. :::tip[Your website session comes with it] Signing in here also signs you in on [app.bitrise.io](https://app.bitrise.io) in the same browser, so you won't be asked to log in again when you open the dashboard. ::: #### Step 4: Confirm your email (email and password only) If you created your account with an email and password, Bitrise sends a confirmation email **immediately** and shows a "confirm your email" screen. Social sign-ins (GitHub, Bitbucket, Google) skip this step — they're already verified by the provider. - Open the email on **any device** — the computer running your agent, your phone, whatever's handy — and click the confirmation link. - The confirmation screen **polls for you**, so it doesn't matter where you click the link. Once your email is confirmed, the screen detects it within a few seconds, reloads itself, and continues the authorization automatically. - You don't need to return to the original window or re-enter anything. When confirmation lands, the flow picks up where it left off. #### Step 5: Confirm the connection Once you're authorized, your agent can call any enabled Bitrise tool. Confirm the connection by asking it to run the `me` or `list_workspaces` tools. If you're new, a Workspace is created for you automatically. To see how Workspaces organize your apps and team, read the [Workspaces overview](/bitrise-platform/workspaces/workspaces-overview). ### Using a personal access token instead The OAuth flow issues and refreshes short-lived tokens behind the scenes, so you stay connected without managing credentials. If your client ever loses authorization (for example after a long idle period), it simply reopens the browser sign-in. If you prefer a fixed credential — for CI, scripts, or a client that doesn't support OAuth — create a durable [personal access token](/bitrise-platform/accounts/personal-access-tokens) at [Account settings → Security](https://app.bitrise.io/me/account/security) and add it as an `Authorization` header instead of relying on OAuth: **Claude Code** ```bash claude mcp remove bitrise && claude mcp add --transport http bitrise https://mcp.bitrise.io -H "Authorization: Bearer " ``` **Cursor** ```json { "mcpServers": { "bitrise": { "url": "https://mcp.bitrise.io", "headers": { "Authorization": "Bearer " } } } } ``` **VS Code** ```json { "servers": { "bitrise": { "type": "http", "url": "https://mcp.bitrise.io", "headers": { "Authorization": "Bearer " } } } } ``` **Claude Desktop** ```json { "mcpServers": { "bitrise": { "command": "npx", "args": ["mcp-remote", "https://mcp.bitrise.io", "--header", "Authorization: Bearer "] } } } ``` ### Reconnecting the MCP client Editing the config in Step 2 takes effect only after the client reloads the Bitrise MCP server. Some clients also surface the OAuth sign-in here (for example, Claude Code's `/mcp` is where you authenticate). How you reload depends on the client: - **Claude Code (CLI):** Run `/mcp` to view, reconnect, and authenticate the server, or quit and relaunch `claude`. - **VS Code (GitHub Copilot):** Open the Command Palette (`Cmd/Ctrl+Shift+P`), run **MCP: List Servers**, select **bitrise**, and choose **Restart**, or run **Developer: Reload Window**. - **Cursor:** Open **Settings → MCP (Tools)** and toggle the **bitrise** server off and on, or click its refresh icon. Restarting Cursor also works. - **Claude Desktop:** Quit the app fully (`Cmd+Q` on macOS, or quit from the system tray on Windows) and reopen it. Closing the window alone doesn't reload it. - **Other clients (Windsurf, Gemini CLI, AWS Kiro):** Restart the client, or its MCP connection if it exposes one. ### If something goes wrong - **No sign-in prompt appeared:** Reload the MCP server in your client (see [Reconnecting the MCP client](#reconnecting-the-mcp-client)) to re-trigger the authorization prompt — in Claude Code, run `/mcp` and start the sign-in for **bitrise**. - **You closed the page before approving:** Trigger any Bitrise tool again and your client restarts the sign-in. - **You're stuck on the "confirm your email" screen:** Click the confirmation link in the email Bitrise sent (check your spam folder). The screen polls every few seconds and continues on its own once your email is confirmed — there's no need to refresh. - **"This email is already registered" during sign-up:** You already have a Bitrise account. Go back and **sign in** with that provider or email instead of creating a new one. ### After your account is created The same MCP connection now drives the rest of Bitrise: [creating apps and connecting repositories](/bitrise-ci/getting-started/adding-a-new-project), [configuring `bitrise.yml`](/bitrise-ci/configure-builds/configuration-yaml/configuration-yaml-overview), triggering builds, reading logs, and managing artifacts and distribution. You can also limit which tool groups the server exposes, as described in [Tools](/bitrise-platform/ai/bitrise-mcp/tools). For conventions and a guided walkthrough of connecting your repository and running your first build, install the Bitrise agent skill: ```bash npx skills add bitrise-io/agent-skills ``` This installs the `using-bitrise-ci` skill, which loads automatically on Bitrise CI topics. Invoke it explicitly with `/using-bitrise-ci`, or add `--global` to install it across all your projects. New to Bitrise? Start with [Getting started](/bitrise-ci/getting-started/getting-started) and the [key Bitrise concepts](/bitrise-ci/getting-started/key-bitrise-concepts). To see what else Bitrise can do with AI, see [AI features on Bitrise](/bitrise-platform/ai/ai-features-on-bitrise). ### Related links - [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp): what the MCP server is and how to authenticate. - [Tools](/bitrise-platform/ai/bitrise-mcp/tools): enable or disable specific tool groups. - [Bitrise MCP repository](https://github.com/bitrise-io/bitrise-mcp): source, install guides, and the tool reference. - [Bitrise agent skills](https://github.com/bitrise-io/agent-skills): the `using-bitrise-ci` knowledge skill. --- ## Collaboration Collaboration is the way different people can work on Bitrise projects together. Bitrise offers multiple levels of collaboration options, with different product solutions having their own fine-grained collaboration features. Collaboration covers: - Membership in Bitrise workspaces, including workspace groups. - Roles and permissions in Bitrise workspaces: actions that users with different access levels can perform. - Product access: you can restrict users to access only Bitrise CI or Release Management. - Roles and permissions in projects, including CI configurations and Release Management apps. ### Collaboration in workspaces The main organizing entity of Bitrise is the workspace. Workspaces own projects, you can connect third-party integrations on workspace level, and you can set up collaboration in a workspace. #### Workspace owners Each workspace has at least one owner: by default, it's the account that created the workspace. Owners have full control over all aspects of the workspace, including collaboration features. For more information, check out [Changing the owners of a Workspace](/bitrise-platform/workspaces/changing-the-owners-of-a-workspace). #### Workspace members You can add individual members to workspaces. You can assign product access and project roles to members: - Product access means selecting the products the member can work on. For example, you can configure members to only have access to Bitrise CI, not Release Management. - Project roles mean the roles and permissions on the specific projects owned by the workspace. You can assign different roles and permissions for different projects. Within the same project, you can assign different roles for Bitrise CI and Release Management, even if the member has access to both products. As such, even if your workspace has hundreds of projects, you can configure fine-grained access for team members so they only see the products and projects that they need. For more information, check out [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). #### Workspace groups Workspace groups are made up of workspace members. Groups make it easy to manage product and project access in bulk. You don't need to set up specific fine-grained access for every member separately; instead, you invite a member and then add them to a group with the required permissions. Just like members, groups can be restricted to certain products and projects. Groups can be assigned roles and permissions on projects: this means that all members in the group will be assigned those roles and permissions. Group permissions don't override workspace member permissions. For example, let's say that: - A user is part of a group that has Developer access to a CI project. - The same user has Admin access to the same CI project as a workspace member. In this case, the user will have Admin access to the project. For more information, check out [Workspace groups](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups). #### Outside contributors in workspaces Outside contributors are users who aren't members of the workspace but they are added to one or more projects that the workspace owns. These users won't have access to the workspace itself, only the assigned projects. Their roles and permissions can be configured only on the **Project settings** page. Outside contributors are allowed by default for new workspaces, but this can be turned off on the **Workspace settings** page. #### Workspace roles When inviting someone to a workspace, you can also assign a workspace role to them. Workspace roles define the users' access to the workspace itself, what actions the users can perform. For example, a user with the **Manager** role can update workspace integrations, add or remove members but can't access billing details. For more information, check out [Roles and permissions in workspaces](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces). ### Collaboration in projects Project-level collaboration means users working together on a Bitrise project. User can have different roles and permissions within the same project. If the project has both a CI configuration and a Release Management app, you can configure separate access for those two products. Project collaboration is defined in two ways: by adding contributors and by assigning workspace groups to the project. #### Project contributors A project contributor is a user who is individually assigned to a project, not as part of a group. A contributor can be a member of the workspace that owns the project, or they can be an outside contributor. Outside contributors can be added only if the feature is enabled for the workspace that owns the project. Contributors are assigned their own roles and permissions to the project. You can add workspace members as contributors to a project either from the **Workspace settings** page or the **Project settings** page. Outside contributors can only be added on the **Project settings** page. For details, check out [Managing user access to a project](/bitrise-platform/projects/managing-user-access-to-a-project). #### Groups Groups are workspace groups: you can assign workspace groups to any project owned by the workspace. On the project level, this means that every member of the group will have the same roles and permissions that the group has on the project. You can assign workspace groups to projects either from the **Workspace settings** page or **Project settings** page. For details, check out [Managing user access to a project](/bitrise-platform/projects/managing-user-access-to-a-project). #### Roles and permissions in projects Projects have no separate roles just for project access: roles and permissions are based on product access. Bitrise CI and Release Management both have their own set of roles and permissions. Each contributor and group can be assigned separate roles for these two products. There is one exception: you can grant a user or group full **Admin** access to a project. **Admin** access means managing all aspects of a project, with access to all products. This is effectively the same as separately granting the **Admin** role on both Bitrise CI and Release Management. Read more in [Product access](/bitrise-platform/getting-started/collaboration#product-access). ### Product access Collaboration includes roles and permissions: what actions users can perform. On Bitrise, the roles and permissions differ by product: you can configure fine-grained access separately for Bitrise CI and Release Management. Product access is mostly independent of workspace roles and permissions. A user who is an Admin on a CI project or a Release Management app doesn't necessarily have full access to the settings of the workspace that owns the project. The exception to that is Workspace owners: all owners have full access to every aspect of the projects owned by the workspace. #### Admin access You can grant **Admin access** to users and groups to enable them to manage all aspects of one or more selected projects. This includes access to all products, such as Bitrise CI and Release Management. You can configure admin access for users or groups both from the **Workspace settings** page and the **Project settings** page. For details, check out [Updating roles and permissions](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces#managing-roles-and-permissions-in-a-workspace). #### Bitrise CI roles and permissions Bitrise CI has its own set of roles and permissions that define how users can interact with the CI/CD process. Each user or workspace group can be granted access to Bitrise CI and then assigned roles on CI projects. The specific CI roles and permissions define access to things such as project settings, Pipelines, Workflows, and other important parts of CI. For details, check out [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). #### Release Management roles and permissions Release Management has its own set of roles and permissions. These define how users can interact with releases, test distribution, and CodePush. In addition, Release Management has a specific collaboration feature: tester groups. A tester group is a group of users who can automatically receive installable artifacts for testing. Testers have limited permissions and they can only be selected from users who are already members of the project that the Release Management app belongs to. For details, check out [Release Management roles and permissions](/release-management/configuring-connected-apps/release-management-roles-and-permissions). --- ## Getting started with the Bitrise platform The Bitrise platform is organized around accounts, workspaces, and projects. We'll quickly go through how to start using them. ### Signing up You can sign up via email, one of three Git providers (GitHub, GitLab, or Bitbucket), or a Google account: [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise). Bitrise also supports SAML SSO: [SAML SSO in Bitrise](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise). After signing up, you receive a limited trial: ### First workspace After signing up, we automatically create your first workspace. This workspace is owned by your user account. You can create additional workspaces at any point and be invited to other workspaces. Workspaces are very important in Bitrise: all your work is organized in workspaces. You can: - Add users and organize them into user groups: [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration) - Configure workspace-level integrations for third-party services such as the Apple Store or Google Play: [About integrations](/bitrise-platform/integrations/about-integrations). - Create projects for Bitrise CI and Release Management. ### Projects When you have your first workspace, you will be prompted to add your first project. ![gettingstarted.png](/img/_paligo/uuid-4f8203e0-c79b-b9ec-7537-53e96b0f1924.png) There are two ways of creating a new project: - Starting with Bitrise CI: you will be automatically taken to the **Add new project** flow. This creates a CI project with a linked Git repository: [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project). - Starting with Release Management: you can add a new app to Release Management and Bitrise will automatically link it to a new project: [Adding a new app to Release Management](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management). This project will not have a CI configuration but you can extend it with one. The **Build Cache** card on this screen isn't a third way to create a project — it takes you to Build Cache setup, which requires a Bitrise CI project to already exist. Configure your project by entering **Project settings**. You can access it from both Bitrise CI and from Release Management. ### Integrations Integrating to third-party tools and services is a vital part of the Mobile DevOps process. We recommend setting up the most important integrations once your first project is up and running: - [The service credential user](/bitrise-platform/integrations/the-service-credential-user) - [Repository access with OAuth](/bitrise-platform/repository-access/repository-access-with-oauth) - [About connecting to Apple services](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) - [Connecting a Google service account to Bitrise](/bitrise-platform/integrations/connecting-a-google-service-account-to-bitrise) --- ## Key concepts of the Bitrise platform The Bitrise Mobile DevOps platform equips users for every step of the mobile development process, from planning to monitoring. It has a few key concepts that help understanding the overall structure of the platform. ### Workspaces [A workspace](/bitrise-platform/workspaces/workspaces-overview) is an environment that allows you to manage your Bitrise projects and the team members working on the projects. To use any of the Bitrise product solutions, you need a workspace. Everything you see on the Bitrise Dashboard belongs to a selected workspace. Each workspace has an owner, and members can be assigned a workspace role — Viewer, Contributor, or Manager — that defines their access to the workspace itself. Members can be sorted into groups: groups allow owners to quickly assign large teams to specific projects. ### Projects [A Bitrise project](/bitrise-platform/projects/projects-overview) is the container for the entire Mobile DevOps process of your development work. Each workspace can own multiple projects. A project allows you to: - Create a CI configuration: a project's CI configuration is tied to a Git repository. - Set up Release Management to distribute your mobile app to testers and to online stores. Projects can add individual users and workspace groups as collaborators with granular access rights. ### Accounts A user account belongs to an individual user. User accounts can't own projects: each user account must be part of a workspace to be able to work on the Bitrise platform. User accounts don't have subscription plans or Release Management licenses: these are tied to workspaces, and Release Management apps, respectively. You can invite individual users to both project teams and workspaces. --- ## Signing up for Bitrise :::tip[Onboarding with an AI agent] If you're setting up Bitrise through an AI agent or coding assistant, such as Claude Code or Cursor, you don't need to sign up here first. Your agent points you at a Bitrise sign-in page where you can create your account, and it's connected automatically once you approve it. Follow the [Bitrise for AI agents onboarding runbook](/bitrise-platform/ai/onboarding-for-agents) instead of this guide. ::: You can sign up for Bitrise either via an email address or by authenticating yourself with your GitHub, Bitbucket, GitLab, or Google account. Signing up using a Git provider account brings some practical benefits, like logging in with one click and of course you won’t have to authorize your Git account when adding repositories hosted by these providers again. ### Signing up with a Git provider 1. You can sign up for Bitrise through the **Start for free** button in the upper right corner of [Bitrise](https://www.bitrise.io/). It will take you to the **Sign up** page. 1. On the **Sign up** page, scroll down to the **Or sign up with your git provider** section where you can pick a git provider. 1. Authorize your selected Git provider. - If you chose GitHub, press the **Authorize bitrise-io** button, and then you will be redirected to Bitrise. ![authorize_github.png](/img/_paligo/uuid-245d62ac-c277-cae8-0f6d-6d60ae23bb70.png) - If you chose Bitbucket, press the **Grant access** button on Bitbucket, and then you will be redirected to Bitrise. ![authorize-bitbucket.png](/img/_paligo/uuid-2b51312c-d04b-29f9-c83a-14dcfa9306d2.png) - If you chose GitLab, press the **Authorize** button, and then you will be redirected to Bitrise. ![authorize-gitlab.png](/img/_paligo/uuid-78feab6d-8731-8d33-b453-bbf6b14a781c.png) 1. Pick a username and a password. When done, click **Sign up**. :::important[Strong password] Please note that you must provide a **strong password** which fulfills these requirements: - It should have at least 8 characters. - One upper case character. - One lower case character. - One number. - Cannot contain the same character more than 3 times in a row (aaa). - Cannot contain your email or username. ::: After that, you are ready to roll. Your first workspace will be created automatically, and you will be redirected to the **Getting Started** page, where you can start with Bitrise CI, Build Cache, or Release Management. ### Signing up with email 1. You can sign up for Bitrise through the **Start for free** button in the upper right corner of [Bitrise](https://www.bitrise.io/). It will take you to the **Sign up** page. 1. Add your email address, username, and password. :::important[Strong password] Please note that you must provide a **strong password** which fulfills these requirements: - It should have at least 8 characters. - One upper case character. - One lower case character. - One number. - Cannot contain the same character more than 3 times in a row (aaa). - Cannot contain your email or username. ::: 1. Check the **I agree to the Bitrise Terms of Service**, and click the **Sign up** button. 1. Check your inbox for a confirmation email from Bitrise and follow the instructions there. If you haven’t received a confirmation email from us, click the **Re-send confirmation email** button. ![checkyourinbox.png](/img/_paligo/uuid-06a9ef1f-701a-678b-cc0c-8aad5c078cd2.png) And that's it! After confirming your account, your first Workspace will be created automatically, and you will be redirected to the **Getting Started** page, where you can start with Bitrise CI, Build Cache, or Release Management. ![gettingstarted.png](/img/_paligo/uuid-4f8203e0-c79b-b9ec-7537-53e96b0f1924.png) --- ## Bitrise Platform --- ## AWS CloudFormation templates [AWS CloudFormation](https://aws.amazon.com/cloudformation/) simplifies the one-click provisioning and management of the Bitrise Cloud Controller on AWS. When the CloudFormation template is deployed into a customer VPC, it creates the Bitrise Cloud Controller and the accompanying infrastructure. ![cloudformation.png](/img/_paligo/uuid-f52635e0-c0c6-f09a-042a-4d8e785fb35c.png) Bitrise maintains CloudFormation templates for different use cases: - **Deploy Cloud Controller to an existing VPC:** Choose this template if the user has an established AWS presence with already built-out networking. - **Deploy Cloud Controller into a brand new VPC**: Choose this template if the user is new to AWS or doesn’t have an already built-out networking. This template creates a new VPC first (based on customer preferences) and then deploys the controller into it. - **Deploy Airgapped Cloud Controller to an existing VPC**: Choose this template if the user has an established AWS presence with already built-out networking and would like to run the controller in a strictly [airgapped environment](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates). This is not fully automated: some [manual configuration is needed](#deploy-airgapped-cloud-controller-to-an-existing-vpc). - **Deploy Airgapped Cloud Controller into a brand new VPC**: Choose this template if the user is new to AWS or doesn’t have an already built-out networking and would like to run the controller in a strictly [airgapped environment](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates). This template creates a new VPC first with the correct airgapped configuration and then deploys the controller into it. ### Deploy CloudController to an existing VPC Template parameters: - **Stack Name** (required): Identifies the Bitrise Cloud Controller parent stack within the AWS Account. - **Latest AMI ID**: This AMI ID is used as a base AMI to run the Cloud Controller on. - **BitriseControllerToken** (required): The controller token the user receives when creating a controller on the Bitrise Website. - **BitriseWorkspaceID** (required): The workspace ID belonging to the customer’s Bitrise account. - **ControllerLogGroupClass** (required): The controller saves error logs to a CloudWatch log group within the customer AWS Account. The customer controls which [Log Group Class](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatch_Logs_Log_Classes.html) fits their budget the most. The default value should be suitable for most of the cases. Default: `INFREQUENT_ACCESS`. - **ControllerLogRetentionInDays** (required): The number of days CloudWatch should retain the Controller error logs. Default: 7 (days). - **ControllerSshKey** (required): Provides SSH access for the Cloud Controller instance. - **SubnetIds** (required): At least two subnets within the same region but in different AZs. We recommend using private subnets, but public subnets work as well. - **VpcId** (required): The VPC where the controller will be deployed. - **VpcCidrBlock** (required): The CIDR block of the selected VPC. - **CustomBashScript** (optional): Custom bash script to run on instance startup - **UseHostNetwork (required)**: Use host network mode for Docker container (--net=host) #### Infrastructure provisioned by the template - **Internal Application Load Balancer**: Servers have no traffic and only perform periodic health checks on the Cloud Controller instance. In all cases the Controller and the build machines will initiate network calls toward the Bitrise control plane, no external inbound traffic is required. - **Autoscaling Group**: Makes sure that a healthy Cloud Controller instance is running at a time.Instance: a t2.small instance on which the Cloud Controller runs. - **LaunchTemplate**: Cloud Controller instance configuration. Also needed for the controller self-update feature. - **IAM role, instance profile, and policy**: Certain permissions are necessary for the controller to query the build node states. - **AWS Secrets Manager**: The template creates two secrets, respectively, for storing the WorkspaceID and the Controller Token. - **CloudWatch log group**: The template creates a CloudWatch log group for storing Controller error logs. - **Security groups**: The template creates two security groups: one for the LoadBalancer and one for the instance. ### Deploy Cloud Controller to a new VPC Template parameters: - **Stack Name** (required): Identifies the Bitrise Cloud Controller parent stack within the AWS Account. - **Latest AMI ID**: This AMI ID is used as a base AMI to run the Cloud Controller on. - **BitriseControllerToken** (required): The controller token the user receives when creating a controller on the Bitrise Website. - **BitriseWorkspaceID** (required): The workspace ID belonging to the customer’s Bitrise account. - **ControllerLogGroupClass** (required): The controller saves error logs to a CloudWatch log group within the customer AWS Account. The customer controls which [Log Group Class](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatch_Logs_Log_Classes.html) fits their budget the most. The default value should be suitable for most of the cases. Default: `INFREQUENT_ACCESS`. - **ControllerLogRetentionInDays** (required): The number of days CloudWatch should retain the Controller error logs. Default: 7 (days). - **ControllerSshKey** (required): Provides SSH access for the Cloud Controller instance. - **EnvironmentName** (optional): Adds a prefix to each piece of Bitrise-related infrastructure with the Environment Name. In case the customer has a vast number of resources, it might come in handy to be able to distinguish Bitrise-related resources from the rest. - **PrivateSubnet1CIDR** (required): CIDR range of the first private subnet of the new VPC. Default: 10.192.32.0/20. - **PrivateSubnet2CIDR** (required): CIDR range of the second private subnet of the new VPC. Default: 10.192.64.0/20. - **PublicSubnet1CIDR** (required): CIDR range of the first public subnet of the new VPC. Default: 10.192.0.0/20. - **PublicSubnet2CIDR** (required): CIDR range of the second public subnet of the new VPC. Default: 10.192.16.0/20 - **VpcCidrBlock** (required): The CIDR block of the selected VPC. - **CustomBashScript** (optional): Custom bash script to run on instance startup - **UseHostNetwork (required)**: Use host network mode for Docker container (--net=host) #### Infrastructure provisioned by the template - **Internal Application Load Balancer**: Servers have no traffic and only perform periodic health checks on the Cloud Controller instance. In all cases the Controller and the build machines will initiate network calls toward the Bitrise control plane, no external inbound traffic is required. - **Autoscaling Group**: Makes sure that a healthy Cloud Controller instance is running at a time. - **Instance**: a `t2.small` instance on which the Cloud Controller runs. - **LaunchTemplate**: Cloud Controller instance configuration. Also needed for the controller self-update feature. - **IAM role, instance profile, and policy**: Certain permissions are necessary for the controller to query the build node states. - **AWS Secrets Manager**: The template creates two secrets, respectively, for storing the WorkspaceID and the Controller Token. - **CloudWatch log group**: The template creates a CloudWatch log group for storing Controller error logs. - **Security groups**: The template creates two security groups: one for the LoadBalancer and one for the instance. - **VPC**: A standard, general-purpose VPC based on best practices. Choosing the default CIDR block results in subnets with 4096 available IP addresses. The list of VPC-related resources the template creates: - One VPC. - Two public subnets. - Two private subnets. - One NAT Gateway + one Elastic IP. - One Internet Gateway + one Elastic IP. - Routing tables. - **Bitrise Agent Logs**: This functionality allows for seamless sending of Bitrise Agent build logs to AWS CloudWatch. It leverages CloudFormation to automatically set up the necessary IAM roles and policies, ensuring the Bitrise Agent has appropriate permissions. Moreover, it creates a specific log group in CloudWatch named `bitrise-agent-log`, facilitating organized log management and real-time analysis within the AWS environment. ### Deploy Airgapped Cloud Controller to an existing VPC Template parameters: - **Stack Name** (required): Identifies the Bitrise Cloud Controller parent stack within the AWS Account. - **BitriseControllerToken** (required): The controller token the user receives when creating a controller on the Bitrise Website. - **BitriseWorkspaceID** (required): The workspace ID belonging to the customer’s Bitrise account. - **ControllerLogGroupClass** (required): The controller saves error logs to a CloudWatch log group within the customer AWS Account. The customer controls which [Log Group Class](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatch_Logs_Log_Classes.html) fits their budget the most. The default value should be suitable for most of the cases. Default: `INFREQUENT_ACCESS`. - **ControllerLogRetentionInDays** (required): The number of days CloudWatch should retain the Controller error logs. Default: 7 (days). - **ControllerSshKey** (required): Provides SSH access for the Cloud Controller instance. - **SubnetIds** (required): At least two subnets within the same region but in different AZs. We recommend using private subnets, but public subnets work as well. - **VpcId** (required): The VPC where the controller will be deployed. - **VpcCidrBlock** (required): The CIDR block of the selected VPC. - **CustomBashScript** (optional): Custom bash script to run on instance startup - **UseHostNetwork (required)**: Use host network mode for Docker container (--net=host) #### Infrastructure provisioned by the template - **Internal Application Load Balancer**: Servers have no traffic and only perform periodic health checks on the Cloud Controller instance. In all cases the Controller and the build machines will initiate network calls toward the Bitrise control plane, no external inbound traffic is required. - **Autoscaling Group**: Makes sure that a healthy Cloud Controller instance is running at a time.Instance: a t2.small instance on which the Cloud Controller runs. - **Airgapped LaunchTemplate**: Cloud Controller instance configuration. Also needed for the controller self-update feature. - **Airgapped IAM role, instance profile, and policy**: Certain permissions are necessary for the controller to query the build node states and access required Bitrise private ECR. - **AWS Secrets Manager**: The template creates two secrets, respectively, for storing the WorkspaceID and the Controller Token. - **CloudWatch log group**: The template creates a CloudWatch log group for storing Controller error logs. - **Airgapped security groups**: The template creates two security groups: one for the LoadBalancer and one for the instance. - **Bitrise Agent Logs**: This functionality allows for seamless sending of Bitrise Agent build logs to AWS CloudWatch. It leverages CloudFormation to automatically set up the necessary IAM roles and policies, ensuring the Bitrise Agent has appropriate permissions. Moreover, it creates a specific log group in CloudWatch named `bitrise-agent-log`, facilitating organized log management and real-time analysis within the AWS environment. #### Manual configuration for the airgapped template 1. Create the following interface-type VPC endpoints using the configured subnet: Ensure that the private DNS is enabled for all. - `com.amazonaws.${AWS::Region}.autoscaling`: Used for controller self-update. - `com.amazonaws.${AWS::Region}.ec2`: Used for EC2 instance and dedicated host management. - `com.amazonaws.${AWS::Region}.ecr.api`: Used for downloading controller binary from Bitrise private ECR. - `com.amazonaws.${AWS::Region}.ecr.dkr`: Used for downloading controller binary from Bitrise private ECR. - `com.amazonaws.${AWS::Region}.logs`: Used for sending controller logs to CloudWatch. - `com.amazonaws.${AWS::Region}.secretsmanager`: Used for accessing secrets. 1. Apply the created endpoints to the Instance Security group. ### Deploy Airgapped Cloud Controller to a new VPC Template parameters: - **Stack Name** (required): Identifies the Bitrise Cloud Controller parent stack within the AWS Account. - **Latest AMI ID**: This AMI ID is used as a base AMI to run the Cloud Controller on. - **BitriseControllerToken** (required): The controller token the user receives when creating a controller on the Bitrise Website. - **BitriseWorkspaceID** (required): The workspace ID belonging to the customer’s Bitrise account. - **ControllerLogGroupClass** (required): The controller saves error logs to a CloudWatch log group within the customer AWS Account. The customer controls which [Log Group Class](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatch_Logs_Log_Classes.html) fits their budget the most. The default value should be suitable for most of the cases. Default: `INFREQUENT_ACCESS`. - **ControllerLogRetentionInDays** (required): The number of days CloudWatch should retain the Controller error logs. Default: 7 (days). - **ControllerSshKey** (required): Provides SSH access for the Cloud Controller instance. - **EnvironmentName** (optional): Adds a prefix to each piece of Bitrise-related infrastructure with the Environment Name. In case the customer has a vast number of resources, it might come in handy to be able to distinguish Bitrise-related resources from the rest. - **PrivateSubnet1CIDR** (required): CIDR range of the first private subnet of the new VPC. Default: 10.192.32.0/20. - **PrivateSubnet2CIDR** (required): CIDR range of the second private subnet of the new VPC. Default: 10.192.64.0/20. - **PublicSubnet1CIDR** (required): CIDR range of the first public subnet of the new VPC. Default: 10.192.0.0/20. - **PublicSubnet2CIDR** (required): CIDR range of the second public subnet of the new VPC. Default: 10.192.16.0/20 - **VpcCidrBlock** (required): The CIDR block of the selected VPC. - **CustomBashScript** (optional): Custom bash script to run on instance startup - **UseHostNetwork (required)**: Use host network mode for Docker container (--net=host) #### Infrastructure provisioned by the template - **Internal Application Load Balancer**: Servers have no traffic and only perform periodic health checks on the Cloud Controller instance. In all cases the Controller and the build machines will initiate network calls toward the Bitrise control plane, no external inbound traffic is required. - **Autoscaling Group**: Makes sure that a healthy Cloud Controller instance is running at a time.Instance: a t2.small instance on which the Cloud Controller runs. - **Instance**: a `t2.small` instance on which the Cloud Controller runs. - **Airgapped LaunchTemplate**: Cloud Controller instance configuration. Also needed for the controller self-update feature. - **IAM role, instance profile, and policy**: Certain permissions are necessary for the controller to query the build node states. - **AWS Secrets Manager**: The template creates two secrets, respectively, for storing the WorkspaceID and the Controller Token. - **CloudWatch log group**: The template creates a CloudWatch log group for storing Controller error logs. - **Airgapped security groups**: The template creates two security groups: one for the LoadBalancer and one for the instance. - **VPC**: A standard, general-purpose VPC based on best practices. Choosing the default CIDR block results in subnets with 4096 available IP addresses. The list of VPC-related resources the template creates: - One VPC. - Two public subnets. - Two private subnets. - One NAT Gateway + one Elastic IP. - One Internet Gateway + one Elastic IP. - Routing tables. - **VPC Endpoints**: The template creates 6 interface type endpoints and connects them to the instance security group to enable controller access to AWS resources: - `com.amazonaws.${AWS::Region}.autoscaling`: Used for controller self-update. - `com.amazonaws.${AWS::Region}.ec2`: Used for EC2 instance and dedicated host management. - `com.amazonaws.${AWS::Region}.ecr.api`: Used for downloading controller binary from Bitrise private ECR. - `com.amazonaws.${AWS::Region}.ecr.dkr`: Used for downloading controller binary from Bitrise private ECR. - `com.amazonaws.${AWS::Region}.logs`: Used for sending controller logs to CloudWatch. - `com.amazonaws.${AWS::Region}.secretsmanager`: Used for accessing secrets. - **Bitrise Agent Logs**: This functionality allows for seamless sending of Bitrise Agent build logs to AWS CloudWatch. It leverages CloudFormation to automatically set up the necessary IAM roles and policies, ensuring the Bitrise Agent has appropriate permissions. Moreover, it creates a specific log group in CloudWatch named `bitrise-agent-log`, facilitating organized log management and real-time analysis within the AWS environment. ### Necessary AWS permissions and connectivity The controller needs certain AWS permissions to perform actions on the build nodes. We did our best to limit the required permissions to a minimal scope. We even made [our CloudFormation template repository](https://github.com/bitrise-io/cloud-controller-cloudformation/blob/production/iam/roles.yaml) public to build trust. Please see the [entire list of (up-to-date) required permissions](https://github.com/bitrise-io/cloud-controller-cloudformation/blob/production/iam/roles.yaml) in the repository. The controller requires connectivity to certain Bitrise endpoints. See more [in the controller documentation](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/creating-and-configuring-a-controller). --- ## Bitrise on AWS overview The Cloud Controller enables you to enjoy the benefits of a Bitrise-managed infrastructure on your AWS environment. With the Cloud Controller, you can manage your build infrastructure even without deep knowledge about AWS. ### AWS offering types There are two basic types of Bitrise on AWS AMIs: - **Bare metal**: Your builds run directly on an AWS machine. This means that the build environment is persistent, the same way it would be on your own computer. Artifacts or cache items from a build can have an effect on subsequent builds, unless you clean up the environment. - **Virtualized/VM-based:** Just like on Bitrise, every build runs in its own virtual machine that is destroyed once the build is finished. It is powered by Bitrise’s virtualization solution that has run millions of builds on the Bitrise-managed machines built on top of Apple’s virtualization framework. Our macOS offerings, including the virtualized solution, are only available on Apple silicon machines. :::important[Updating the AMIs] The Bitrise AMIs are constantly updated with the latest versions of the pre-installed tools. However, providing the latest Xcode and Android Studio versions in the form of AMIs are slower than on the Bitrise-managed machines, because of the AWS AMI review process. You can check out the currently available versions on the [AWS stack reports](https://stacks.bitrise.io/stack_reports/aws/). ::: :::note[AWS pricing for Mac dedicated hosts] For macOS instances, a dedicated host must be allocated. On-Demand Amazon EC2 Mac Dedicated Hosts have a minimum host allocation and billing duration of 24 hours. For more details, check out the official AWS documentation: [Amazon EC2 Dedicated Hosts Pricing](https://aws.amazon.com/ec2/dedicated-hosts/pricing/#Pricing_for_Dedicated_Hosts). ::: #### Bare metal macOS [The bare metal macOS AMI](https://aws.amazon.com/marketplace/pp/prodview-gvebicfl7c37w) is only available on Apple silicon machines, on the following Amazon EC2 Mac instance types: - `mac-m4.metal` - `mac-m4pro.metal` - `mac2.metal` - `mac2-m2.metal` - `mac2-m2pro.metal` Android emulators are supported on all the instance types above. #### Virtualized macOS [The virtualized macOS AMI](https://aws.amazon.com/marketplace/pp/prodview-aqc5tyfdeozky) is only available on Apple silicon machines, on the following Amazon EC2 Mac instance types: - `mac-m4.metal` - `mac-m4pro.metal` - `mac2.metal` - `mac2-m2.metal` - `mac2-m2pro.metal` Virtualization offers an ephemeral build environment: the virtual machine is destroyed at the end of every build. This means that all builds run in a completely clean environment, and previous builds have no effect on them. You have the option of running either one or two VMs per build. Depending on how resource intensive a build is, running two VMs can mean significant savings in hardware costs. :::caution[No Android emulation] Android emulation is not available as the Apple silicon architecture doesn't support nested virtualization. ::: #### Bare metal Linux [The bare metal Linux AMI](https://aws.amazon.com/marketplace/pp/prodview-7h5yynaygkhls) is available on the following Amazon EC2 Linux instance types: - `t2.2xlarge` - `t2.xlarge` - `c5n.metal` - `c5.xlarge` - `c5.metal` - `c5.4xlarge` - `c5.2xlarge` Different instance types suit different computing needs. To find out more about the functions and capabilities of the different instance types, check out [the official AWS documentation](https://aws.amazon.com/ec2/instance-types/). You can run Android emulators on the `metal` instance types only. The other instance types don't support the use of emulators. ### When to choose the AWS option If you need to run Bitrise builds on infrastructure that you control, we offer two options: using Amazon EC2 Mac or Linux instances or our on-premise option. We recommend using Amazon EC2 instances to run Bitrise builds if you or your company already has an AWS account to operate important infrastructure. Using an Amazon EC2 instance comes with several advantages: - Plug and play: we provide the Amazon Machine Image (AMI) as a mobile-specific build environment, with all required tools preinstalled. No specific setup needed: you only need to configure the EC2 Mac or Linux instance. - Control your environment: you can configure network and storage settings during the launch of the instance (for example, you can configure a separate subnet for your Bitrise builds) to make sure all build machines run in their own AWS environment and operate according to company security policies. - Security: your code base will remain entirely in your control. :::caution[Information leaving the AWS environment] Using certain features means leaving the AWS environment: for example, using the build cache, generating build artifacts or test results. ::: If you don't have an AWS account, use some other cloud provider, or already manage your own machines, we recommend checking out [our on-premise runner offering](/bitrise-platform/infrastructure/running-bitrise-builds-on-premise). ### Cloud controller overview The Cloud Controller enables you to enjoy the benefits of a Bitrise-managed infrastructure on your AWS environment. With the Cloud Controller, you can manage your build infrastructure even without deep knowledge about AWS. The Cloud Controller enables Bitrise on AWS users to operate Amazon EC2 infrastructure at scale: - The automation supports both the bare metal and the VM-based macOS offerings, providing complete automation on reserving macOS dedicated hosts, starting the instances with the chosen AMI, and connecting to the Bitrise pool. - Controller's automation saves your mobile DevOps team time and removes an error-prone manual process that doesn't scale above a certain number of instances. - Changing the number of instances in the Agent Pool definition enables Amazon EC2 cost savings. Scaling down even a bigger macOS machine pool for the weekend will be as easy as changing a single number in the configuration. - Updating the machines to a newer build environment - provided in the form of an AMI by Bitrise - will be seamless and won't disturb the mobile developers. The configuration can define the percentage of machines affected by the update at any given time. - You can monitor the instances in each Bitrise pool, see their state, and the builds they are currently running. :::important[No inbound traffic required] We’ve created the Bitrise on AWS offering with the highest security standards in mind, to match even the most strict company policy requirements. In all cases the Controller and the build machines will initiate network calls toward the Bitrise control plane, so no external inbound traffic is required. ::: ![controller-diagram.png](/img/_paligo/uuid-af9f1f82-169a-eb0c-6c50-1d23315691dc.png) :::note[Manual setup] We recommend using the Cloud Controller to run Bitrise builds on AWS. However, if you want full control and customization options, you can choose [the manual setup](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances). ::: ### Air-gapped mode for the controller In order to provide the core functionalities of Bitrise in AWS environment, both the controller and the build machines need to access the Bitrise Control Plane on three addresses: - https://cloud-controller-aws-internal.services.bitrise.io - https://exec.bitrise.io - https://build-log.services.bitrise.io Some additional quality-of-life features (like the build machine self-update or the external IP collection) require further communication with additional resources on different addresses. To achieve the maximum security in AWS, you can disable these extra functionalities by enabling the **Air-gapped network mode** during controller creation. Please note that this setting doesn't affect your AWS configuration. You need to ensure that the network you use is configured securely. --- ## Configuring a machine pool After [you created an AWS controller](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/creating-and-configuring-a-controller), you can configure a machine pool. The pool is a group of instances that share the same configuration and can run Bitrise builds. The Controller ensures that the necessary amounts of matching resources are started on AWS. ### Creating a new pool Creating a new pool is happening through a multi-stage wizard, where you need to provide details about the pool: 1. Open your **Workspace settings** page. 1. Select **Infrastructure** and go to the **Bitrise on AWS** tab, then click **Create pool**. ![create-pool.png](/img/_paligo/uuid-4defa7e8-2933-8118-8b32-414f4a4994d2.png) 1. On the first screen, configure your agent pool settings: - **Pool name** (required): The pool name will appear on the **Stacks & Machines** tab of the Workflow Editor to allow you to select the pool to run builds. The name must be unique within the Workspace, across other pools and Bitrise agent pools. If the name is not unique, the pool cannot be created. - **Nr. of machines** (required): The number of machines created. The higher the number, the more builds can run parallel within the available concurrency. - **Rolling update percentage** (required): Rolling update percentage configures the expected system availability during machine restarts. The lower the number, the more machines will be available during a change rollout, but the overall time required for the rollout could be significantly higher. The provided values should be between 1% and 100% inclusive. The system rounds up the percentage-based values. If you have five machines with a 95% rolling update percentage, all five machines will be attempted to restart simultaneously. We recommend keeping this number high in case a breaking or blocking change is released (like SSH key rotation) and could be lower for smaller changes (like decreased disk size). - **Labels** (optional): Add key-value pairs to organize and categorize your pool. Each label needs a unique key; the value is optional. You can add up to 10 labels. - **IMDSv2** (optional): Requires token-based access for the instance metadata service instead of plain unauthenticated requests, for enhanced security. Disabled by default. 1. After clicking **Next**, provide the machine parameters on the next screen: ![create-machine-pool.png](/img/_paligo/uuid-12b52688-9137-1a9a-47d8-2944653f1d74.png) - **Amazon Machine Image (AMI) ID** (required): AMI is the Bitrise-built environment with all required tools preinstalled to run mobile builds. The provided ID of the AMI you subscribed to must be configured here. Only the Bitrise-managed AMIs are accepted in the current version. - **Stack** (required for VM-based AMIs): Stack selector becomes available only if the selected AMI is a VM-based MacOS AMI. In this case, the user must select one stack from the dropdown. - **Number of virtual machines**: Number of VM selector becomes available only if the selected AMI is a VM-based MacOS AMI. In this case, the user must select how many VM should run on the build machines (1 or 2). - **Availability zone** (required): The availability zone will define where the resources will be reserved. The Controller is going to start resources with the **mac2.metal** or **mac2-m2.metal** or **mac2-m2pro.metal** instance families, which are not available in every AWS availability zone. Make sure to select a valid availability zone [from the list](https://aws.amazon.com/about-aws/whats-new/2021/10/amazon-ec2-mac-instances-additional-regions/). - **Machine type (required)**: Machine type selector becomes available only after the Availability zone is provided. The Controller will start the build machines according to the selected machine type. :::note[Select the right region] The Controller is able to start resources only in the same region where it is located. If the selected availability zone is not in the same region, the machines are not going to start. ::: 1. On the next screen, under **Network & security settings**, you can specify further details about the machines: ![create-pool-security.png](/img/_paligo/uuid-ac4d6375-b153-bb6a-d78d-f0bd9bebf824.png) - **Subnet ID** (required): Specify the subnet ID you want to use for your machines from the availability zone configured before. All created machines will run under the same subnet. The machines must be able to reach Bitrise services from the subnet, but it doesn’t need to be a public subnet as Bitrise is not going to initiate communication. Make sure that your instance can access the following endpoints: - https://exec.bitrise.io - https://build-log.services.bitrise.io Without accessing these endpoints, you won't be able to run builds even after connecting the instance. This means the subnet must be able to access the internet, either via a NAT Gateway or an Internet Gateway. For more details about subnets, check [the official AWS documentation](https://docs.aws.amazon.com/vpc/latest/userguide/configure-subnets.html). - **Auto-assign public IP address**: Enabling the this field will ensure that a public IPv4 address is created for the EC2 instances. Enable it only when the configured subnet is public: that is, it has an internet gateway to directly communicate to the internet. If the subnet can't access the internet, disable this option. - **Security groups** (required): You can specify one or more security group IDs. With the security groups, you can control traffic to your AWS resources. At a minimum, an `empty-default` security group is required, which is empty from the incoming side and allows 0.0.0.0/0 for the outgoing side. If you want to use SSH to access your instances, the security groups must have an incoming port 22 open. If SSH access capability is not required, we recommend removing the related security group. For more details about security groups, check [the official AWS documentation](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-security-groups.html). :::note[Network configuration] Make sure that the selected subnet and security group belongs to the same network, otherwise the machines will not start. ::: - **AWS instance profile** (optional): You can configure extra IAM roles for your machines with the instance profile. This is necessary if you wish to access any other resources in AWS. For example, if you want to use your S3 bucket as an artifact store. If such capabilities are not needed, leave the profile empty. This option can be used to include permissions for streaming [Bitrise agent logs directly to CloudWatch](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/creating-and-configuring-a-controller#enabling-cloudwatch-bitrise-agent-logging), offering a centralized solution for log management and monitoring. If the AWS CloudFormation parameters have been set correctly, an instance profile called `bitrise-agent-log-instance-profile` has been generated. On AWS, you can get the generated ARN of that profile to use here. - **SSH key name** (optional): Facilitates debugging of the instances. You can access the created instances via SSH if an SSH key is provided and the correct security group settings are configured. If debugging is not required, we recommend leaving this field empty. 1. After clicking **Next**, configure storage requirements: ![prewarm.png](/img/_paligo/uuid-8dad9adf-f9a7-fe6b-e598-972b45ecca27.png) - **Disk type** (required): You can select from different root volume types. We recommend going with at least the gp3 setting. For details, check out [the AWS documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ebs-volume-types.html). - **Storage size** (required): Specify the root volume size in GB. Different images are created with different disk sizes that are the required minimum disk size. For the virtualized AMI with 1 VM per host, we recommend 700GB. For the virtualized AMI with 2 VMs per host, we recommend 1000GB. For bare metal, we recommend setting the disk size at least 50GB more than the minimum. - **Prewarming the disk**: Disk prewarming is suggested for every Amazon EBS device in order to work reliably. This prewarming could take significant time, up to multiple hours in the case of a bigger storage size configuration. The prewarming can be disabled but then the first few builds running on the build machine will fail. 1. When done, click **Create pool** Once a pool is created, the pool details appear on the screen: ![pool-detail.png](/img/_paligo/uuid-a30a61ec-5dea-3792-44ea-3e6d9c96b19d.png) In the header, you can see the name of the pool and its state. If the desired state of the pool has not been reached yet, then the state is **Updating...** A fully working pool’s status is Up-to-date. You can also see a section about the pool configuration, followed by the individual machines. Each machine also has a state, indicating if and what build is running on it. ### Reconfiguring a pool If the pool configuration is incorrect (for example, you need to investigate something that needs a different SSH key and a different subnet), hit the **Edit** button for any configured pools and reconfigure the pool. When a reconfiguration is requested, the Controller will terminate some running and incorrectly configured resources. When such termination is completed, a new resource will be created instead. This approach aims to reduce your costs as much as possible. We recommend reviewing the **Rolling update percentage** setting during the configuration, as it can create reduced availability if the setting is high. However, it can also slow rollout if the setting is low. When a reconfiguration starts, the pool status becomes **Updating...**, which stays in this status until all the resources are running according to the new configuration. At that time, the pool status becomes **Up-to-date** again. --- ## Creating and configuring a controller You must create and connect a Cloud Controller to take advantage of our Controller-managed AWS offering. The process has two stages: 1. [Configuring the Controller on Bitrise.](#configuring-the-controller-on-bitrise) 1. Setting up an instance running the controller agent on AWS. ### Configuring the controller on Bitrise 1. Get access to the AWS controller feature from the Bitrise team. 1. Log in to your Bitrise Workspace as a Workspace owner. Only Workspace owners can access and configure this feature. 1. Open the **Workspace settings** page of the Workspace. 1. Select **Infrastructure** and go to the **Bitrise on AWS** tab. ![create-controller-1.png](/img/_paligo/uuid-bfadf366-bdfc-4440-d2db-5e9f68843f9f.png) 1. Click **Connect with AWS**. This should bring up a dialog box. 1. Set a name for your controller and specify if you want to use the controller in an air-gapped network. For more information on air-gapped mode, see [Air-gapped mode for the controller](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/bitrise-on-aws-overview#air-gapped-mode-for-the-controller). ![create-controller-1.png](/img/_paligo/uuid-a4204c31-4165-2af9-290e-e3116ef784a3.png) 1. Copy and save your token. :::important[Save the token] This token is only accessible only right after creation. If the token is lost, you need to delete the controller and create a new one which would generate a new token. ::: After successful creation, the Bitrise on AWS screen should indicate that the controller on the Bitrise side is prepared, and it’s waiting for an AWS connection. In all cases the Controller and the build machines will initiate network calls toward the Bitrise control plane, no external inbound traffic is required. ### Setting up the controller instance on AWS After a successful controller creation on Bitrise, go to AWS and create an instance running the Controller Agent. :::note[New or existing VPC] The configuration will need a Virtual Private Cloud (VPC). Every AWS region contains a default VPC but if necessary, you can create your own VPC within each region. If you wish to share your VPC between Bitrise-specific resources and your other resources you can reuse the already existing and configured VPC. If you prefer to separate resources, you can create a new VPC with the provided template. For more information, read [the official AWS documentation on VPCs](https://docs.aws.amazon.com/vpc/latest/userguide/configure-your-vpc.html). ::: **Setup with an existing VPC** 1. Log in to your AWS account. 1. Select the template option you need and you'll get the HTTP link to your template. You can read more about templates on the [AWS CloudFormation templates](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates) page. - [Link to the base template](https://bitrise-cloudformation-templates.s3.amazonaws.com/cloud-controller-with-existing-vpc.yaml). - [Link to the airgapped template](https://bitrise-cloudformation-templates.s3.amazonaws.com/cloud-controller-with-existing-vpc-airgapped.yaml). Use this if the Bitrise Controller is expected to run [in airgapped mode](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates). :::note[Additional manual configuration] The airgapped support requires some manual configuration in AWS that is not automated via CloudFormation. For details, please check the [AWS CloudFormation templates](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates) page. ::: 1. Navigate to CloudFormation and select **Create stack with new resources (standard)**. ![controller-create-stack.png](/img/_paligo/uuid-336544f8-0f74-08ad-8a5d-616f33d62736.png) 1. Create a stack using the **Template is ready** and **Amazon S3 URL** options. 1. In the **Amazon S3 URL** field, provide the URL gathered in the previous step and click **Next**. ![create-stack-template.png](/img/_paligo/uuid-d2e802df-0b0d-afba-f36c-ad6a9af244bb.png) 1. On the following prompt, specify the following fields: - **Stack name**: Any value works here. This helps to identify the stack if you have multiple stacks. - **Latest AMI ID**: This AMI ID is used as a base AMI to run the Cloud Controller on. - **Bitrise Controller Token**: The token is generated as part of controller creation on Bitrise: [Configuring the controller on Bitrise](#configuring-the-controller-on-bitrise). - **Bitrise Workspace ID**: [Identifying Workspaces and apps with their slugs](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs). - **Controller Log Group Class** : The Cloud Controller generates logs that are accessible to the customers in AWS. This configuration specifies what features the customer wants to use during log analysis. The default is **Infrequent access**, which provides a limited log analyzing capability at a lower cost. - **Controller Log Retention In Days** : Determines how long AWS stores the Cloud Controller logs. - **Controller SSH Key** : Select one previously configured SSH key. With this key, you can log into the created instance and, if needed, investigate. - **Subnet IDs** : Choose at least two subnets in two different Availability Zones from the previously configured subnets, but make sure not to select more than one subnet from the same Availability Zone. The selected subnets should belong to the selected VPC. The subnets should have a route table configuration enabling the created instances to communicate to the Bitrise Services. There is no incoming communication required for the Controller. - **VPC CIDR Block** : Default value is provided. Make sure you select a CIDR Block matching the VPC’s CIDR Block. For more info, see [the official AWS docs](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-cidr-blocks.html). - **VPC ID** : Select from the previously configured VPCs. :::note[Only one controller per VPC/region] We do not recommend running more than one Controller in one VPC/one region. These Controllers could start more resources than necessary which can cost money. ::: 1. The other stack option configurations are optional. For details, check [AWS’s official documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-add-tags.html). 1. Review your previous settings on the **Review** screen. If everything looks correct, acknowledge your CloudFormation capabilities at the bottom and then submit your request. 1. Once the AWS CloudFormation successfully creates the instance running the Controller (this process can take 5-7 minutes), go back to your Workspace page on Bitrise to confirm the connectivity between the instance and AWS. If the Controller’s status is **Connected**, the connection works correctly. ![controller-ready.png](/img/_paligo/uuid-85d4125e-c0ef-ea64-d916-d04725b00581.png) **Setup with a new VPC** 1. Log in to your AWS account. 1. Select the template option you need and you'll get the HTTP link to your template. You can read more about templates on the [AWS CloudFormation templates](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates) page. - [Link to the base template](https://bitrise-cloudformation-templates.s3.amazonaws.com/cloud-controller-with-new-vpc.yaml). - [Link to the airgapped template](https://bitrise-cloudformation-templates.s3.amazonaws.com/cloud-controller-with-new-vpc-airgapped.yaml). Use this if the Bitrise Controller is expected to run [in airgapped mode](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates). :::note[Additional manual configuration] The airgapped support requires some manual configuration in AWS that is not automated via CloudFormation. For details, please check the [AWS CloudFormation templates](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates) page. ::: 1. Navigate to CloudFormation and select **Create stack with new resources (standard)**. ![controller-create-stack.png](/img/_paligo/uuid-336544f8-0f74-08ad-8a5d-616f33d62736.png) 1. Create a stack using the **Template is ready** and **Amazon S3 URL** options. 1. In the **Amazon S3 URL** field, provide the URL gathered in the previous step and click **Next**. ![create-stack-template.png](/img/_paligo/uuid-d2e802df-0b0d-afba-f36c-ad6a9af244bb.png) 1. On the following prompt, specify the following fields (all mentioned fields are required unless specified otherwise): - **Stack name**: Any value works here. This helps to identify the stack if you have multiple stacks. - **Latest AMI ID**: This AMI ID is used as a base AMI to run the Cloud Controller on. - **Bitrise Controller Token**: The token is generated as part of controller creation on Bitrise: [Configuring the controller on Bitrise](#configuring-the-controller-on-bitrise). - **Bitrise Workspace ID**: [Identifying Workspaces and apps with their slugs](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs). - **Controller Log Group Class** : The Cloud Controller generates logs that are accessible to the customers in AWS. This configuration specifies what features the customer wants to use during log analysis. The default is **Infrequent access**, which provides a limited log analyzing capability at a lower cost. - **Controller Log Retention In Days** : Determines how long AWS stores the Cloud Controller logs. - **Controller SSH Key** : Select one previously configured SSH key. With this key, you can log into the created instance and, if needed, investigate. - **Environment Name**: Optional. The provided value will appear in the names of the created VPC, subnets, and route tables. - **Private Subnet 1 CIDR**: Default value is provided. IP range (CIDR notation) for the private subnet of the new VPC in the first Availability Zone. The value must be between a /28 netmask and /16 netmask. - **Private Subnet 2 CIDR**: Default value is provided. IP range (CIDR notation) for the private subnet of the new VPC in the second Availability Zone. The value must be between a /28 netmask and /16 netmask. - **Public Subnet 1 CIDR**: Default value is provided. IP range (CIDR notation) for the public subnet of the new VPC in the first Availability Zone. The value must be between a /28 netmask and /16 netmask. - **Public Subnet 2 CIDR**: Default value is provided. IP range (CIDR notation) for the public subnet of the new VPC in the second Availability Zone. The value must be between a /28 netmask and /16 netmask. - **VPC CIDR**: Default value is provided. Select the Classless Inter-Domain Routing (CIDR) for the new VPC. 1. The other stack option configurations are optional. For details, check [AWS’s official documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-console-add-tags.html). 1. Review your previous settings on the **Review** screen. If everything looks correct, acknowledge your CloudFormation capabilities at the bottom and then submit your request. 1. Once the AWS CloudFormation successfully creates the instance running the Controller (this process can take 5-7 minutes), go back to your Workspace page on Bitrise to confirm the connectivity between the instance and AWS. If the Controller’s status is **Connected**, the connection works correctly. ![controller-ready.png](/img/_paligo/uuid-85d4125e-c0ef-ea64-d916-d04725b00581.png) ### Enabling CloudWatch Bitrise Agent logging Setting up CloudWatch is optional, but we recommend doing so: it enables better build troubleshooting capabilities. Bitrise can provide you with faster support in case of an issue if you share the Bitrise Agent logs from your CloudWatch setup. To enable your AWS resources, such as EC2 instances, to send logs to CloudWatch, you must configure it in [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html). You need the following settings: - **CreatedBitriseAgentLogs**: When enabled, this setting initiates the creation of a CloudWatch log group for the log stream, along with the required role and an instance profile named `bitrise-agent-log-instance-profile`. - **Bitrise Agent Logs Group Class**: The Bitrise Agent generates logs that are accessible to the customers in AWS. This configuration specifies what features the customer wants to use during log analysis. The default is **Infrequent access**, which provides a limited log analyzing capability at a lower cost. - **Bitrise Agent Logs Retention In Days** (required): The days until AWS stores the Bitrise Agent logs. ![agent-logging.png](/img/_paligo/uuid-639ad75f-9b32-7eb3-a08a-0f0a1c5035bf.png) --- ## Subscribing to the Bitrise on AWS AMI The Bitrise on AWS AMI is now available for both Linux and macOS. It enables running Bitrise builds on Amazon EC2 instances. Bitrise on AWS is sold via AWS Private Offer and a Bitrise account is required before you can use Bitrise-provided AMIs. Please don't purchase the offerings via the public AWS Marketplace. You can get a private offer of the Bitrise on AWS listings: 1. After [contacting Bitrise](https://bitrise.io/contact), we will send the order in a pdf format. This document contains all the details of our Bitrise on AWS offering, including the relevant customer data, the service provided, and the price of the service. 1. Once satisfied with the terms, contact Bitrise again to give up permission to create the AWS private offer. The offer will be visible on the AWS Marketplace. 1. Next you will receive a link to an AWS private offer which will also contain the order form attached. The link should take you to the AWS Marketplace. ![aws-offer-1.png](/img/_paligo/uuid-286c4817-1c22-6e11-06ec-26a34ce81273.png) 1. Optionally, you can enter a purchase order ID for invoicing purposes here: click **Add a purchase order**. To learn more about purchase orders, check out the official AWS documentation: [Managing your purchase orders](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/manage-purchaseorders.html). 1. Review the terms of the agreement. The pdf document will be available under the End User License Agreement link below the **Create Contract** button. Note that on the bottom right, you might see other available offers, including the Bitrise public offer. These are not relevant: the link you received took you straight to your private offer. 1. If everything is in order, click **Create Contract** on the right. After this point, the contract can’t be modified on the AWS page. ![aws-offer-2.png](/img/_paligo/uuid-dd9a98bf-41aa-d933-c06f-34d69bb56148.png) 1. Once the contract is ready, AWS should display a message about receiving a license. At this point you can proceed to configure your AMI by clicking **Continue to Configuration**. ![license-mgt.png](/img/_paligo/uuid-594370f7-8b76-f5b1-3042-d09c9f06bfe7.png) 1. Choose a fulfillment option, a version and your region before launching. You can read more about launching software from the AWS Marketplace in the official AWS documentation: [Launching container software from AWS Marketplace](https://docs.aws.amazon.com/marketplace/latest/buyerguide/buyer-configuring-a-product.html). 1. Once ready, click **Continue to Launch** to launch the software. ![continue-to-launch.png](/img/_paligo/uuid-d1f6b886-e707-4116-3eb6-331b765507ba.png) To read more about configuring your Amazon EC2 instance and running builds there: [Launching an EC2 instance for the Bitrise AMI](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/launching-an-ec2-instance-for-the-bitrise-ami). --- ## Troubleshooting the cloud controller We've listed some of the potential issues you might run into when attempting to use a cloud controller to run Bitrise builds on AWS. If you're experiencing problems, check this page for your issue. Can't see the Bitrise on AWS screen Make sure you’re looking at the correct place: **Workspace settings** > **Infrastructure** > **Bitrise on AWS**. If the page is not there, contact [Bitrise](https://bitrise.io/). You might need additional access rights. I see the Bitrise on AWS screen, but I cannot create a new controller Only Workspace Owners can create a new controller. Please make sure you have the correct access rights. The CloudFormation fails to create the stack when setting up the instance on AWS Please open a [support ticket](https://bitrise.io/)! The controller instance cannot connect to Bitrise 1. Confirm that your configuration is correct: - Check the CloudWatch logs for any errors. If the controller starts working but fails to execute anything, you will find the related logs there. - Under AWS Secrets Manager & Secrets, validate that both the workspace ID and the controller token are provided correctly. If any of the above is not configured correctly, destroy the CloudFormation stack and recreate it with the correct settings. 1. If the instance started but cannot connect to Bitrise: - Check the System Logs of the instance: If you see an `Error response from daemon: Get "https://public.ecr.aws/v2/": context deadline exceeded` message, you probably don’t have internet access on your instance. Double-check your route table configuration and make sure the configured subnets are able to access the internet. - Ensure that egress communication to the Bitrise URLs works. You can validate it in the following way: SSH into the created instance. In the terminal, use `telnet`, `curl`, or `wget` to access `cloud-controller-aws-internal.services.bitrise.io:443`. If the request runs to timeout, collect the evidence and notify our support. If you get 404, the egress communication is good. 1. If none of the above works, get in touch with Bitrise. The controller instance is randomly recreating This could be part of the normal workflow. A built-in functionality keeps the registered controllers in a fresh version to ensure the controller is compatible with the constantly evolving Bitrise. The controller also has a built-in health check functionality, which ensures that the instance is always working and working correctly. As part of that, to solve intermittent issues, the instances can occasionally restart. This is not going to prevent the controller from working correctly. If the controller is still restarting frequently or the user suspects issues with the controller’s behavior, please get in touch with Bitrise. I forgot the controller’s Secret before creating the controller in AWS You can read the token from the AWS Secrets. I cannot delete the controller from Bitrise You can delete the controller by clicking the **Remove** button next to the controller on the **Workspace settings** page. Only Owners of the Workspace can delete a controller. :::important[Removing the controller from AWS] Deleting the controller from Bitrise does not remove the controller from AWS. That needs to happen separately. After deleting a connected controller from Bitrise, the controller running in AWS will no longer be able to operate. ::: I cannot create a new machine pool Only Workspace Owners can create machine pools. Please make sure you have the correct access rights. I created a pool, but nothing happens Make sure the controller is in a **Connected** state: ![controller-ready.png](/img/_paligo/uuid-85d4125e-c0ef-ea64-d916-d04725b00581.png) If the Controller is in a Connected state, please check the CloudWatch logs for any errors. The CloudWatch logs could hold information about the misconfigured settings. For example: - Image availability and access. - Disk size requirement. - Security group and subnet configuration issues. I have configured the pool and see a machine, but its status has been Starting for over 3 minutes now When a new MacOS instance starts in AWS, it could take 5-10 minutes to start the underlying infrastructure. Open the instance details and check the **Created at** field under **Machine details**: If you see that the host details are filled after minutes, but the instance details are empty, that probably means the pool configuration was incorrect. That could be confirmed under AWS CloudWatch logs. Possible issues include a non-existent SSH key, an incorrect subnet or security group, and an unavailable AMI ID configured. Based on the findings, update the machine pool configuration. ![pool-detail.png](/img/_paligo/uuid-a30a61ec-5dea-3792-44ea-3e6d9c96b19d.png) The instance has started on the AWS infrastructure if the machine details are filled in. If you see that the machine was created more than 8-9 minutes ago and the machine’s status is still **Starting...**, start investigating: - Ensure all the configurations and the AWS resources are correctly provided. - Ensure the created instance can reach out to Bitrise: log in to the instance via the provided SSH key and ping exec.bitrise.io. I have created a pool, and machines are in the Running state, but I can't start builds on them Make sure that your builds are targeting the correct pool. In the Workflow Editor, every pool is selectable; make sure the correct `agent-pool-***` is selected for the builds. I have manually added a security group to one of the Bitrise-managed instances, but in a few seconds, the instance status becomes shutting-down The controller is responsible for achieving a state of machines configured on the Bitrise page. If any instances deviate from the required configuration, the controller identifies that and restarts the misconfigured resource. Please reconfigure the pool if you want to change such a configuration. I would like to reconfigure the pool to have fewer/more instances, but I don’t see the Edit button Only Workspace Owners can edit the pool configuration. Please make sure you have the correct access rights. I requested fewer machines, but in AWS, I still see Bitrise-managed dedicated hosts in pending/available status When a dedicated host is reserved, it cannot be released until 24 hours. The controller tries to free up the oldest dedicated hosts, but the dedicated host cannot be released if the 24-hour window has not passed. The controller is going to make sure to release the unneeded resources. I requested fewer machines 5 minutes ago, but there are still as many machines as I had before in the Running state Make sure that the controller is still in the **Connected** state. If the controller is connected, the system might prevent machine termination if builds are still running on the machines. If all the machines are running builds, the system marks the machine with the oldest dedicated host to be terminated. The machine termination will also start as soon as the running build finishes. The above logic does not target the build expected to finish first. Instead, it targets the dedicated host that could be released soonest to save you extra costs. I cannot delete the machine pool I have created Only Workspace Owners can delete a machine pool. Workspace Owners can also reconfigure the pools if any of the settings are incorrect, like the desired number of replicas. I need to access Bitrise Agent logs To obtain Bitrise Agent logs, configure CloudWatch Bitrise Agent logging. This is an optional feature but we highly recommend using it for better troubleshooting capabilities. --- ## Advanced options for EC2 instances For optimal use of the EC2 Mac and Linux instances, we recommend additional configuration that is not strictly required for the instances to run Bitrise builds. Some of these configuration options are best set during instance creation. ### Connectivity and security of your EC2 Mac and Linux instance Once your EC2 Mac or Linux instance is ready, make sure you can connect to the instance and that it can connect to the relevant Bitrise services. You can connect to the instance using SSH or in the case of EC2 Mac instances, VNC. You can also set a password for your instance. #### Instance passwords :::note[User data] To make sure instance behavior is consistent across all instances, we recommend configuring this as part of [user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html#user-data-console) during [instance creation](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/launching-an-ec2-instance-for-the-bitrise-ami). User data is provided either in plain text or in base64 encoded format. ::: By default, the Bitrise AMI doesn't have user passwords. It is the subscriber's responsibility to set the desired password. For an EC2 Mac instance, you need to set a user password and the default `login.keychain` password: ```bash sudo /usr/bin/dscl . -passwd /Users/ec2-user security set-keychain-password -o "" -p "" ~/Library/Keychains/login.keychain-db ``` For a Linux instance: ```bash sudo passwd ``` #### Connecting to the instance To connect to your instance using SSH, we recommend using TCP port 22. To connect to the instance via SSH: **macOS** - ```bash ssh -i "<your-ssh-key>" ec2-user@<your-mac2-instance> ``` You can also connect with VNC. We recommend using TCP port 5900. To connect: ```bash open vnc://ec2-user@<aws-mac2-instance> ``` **Linux** - ```bash ssh -i ~/.ssh/key ubuntu@ ``` :::important[Security group configuration] Make sure to enable the use of both ports in your [security group configuration](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-ec2-sg.html) of the instance! ::: ## Pre-warming the disk after booting :::note[User data] To make sure instance behavior is consistent across all instances, we recommend configuring this as part of [user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html#user-data-console) during [instance creation](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/launching-an-ec2-instance-for-the-bitrise-ami). User data is provided either in plain text or in base64 encoded format. ::: You can improve Amazon EBS performance by pre-warming the disk right after booting it up. You only need to do it once. :::important[Recommended for virtualization] We highly recommend pre-warming the disk if you use our virtualized offering. ::: - ```bash export cnt=$(($(df -h | grep "/$" | awk '{print $4}' | grep -oE "[0-9]+")-2)) sudo dd if=/dev/random of=bigfile bs=1g count=$cnt ``` **Linux instance** - ```bash sudo dd if=/dev/xvdf of=/dev/null bs=1M ``` :::note[dev/xvfd] Be aware that `xvdf` might be different on your machine ::: ## Increasing disk size on an EC2 Mac instance :::note[User data] To make sure instance behavior is consistent across all instances, we recommend configuring this as part of [user data](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html#user-data-console) during [instance creation](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/launching-an-ec2-instance-for-the-bitrise-ami). User data is provided either in plain text or in base64 encoded format. ::: If you have configured a bigger Amazon EBS storage for your EC2 Mac instance than the default (400 GB), resize the partition so macOS can use all available disk space: ```bash PDISK=$(diskutil list physical external | head -n1 | cut -d" " -f1) APFSCONT=$(diskutil list physical external | grep "Apple_APFS" | tr -s " " | cut -d" " -f8) yes | sudo diskutil repairDisk $PDISK sudo diskutil apfs resizeContainer $APFSCONT 0 ``` For more information, please refer to the [AWS macOS EC2 documentation](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-mac-instances.html#mac-instance-increase-volume). ### Cleaning up your AWS build environment When running a self-hosted agent, one agent executes multiple builds (one after the other). This allows sharing of data between builds on the local filesystem, but it also requires some care in order to avoid one build affecting another. To avoid this problem, you can clean up your build environment in between builds. To do so, you need to run the [Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli) on the self-hosted machines in agent mode: [Cleaning up persistent build environments](/bitrise-platform/infrastructure/cleaning-up-persistent-build-environments) ### Using secrets in your builds running on AWS You can use secret Environment Variables even if your organization's security policy doesn't allow you to host them on bitrise.io: [Secrets in self-hosted environments](/bitrise-ci/configure-builds/secrets#secrets-in-self-hosted-environments). --- ## Allocating a dedicated host for Mac instances Every Amazon EC2 Mac instance needs to run on a dedicated host. To be able to run the Bitrise AMI on an EC2 Mac instance, you'll need to allocate a dedicated host and launch the EC2 Mac instance on that host. Doing that requires knowing the host ID which AWS automatically generates when you allocate a host. :::note[AWS pricing for Mac dedicated hosts] For macOS instances, a dedicated host must be allocated. On-Demand EC2 Mac Dedicated Hosts have a minimum host allocation and billing duration of 24 hours. For more details, check out the official AWS documentation: [Amazon EC2 Dedicated Hosts Pricing](https://aws.amazon.com/ec2/dedicated-hosts/pricing/#Pricing_for_Dedicated_Hosts). ::: :::important[Service quotas] Make sure you have enough service quotas in your selected region to be able to launch a dedicated host. - [Viewing current quotas](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-resource-limits.html#view-limits). - [Request an increase](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-resource-limits.html#request-increase). ::: 1. On the EC2 Dashboard, find the **Instances** menu on the left navigation bar. 1. Select **Dedicated Hosts**. 1. Click **Allocate dedicated host**. 1. Fill out the required fields: - **Name tag**: This will be the name of your host. :::note[Host ID] The name is not the same as the host ID which you need to launch an EC2 instance on the dedicated host. The host ID is automatically generated by AWS. ::: - **Instance family**: **mac2** or **mac-m4** (depending on which Apple silicon generation you want) - **Instance type**: **mac-m4.metal, mac-m4pro.metal, mac2.metal, mac2-m2.metal, mac2-m2pro.metal** - **Availability Zone**: It depends on the subnets you plan to use. AWS will tell you if there is no node capacity in your chosen zone. - **Quantity**: The number of hosts you want to create. - **Host maintenance**: Disabled. The `mac2` and `mac-m4` instance families don't support host maintenance 1. When you're ready, click **Allocate**. Once the host is ready, you can proceed to launch an EC2 Mac instance. --- ## AWS manual setup overview Bitrise is available as an Amazon Machine Image (AMI) in the AWS Marketplace. With the Bitrise AMI, you can run Bitrise builds using your own AWS resources on Amazon EC2 instances connected to a Bitrise workspace. This section focuses on how to manually set up a fully customized AWS configuration for Bitrise builds. :::important[No inbound traffic required] We’ve created the Bitrise on AWS offering with the highest security standards in mind, to match even the most strict company policy requirements. In all cases the Controller and the build machines will initiate network calls toward the Bitrise control plane, so no external inbound traffic is required. ::: ![aws-manual-setup-diagram.png](/img/_paligo/uuid-035193f8-4a3b-65de-4c0b-8054d2e63586.png) The manual setup also requires an active subscription to a Bitrise AMI: [Subscribing to the Bitrise on AWS AMI](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/subscribing-to-the-bitrise-on-aws-ami). :::note[Cloud Controller] Instead of the manual setup, we strongly recommend using the Cloud Controller to set up AWS for Bitrise builds: [Bitrise on AWS: Cloud Controller](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates). ::: ### Setting up the EC2 Mac or Linux instance To run Bitrise builds on an Amazon EC2 Mac or Linux instance, you need to: 1. [Configure runner pools on Bitrise](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/launching-an-ec2-instance-for-the-bitrise-ami#configuring-the-instance): Set up a runner pool for your builds and get the token required to connect your Bitrise Workspace to your Amazon EC2 instance. 1. [Subscribe to the Bitrise AMI and launch an Amazon EC2 instance](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/launching-an-ec2-instance-for-the-bitrise-ami#preparing-your-ec2-mac-and-linux-instance). You can launch either an EC2 Mac or an EC2 Linux instance. For an EC2 Mac instance, you'll need to allocate a dedicated host before launching the instance. 1. [Use the token to connect the instance to your Bitrise Workspace](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/launching-an-ec2-instance-for-the-bitrise-ami#connecting-the-ec2-mac-or-linux-instance-to-your-bitrise-workspace). This will allow the Bitrise agent to run your builds on your EC2 Mac or Linux instances. --- ## Launching an EC2 instance for the Bitrise AMI We offer a dedicated Bitrise Amazon Machine Image (AMI) to run the Bitrise agent on your own Amazon EC2 Mac or Linux instance. This document guides you through launching an instance on the Amazon EC2 console UI. The process has three main phases but you can complete it in one sitting: 1. [Preparing your EC2 Mac or Linux instance.](#preparing-your-ec2-mac-and-linux-instance) 1. [Configuring the instance on AWS.](#configuring-the-instance) 1. [Connecting the instance to your Bitrise workspace.](#connecting-the-ec2-mac-or-linux-instance-to-your-bitrise-workspace) ### Preparing your EC2 Mac and Linux instance **Mac instance** 1. [Configure a runner pool](/bitrise-platform/infrastructure/configuring-runner-pools) and copy the token required for authentication. 1. Get the token from the process of adding the runner pool on Bitrise. 1. [Create an AWS Secrets Manager secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html) and store the token in the secret. 1. [Create an IAM role](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) with permission to read the secret. You will need to attach it to the EC2 instance. 1. [Allocate a dedicated host](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/allocating-a-dedicated-host-for-mac-instances) on AWS. You will need the automatically generated host ID. **Linux instance** 1. [Configure a runner pool](/bitrise-platform/infrastructure/configuring-runner-pools) and copy the token required for authentication. 1. Get the token from the process of adding the runner pool on Bitrise. 1. [Create an AWS Secrets Manager secret](https://docs.aws.amazon.com/secretsmanager/latest/userguide/create_secret.html) and store the token in the secret. 1. [Create an IAM role](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) with permission to read the secret. You will need to attach it to the EC2 instance. ### Configuring the instance **Mac instance** 1. Go to the AWS Marketplace page, and on the left, select **Manage subscriptions**. 1. Choose the AMI you need, and select **Launch new instance**. ![aws-markplace-amis.png](/img/_paligo/uuid-81bb90b8-85ea-ae9e-7349-3783f7af230e.png) 1. Make sure the software version and the region are correct, then click **Continue to launch through EC2**. 1. Fill out the required fields on the **Launch an instance** page: **Name and tags** section: - **Name**: The name of your instance. **Instance type** section: - **Instance type**: The supported types are: `mac-m4.metal`, `mac-m4pro.metal`, `mac2.metal`, `mac2-m2.metal`, `mac2-m2pro.metal`. :::important[Dedicated host type] The selected instance type must match the type of the dedicated host! ::: **Key pair (login)** section: - **Key pair name - *required***: **Network settings** section - click **Edit** to modify the settings: - **VPC - *required***: Select a virtual private cloud from the dropdown menu. - **Subnet**: Select your preferred subnet from the dropdown menu, or leave it on **No preference**. - **Firewall (security groups)**: Create a new security group or select an existing one. **Configure storage** section: - Set the size of the storage volume in gigabytes: For the bare metal macOS AMI, the minimum number is 400 GB but we recommend at least 450 GB. For the virtualized macOS AMI, we recommend 700GB with 1 VM per host and 1000GB with 2 VM per host. :::note[Increasing the disk size] If you need to increase the disk size from the default 400 GB, re-partition the disk so macOS can use all the allocated storage. You can do this when setting up the instance by adding a script to **User data** in the **Advanced details** section: [Increasing disk size on a Mac instance](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#increasing-disk-size-on-an-ec2-mac-instance). ::: - Select a root volume type from the dropdown menu. :::note[Storage type] We recommend using at least the **gp3** root volume, the higher the IOPS the better. ::: **Advanced details** section: - **Tenancy**: Select the **Dedicated host - launch this instance on a dedicated Host** option from the dropdown menu. - **Target host**: Select the **Host ID** option from the dropdown menu. - **Tenancy host ID**: Select the host ID of the previously created dedicated host. **Linux instance** 1. [Configure a runner pool](/bitrise-platform/infrastructure/configuring-runner-pools) and copy the token required for authentication. 1. Navigate to the EC2 Dashboard. 1. Go to the AWS Marketplace page, and on the left, select **Manage subscriptions**. 1. Choose the AMI you need, and select **Launch new instance**. ![aws-markplace-amis.png](/img/_paligo/uuid-81bb90b8-85ea-ae9e-7349-3783f7af230e.png) 1. Make sure the software version and the region are correct, then click **Continue to launch through EC2**. :::important[Service quotas] Make sure you have enough service quotas in your selected region to be able to launch as many instances as you need. - [Viewing current quotas](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-resource-limits.html#view-limits). - [Request an increase](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-resource-limits.html#request-increase). ::: 1. Fill out the required fields on the **Launch an instance** page: **Name and tags** section: - **Name**: The name of your instance. **Instance type** section: - **Instance type**: Select an x86_64 Linux metal instance. **Key pair (login)** section: - **Key pair name - *required***: **Network settings** section - click **Edit** to modify the settings: - **VPC - *required***: Select a virtual private cloud from the dropdown menu. - **Subnet**: Select your preferred subnet from the dropdown menu, or leave it on **No preference**. The subnet must be able to access the internet either via a NAT Gateway or an Internet Gateway. - **Firewall (security groups)**: Create a new security group or select an existing one. **Configure storage** section: - Set the size of the storage volume in gigabytes. The minimum value is 450 GB. - Select a root volume type from the dropdown menu. ### Connecting the EC2 Mac or Linux instance to your Bitrise Workspace **Mac bare metal instance** 1. Make sure that your instance can access the following endpoints: - https://den.services.bitrise.io - https://build-log.services.bitrise.io 1. [Modify the User data of the instance](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html#user-data-cloud-init): add the command to launch the Bitrise runner, using the Secret you created in the AWS Secrets Manager: :::important When modifying the user data scripts for an EC2 Mac instance, make sure that there is no empty space before the start of the script. The first line should always be `#!/bin/bash`. If there is empty space before this line, the instance won't work. ::: ```bash TOKEN=$(aws secretsmanager get-secret-value --secret-id MY_SECRET | jq -r '.SecretString | fromjson | .["MY_SECRET"]') sudo sed -i '' "s/BITRISE_AGENT_TOKEN/$TOKEN/" /Users/ec2-user/Library/LaunchDaemons/io.bitrise.self-hosted-agent.plist sudo launchctl load -w /Users/ec2-user/Library/LaunchDaemons/io.bitrise.self-hosted-agent.plist ``` 1. You can also set shell scripts or other custom data in the **User data** section. In the [Advanced options for EC2 Mac and Linux instances](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances) section, you can find recommendations for optimizing your instance with user data: - [Instance passwords](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#connectivity-and-security-of-your-ec2-mac-and-linux-instance) - [Pre-warming the disk after booting](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#pre-warming-the-disk-after-booting) - [Increasing disk size on a Mac instance](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#increasing-disk-size-on-an-ec2-mac-instance) **Mac virtualized instance** 1. Make sure that your instance can access the following endpoints: - https://den.services.bitrise.io - https://build-log.services.bitrise.io 1. [Modify the User data of the instance](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html#user-data-cloud-init): add the command to launch the Bitrise runner, using the Secret you created in the AWS Secrets Manager. You also need to provide the number of concurrencies and the stack you wish to run. :::important When modifying the user data scripts for a macOS instance, make sure that there is no empty space before the start of the script. The first line should always be `#!/bin/bash`. If there is empty space before this line, the instance won't work. ::: You can get the list of available stacks with the following command: ```bash /opt/virtualization-cli/bin/virtualization-cli list ``` The allowed values for your concurrency preference are 1 or 2. - With 1 CC, the runner will schedule 1 VM with 8 vCPU and 12 GB RAM. - With 2 CC, the runner will schedule 2 VMs with 4 vCPU and 6 GB RAM each. ```bash TOKEN=$(aws secretsmanager get-secret-value --secret-id MY_SECRET | jq -r '.SecretString | fromjson | .["MY_SECRET"]') sudo sed -i '' 's/BITRISE_AGENT_CC//' /Users/ec2-user/Library/LaunchDaemons/io.bitrise.self-hosted-agent.plist sudo sed -i '' 's/BITRISE_AGENT_STACK//' /Users/ec2-user/Library/LaunchDaemons/io.bitrise.self-hosted-agent.plist sudo sed -i '' "s/BITRISE_AGENT_TOKEN/$TOKEN/" /Users/ec2-user/Library/LaunchDaemons/io.bitrise.self-hosted-agent.plist sudo launchctl load -w /Users/ec2-user/Library/LaunchDaemons/io.bitrise.self-hosted-agent.plist ``` 1. You can also set shell scripts or other custom data in the **User data** section. In the [Advanced options for EC2 instances](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances) section, you can find recommendations for optimizing your instance with user data: - [Instance passwords](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#connectivity-and-security-of-your-ec2-mac-and-linux-instance) - [Pre-warming the disk after booting](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#pre-warming-the-disk-after-booting) - [Increasing disk size on a Mac instance](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#increasing-disk-size-on-an-ec2-mac-instance) **Linux instance** 1. Make sure that your instance can access the following endpoints: - https://den.services.bitrise.io - https://build-log.services.bitrise.io 1. [Modify the User data of the instance](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html#user-data-cloud-init): add the command to launch the Bitrise runner, using the Secret you created in the AWS Secrets Manager: ```bash TOKEN=$(aws secretsmanager get-secret-value --secret-id MY_SECRET | jq -r '.SecretString | fromjson | .["MY_SECRET"]') /opt/bitrise/releases/bitrise-den-agent-configure.sh $TOKEN ``` :::caution[Linux image version] If your Linux image version is EARLIER than `v2025W10`, the required command is slightly different: ```bash TOKEN=$(aws secretsmanager get-secret-value --secret-id MY_SECRET | jq -r '.SecretString | fromjson | .["MY_SECRET"]') sudo sed -i “s/BITRISE_AGENT_TOKEN/$TOKEN/” /etc/systemd/system/bitrise-den-agent.service sudo systemctl start bitrise-den-agent.service ``` ::: 1. You can also set shell scripts or other custom data in the **User data** section. In the [Advanced options for EC2 instances](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances) section, you can find recommendations for optimizing your instance with user data: - [Instance passwords](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#connectivity-and-security-of-your-ec2-mac-and-linux-instance) - [Pre-warming the disk after booting](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#pre-warming-the-disk-after-booting) - [Increasing disk size on a Mac instance](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances#increasing-disk-size-on-an-ec2-mac-instance) --- ## Bitrise on AWS: OS security patching On AWS, security patching and maintenance are governed by the [Shared Responsibility Model](https://aws.amazon.com/compliance/shared-responsibility-model/). For Bitrise, the most important issues are the following: - Host AMI updates - Bitrise VM image updates (if applicable) The responsibilities regarding these tasks are shared between Bitrise and the customer. The exact responsibilities differ based on the AWS environment: different policies apply to macOS and Linux environments. ### macOS virtualized environment Bitrise on AWS offers AMIs with VM images of our [stable stacks](https://bitrise.io/stacks/) (not edge stacks) for the macOS virtualized environment. :::note[Regular tooling updates] Bitrise performs regular VM updates for tooling changes. When a new VM image is built due to a tooling update, the latest AWS macOS version is used for the host instance (AMI). The OS of the VM image will not change. ::: | Component | Bitrise Update Frequency | Customer Responsibility | | --- | --- | --- | | **Host OS** | Bitrise does not perform general OS updates. OS security patches occur only if required by our internal information security assessment (as defined in our trust center). | It is the customer’s responsibility to use the newest AMIs. | | **VM OS** | Bitrise does not perform general OS updates. OS security patches occur only if required by our internal information security assessment (as defined in our trust center). | It is the customer’s responsibility to use the newest AMIs. | ### macOS bare metal environment In the macOS Bare Metal environment, Bitrise on AWS offers AMIs only for [stable stacks](https://bitrise.io/stacks/) only (not edge stacks). | Component | Bitrise Update Frequency | Customer Responsibility | | --- | --- | --- | | **Bitrise AMI** | Bitrise uses AWS's latest macOS version as the base when building a new host AMI. We monitor macOS vulnerabilities and rebuild and publish new AMI versions when internal information security assessments dictate. | It is the customer’s responsibility to use the newest AMIs. | :::note[Trust Center] Additional information on how Bitrise monitors and assesses vulnerabilities can be found in the [Trust Center](http://security.bitrise.io). ::: ### Linux environment Linux instances on Bitrise on AWS operate on Bare Metal only, with no virtualization or Docker. All required tooling is baked directly into the Amazon Machine Image (AMI). | Component | Bitrise Update Frequency | Customer Responsibility | | --- | --- | --- | | **Bitrise AMI** | Bitrise updates the core Linux AMI for tooling changes (for example, Android tools) only. | The customer is responsible for applying OS security patches. | ### Patching scenarios The method for applying security patches differs based on whether or not you are using the [Bitrise Controller](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates). #### Patching without the controller If you are using a manual setup, you have more flexibility for applying patches or updates in general to the instance. You can: - Create a custom AMI: start a Bitrise AMI, make a change (like an OS patch), take a new AMI snapshot, and then configure your environment to run with the ID of this new, custom AMI. - Use a [user data script](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html): define your own script to execute commands upon instance startup. - Use SSH updates: connect to your instances via SSH to perform updates manually with a guarantee that the updates will persist. #### Patching with the controller You have multiple options to apply patches when using the controller: - Host warmup script: this script runs when an instance is started (a one-time operation). To apply updates to the instance, you can modify the host warmup script, drain the instance pool and then bring it back up, which will run the script for a fully updated instance. :::caution[Availability] Be mindful of Mac EC2 availability when performing this operation. ::: - Controller with virtualization: the VM OS on stable stacks does not receive general updates, however, Bitrise monitors for OS vulnerabilities and publishes new AMIs based on internal information security assessments. The VM warmup script runs in the fresh VM for every new build that is started. This may not be a good option for VM OS patches due to the time they consume. :::important[Custom AMIs] You cannot use a custom AMI with the Bitrise Controller, which means you cannot take a snapshot of an updated AMI and use it with the Controller. The Controller only permits specific Bitrise AMIs. If you think this may be a requirement, please [contact us](https://bitrise.io/contact) to discuss. ::: ### Security patching reference | | macOS Virtualized - Controller | macOS Bare Metal - Controller | macOS Virtualized - Manual | macOS Bare Metal - Manual | Linux Bare Metal - Manual | | --- | --- | --- | --- | --- | --- | | **Host OS Update** | Can use host warm up script to perform updates. | Can use host warm up script to perform updates. | Can use custom AMI Can directly modify instance | Can use custom AMI Can directly modify instance | Can use custom AMI Can directly modify instance | | **VM OS Update** | Bitrise is responsible for critical security updates. | N/A | Bitrise is responsible for critical security updates. | N/A | N/A | --- ## About build machines For [Bitrise CI](/bitrise-ci), both Linux and Xcode stacks are available on several different build machine types. Each machine type offers several options with varying computing power, depending on [your subscription plan](http://www.bitrise.io/pricing). You can configure a default machine type for each of your projects and you can also set Workflow-specific machine types. You can do this when selecting stacks for your project: [Setting the stack for your builds](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds). :::tip[Changing machine types using the API] You can also change build machine types for all projects owned by a single user or workspace using the API: [Changing machine types in all apps at the same time](/bitrise-ci/api/adding-and-managing-apps#changing-machine-types-in-all-apps-at-the-same-time). ::: Each Bitrise build machine has its own IP address range: you can allowlist these IP addresses to be able to access our build machines from, for example, a private cloud: [Configuring your network to access our build machines](/bitrise-platform/infrastructure/build-machines/configuring-your-network-to-access-our-build-machines) For more information about build and code security, see [Code security](/bitrise-platform/infrastructure/code-security). --- ## Build machine types(Build-machines) Bitrise offers multiple build machines with different specifications You can choose between them based on your needs. You can track how much time you spent building your apps on each machine type with Insights: [Bitrise CI metrics](/insights/available-metrics-in-insights/bitrise-ci-metrics). :::tip[Machine availability by subscription plan] Not all machines are available on all subscription plans. Visit [the pricing page](http://www.bitrise.io/pricing) to find out which machines are available on your plan! ::: Machine types are divided into resource classes. The same resource class offers multiple machine types with broadly similar performances. Bitrise automatically assigns machine types from a resource class, which means that on the same day, your builds might run on different machine types. :::tip Use the machine type ID to set the machine type in your [configuration YAML](/bitrise-ci/configure-builds/configuring-build-settings/setting-the-stack-for-your-builds#setting-the-stack-in-the-configuration-yaml). ::: | OS and resource class | Hardware type | Specs | Machine type ID | | --- | --- | --- | --- | | macOS Medium | M2 Pro Medium | • 4 CPU @3.49GHz• 6 GB RAM | `g2.mac.medium` | | macOS Medium | M4 Medium | • 5 CPU @4.4 GHz• 6 GB RAM | `g2.mac.medium` | | macOS Large | M2 Pro Large | • 6 CPU @3.49GHz• 14 GB RAM | `g2.mac.large` | | macOS Large | M4 Large | • 5 CPU @4.4 GHz• 14 GB RAM | `g2.mac.large` | | macOS X Large | M2 Pro X Large | • 12 CPU @3.49GHz• 28 GB RAM | `g2.mac.x-large` | | macOS X Large | M4 X Large | • 10 CPU @4.4 GHz• 28 GB RAM | `g2.mac.x-large` | | macOS 4Large | M4 Pro Large | • 7 CPU @4.52GHz• 27 GB RAM | `g2.mac.4large` | | macOS 4X Large | M4 Pro X Large | • 14 CPU @4.52GHz• 54 GB RAM | `g2.mac.4x-large` | | Linux Medium | | • 4 vCPU @3.1 GHz• 16 GB RAM | `standard` | | Linux Large | | • 8 vCPU @3.1 GHz• 32 GB RAM | `elite` | | Linux X Large | | • 16 vCPU @3.1 GHz• 64 GB RAM | `elite-xl` | | Linux Small | AMD EPYC Zen 4/5 | • 2 vCPU• 8 GB RAM | `g2.linux.2small` | | Linux M | AMD EPYC Zen 4/5 | • 4 vCPU @3.7 GHz• 16 GB RAM | `g2.linux.medium` | | Linux 2M | AMD EPYC Zen 4/5 | • 6 vCPU @3.7 GHz• 24 GB RAM | `g2.linux.2medium` | | Linux L | AMD EPYC Zen 4/5 | • 8 vCPU @3.7 GHz• 32 GB RAM | `g2.linux.large` | | Linux 4L | AMD EPYC Zen 4/5 | • 14 vCPU @3.7 GHz• 56 GB RAM | `g2.linux.4large` | | Linux XL | AMD EPYC Zen 4/5 | • 16 vCPU @3.7 GHz• 64 GB RAM | `g2.linux.x-large` | | Linux 3XL | AMD EPYC Zen 4/5 | • 24 vCPU @3.7 GHz• 96 GB RAM | `g2.linux.3x-large` | | Linux 5XL | AMD EPYC Zen 4/5 | • 32 vCPU @3.7 GHz• 128 GB RAM | `g2.linux.5x-large` | | Linux 7XL | AMD EPYC Zen 4/5 | • 48 vCPU @3.7 GHz• 192 GB RAM | `g2.linux.7x-large` | :::note Some macOS resource classes list two hardware types with the same machine type ID. Both generations use the same ID — Bitrise automatically selects the available hardware for each build. ::: --- ## Configuring your network to access our build machines Our datacenters are behind a set of public static IP addresses, with the virtual machines having their own internal subnets behind these addresses. Depending on your company security policy, you may need to allowlist the public IP addresses to be able to access the build machine: [IP address ranges for the Bitrise build machines](#ip-address-ranges-for-the-bitrise-build-machines). Similarly, the Bitrise background workers powering [app.bitrise.io](http://app.bitrise.io) UI and related control plane, configuration management, signaling to your services are accessible at a set of static IP addresses. Allowlisting these addresses can ensure you can still receive build status updates or that Bitrise can access the `bitrise.yml` file: [IP address ranges for Bitrise backend workers](#ip-address-ranges-for-bitrise-backend-workers) of your app. ### IP address ranges for the Bitrise build machines For most users, who host their repositories on cloud-based service providers, there is no need for any network configuration to be able to use Bitrise. All we need is permission to access the repository and for that, [an SSH key](/bitrise-platform/repository-access/configuring-ssh-keys) or [an access token](/bitrise-platform/repository-access/configuring-https-authorization-credentials) is enough. However, your company security policy might not allow unknown and unauthorized IP addresses to communicate with the servers where your code is being stored - either on your own datacenter or in a private cloud. In that case, Bitrise won’t work unless the relevant IP addresses are added to your allow list. You will see IP addresses from the following ranges as source when your Bitrise build machines reach out to your services like Git to download your source code, or call into your test backend services, or any other services you run outside Bitrise that are required to be reached as part of your CI workflow. :::warning[Allowlist the entire subnet] If the provided public IP address is a subnet, you need to allow the entire subnet on your network! For example, 208.52.166.128/28 means all IP addresses between 208.52.166.128 and 208.52.166.143 (208.52.166.128, 208.52.166.129, 208.52.166.130, and so on, all the way to and including 208.52.166.143) have to be allowlisted. ::: :::warning[Multi-tenant vs Single-tenant] The build machine IP ranges listed below are for the Bitrise multi-tenant environment. Depending on your organization's security requirements, it may not be advisable to allow access to your network from the Bitrise multi-tenant IP range. For organizations with enhanced security requirements, you can: - [Connect by VPN](/bitrise-platform/integrations/connecting-to-a-vpn-during-a-build). - [Select a single-tenant environment](/bitrise-platform/infrastructure/customizable-enterprise-build-platforms). - [Deploy runners to your own AWS account](/bitrise-platform/infrastructure/bitrise-on-aws--cloud-controller/aws-cloudformation-templates). Feel free to [contact us](https://bitrise.io/contact) if you have questions. ::: macOS IP addresses Linux IP addresses 74.122.200.224/27(74.122.200.224 - 74.122.200.255)74.122.201.224/27(74.122.201.224 - 74.122.201.255)74.122.202.224/27(74.122.202.224 - 74.122.202.255)74.122.203.224/27(74.122.203.224 - 74.122.203.255) 74.122.200.224/27(74.122.200.224 - 74.122.200.255)74.122.201.224/27(74.122.201.224 - 74.122.201.255)74.122.202.224/27(74.122.202.224 - 74.122.202.255)74.122.203.224/27(74.122.203.224 - 74.122.203.255) 185.55.252.224/27(185.55.252.224 - 185.55.252.255)185.55.253.224/27(185.55.253.224 - 185.55.253.255)185.55.254.224/27(185.55.254.224 - 185.55.254.255)185.55.255.224/27(185.55.255.224 - 185.55.255.255) 185.55.252.224/27(185.55.252.224 - 185.55.252.255)185.55.253.224/27(185.55.253.224 - 185.55.253.255)185.55.254.224/27(185.55.254.224 - 185.55.254.255)185.55.255.224/27(185.55.255.224 - 185.55.255.255) 208.52.166.154/32 104.197.15.74/32 208.52.166.128/28 34.123.172.192/32 207.254.0.248/29 34.125.50.224/32 207.254.0.208/28 34.125.82.130/32 207.254.34.148/32 34.134.193.138/32 207.254.33.176/28 34.138.187.10/32 34.150.152.190/32 34.162.185.129/32 34.162.202.37/32 34.162.229.32/32 34.162.29.153/32 34.162.88.79/32 34.23.207.105/32 34.85.139.176/32 34.85.240.93/32 34.86.56.118/32 35.202.121.43/32 35.225.44.167/32 35.231.56.118/32 35.237.165.17/32 35.243.148.182/32 35.245.56.67/32 ### IP address ranges for Bitrise backend workers Bitrise backend workers are operating behind firewalls and NAT gateways. Our backend systems reach out to your services and webhooks, or send build status updates on commits, pull requests, and tags in a self-hosted repository. These addresses may be relevant if you use self-hosted Git services or store your `bitrise.yml` file in the repository. In this way Bitrise can, for example, access the `bitrise.yml` file, or [send build status updates](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider) on commits and pull requests in a self-hosted repository. IP address ranges for backend workers 35.232.76.43 34.68.119.18 34.135.186.58 74.122.200.64/28 (74.122.200.64 - 74.122.200.78)74.122.201.64/28 (74.122.201.64 - 74.122.201.78)74.122.202.64/28 (74.122.202.64 - 74.122.202.78)74.122.203.64/28 (74.122.203.64 - 74.122.203.78) 185.55.252.64/28 (185.55.252.64 - 185.55.252.78)185.55.253.64/28 (185.55.253.64 - 185.55.253.78)185.55.254.64/28 (185.55.254.64 - 185.55.254.78)185.55.255.64/28 (185.55.255.64 - 185.55.255.78) ### Document changelog **November 2025** Added the 185.55.252.0/22 range to the IP ranges of both the build machines and the backend workers, which will utilize the new IP range from the 21st of January, 2026. The exact IP ranges are as follows: Build machines: - 185.55.252.224/27 - 185.55.253.224/27 - 185.55.254.224/27 - 185.55.255.224/27 Backend workers: - 185.55.252.64/28 - 185.55.253.64/28 - 185.55.254.64/28 - 185.55.255.64/28 **May 2025** Narrowed the Bitrise build machines IP range from 74.122.200.0/22 to: - 74.122.200.224/27 - 74.122.201.224/27 - 74.122.202.224/27 - 74.122.203.224/27 Narrowed the Bitrise backend workers IP range: from 74.122.200.0/22 to: - 74.122.200.64/28 - 74.122.201.64/28 - 74.122.202.64/28 - 74.122.203.64/28 **April 2024** Added the 74.122.200.0/22 range to the IP ranges of both the build machines and the backend workers. **October 2022** Significantly increased the Linux/Docker stacks IP range. --- ## Freeing up storage space on build machines If you need additional disk space on Bitrise build machines, you can always delete tools and resources that you do not use. You just need to use a **Script** Step at the start of your build. :::note[java.io.IOException: No space left on device] If you get the `java.io.IOException: No space left on device` error during a build, you can try to free up additional space with the below method - the error indicates there's no more space available on the build machine. ::: 1. Check your stack's [System Report on GitHub](http://stacks.bitrise.io/). The System Report includes the list of [pre-installed tools](/bitrise-platform/infrastructure/build-stacks/preinstalled-tools-on-bitrise-stacks) and their version on the stack. 1. Find the tools you don't need in your build. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add a [**Script**](https://github.com/bitrise-io/steps-script) Step to the beginning of your Workflow. 1. In the **Script content** input of the Step, add the necessary commands to uninstall the tools. **Uninstalling unneeded tools** If your app doesn't need Android SDK tools, you can remove them with the following commands in your [**Script**](https://github.com/bitrise-io/steps-script) Step: ```bash sudo rm -rf /usr/local/share/android-sdk sudo rm -rf /opt/android-ndk ``` You can delete iOS simulators that you don't use: ```bash sudo rm -rf ~/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS\\ 26.simruntime/ ``` --- ## About build stacks(Build-stacks) The build stack indicates the virtual machine version that we will use to run your build. The main stack types are: - **macOS stacks**: These stacks run on a macOS operating system and each one includes multiple Xcode versions. Ideal for building iOS apps. They also have Android tools installed if you want to use them to build a cross-platform app. - The **Android & Docker** stack: These stacks run on Linux operating system in a Docker environment. They have all Android tools installed and they are ideal for building native Android apps. :::note[Free disk space] Each stack has at least 100 GB of free disk space. You can check each stack's exact available disk space on the relevant stack report page: [Bitrise stack reports](https://stacks.bitrise.io/stack_reports/). ::: Each build runs in its own virtual machine and the virtual machine is rolled back to a saved state, the “base box” state, after the build is finished. This way **your builds are always protected** by changes made by others and by your previous builds and you can use a **stable environment** to define your build workflow, since no state persists between builds. :::note[Passwordless sudo enabled] The user account that is used for the builds is configured to have **passwordless sudo** enabled. This way you are able to install all the extra things you need for your builds and for other automation. If a tool is not preinstalled on your stack of choice, you can install it yourself - see the guide. ::: After adding your app to Bitrise we will select an appropriate stack for it. You can change the stack at any time on the **Stacks & Machines** tab of the Workflow Editor. ![xcode_image.png](/img/_paligo/uuid-fc53715a-add5-8c4c-d4a6-9a04f5da6d3b.png) After selecting the stack you want to use, you’ll see a short description of the stack with an additional link to learn more about that specific one (for example, to see what tools are preinstalled, and which versions, on the selected stack). | Type | Description | | --- | --- | | Stable | Generally available and expected to be supported for the foreseeable future. Updated when an update for the stack’s primary tool is available. Example: when Xcode 7.3.1 was released, the Xcode 7.3 stack was updated to have 7.3.1 instead of 7.3(.0). | | Edge | Previews upcoming versions and changes. Includes the latest stable release, the latest beta release (if available), and the latest versions of preinstalled tools. Regular updates can add, remove, or upgrade tools, and backwards compatibility between updates isn't guaranteed. | | Frozen | No longer updated and flagged for removal per the [stack deprecation and removal policy](/bitrise-platform/infrastructure/build-stacks/stack-deprecation-and-removal-policy). Still available for your builds, but preinstalled tools won't receive updates, so keeping up with bugfixes and security patches becomes your responsibility. | | Type | Description | | --- | --- | | Pre-booted | If a stack is available as pre-booted, and there’s enough pre-booted machines with that stack configuration, your build can start right away, without waiting for the build environment to boot. In case there’s no more available pre-booted machine with that stack configuration, your build will start on an on-demand configuration. | | On-demand | If a stack is available as on-demand configuration and there’s no (available) pre-booted configuration for the stack, our system will have to create a virtual machine for your selected configuration when your build starts. This means that your build will be in preparing environment state while the related virtual machine is created & booted. For a macOS configuration the boot process usually takes about 1 - 1.5 minutes. The prepare time (of course) is not counted into the build time, it won’t affect how long your build can run. | --- ## Changelog(Build-stacks) ### June 2025 **Changed** Mentions of Linux stack update policy has been moved on its own page, [Linux stack update policy](/bitrise-build-hub/infrastructure/build-stacks/linux-stack-update-policy), with more information on Edge, Stable and Frozen stacks. It also describes the yearly cadence of new Linux stacks, as well as the deprecation and removal of older Linux stacks. Removed how to use previous versions of a stack from this page and added it to [Stack update policy](/bitrise-build-hub/infrastructure/build-stacks/stack-update-policy). ### July 2024 **Removed**: Mentions of dependency manager cache updates. Both Cocoapods and Homebrew have better mechanisms now than cloning the entire registry git repo, and these newer mechanisms (Cocoapods CDN, Homebrew API) are enabled on stacks now. When stacks are updated, you can expect the on-disk repos to be up-to-date, but Stable stacks are no longer strictly updated weekly if there are no other changes to release. **Changed**: The breaking changes to stable macOS stacks (once a year when a new Xcode major version is released) no longer apply to older, existing stable stacks, only the newly released stable stack. For example, when Xcode 16.0 is released, the planned breaking changes only apply to the Xcode 16.0 stable stack. Xcode 14.x and 15.x stable stacks won’t receive breaking changes. ### March 2024 **New**: Define what happens when an Edge stack is phased out in favor of a newer edge stack. **Removed**: When a new Xcode Edge stack is released, it no longer brings tooling changes to the Stable stacks. **Changed**: New, simpler simulator runtime policy. The same number of older iOS major versions are installed, but only the latest minor version is installed for each. --- ## Linux stack update policy(Build-stacks) Linux stacks on Bitrise are based on Ubuntu LTS releases. Each Bitrise stack is based on one Ubuntu LTS version and never gets upgraded to another. Instead, we release new stacks and sunset older ones over time. :::note[Previous version of a stack] Updating a stack to a new version might cause problems with some builds. To help ease the transition, you can use the previous version of a stack for 2-3 days after an update: [Using the previous version of a stack](/bitrise-build-hub/infrastructure/build-stacks/stack-update-policy#using-the-previous-version-of-a-stack). ::: For macOS specific information, check out [macOS stack update policy](/bitrise-build-hub/infrastructure/build-stacks/macos-stack-update-policy). ### Linux stack offerings Bitrise offers multiple Linux stacks to handle different use-cases. You can check the available stacks at any given time [here](https://bitrise.io/stacks/). Each stack is based on one release of a Linux distribution. At the moment, we offer stacks based on Ubuntu LTS releases. Tools are installed on this base image, creating the Bitrise edition of a system. The stack name and ID contains all of the above parameters and looks like this in practice: - Name: Ubuntu Noble 24.04 - Bitrise 2025 Edition - ID: `ubuntu-noble-24.04-bitrise-2025-android` There are subtle differences between the different Linux stacks and their update frequency. You need to be aware of these details in order to pick the right stack and to avoid sudden broken builds. ### Linux stack updates A new Bitrise edition and a new stack is created each year. This is always based on the latest Ubuntu LTS release. Besides the new Ubuntu release, this new yearly Bitrise edition contains breaking changes that would have been too disruptive to ship in existing stacks. For example: - Upgrading a preinstalled tool to a new version with breaking changes. - When multiple versions of a tool are installed (for example, Ruby, Node.js,), removing an old version that reached its end-of-life and no longer receives security fixes. - Configuration changes that could be breaking to some or all user workflows. | Year of stack release | Stack name | Ubuntu base | | --- | --- | --- | | 2024 | Ubuntu Jammy 22.04 - Bitrise 2024 Edition | Ubuntu 22.04 LTS | | 2025 | Ubuntu Noble 24.04 - Bitrise 2025 Edition | Ubuntu 24.04 LTS | | **Future releases** (release codenames are unknown at this point) | | | | 2026 | Ubuntu 26.04 - Bitrise 2026 Edition | Ubuntu 26.04 | | 2027 | Ubuntu 26.04 - Bitrise 2027 Edition | | | 2028 | Ubuntu 28.04 - Bitrise 2028 Edition | Ubuntu 28.04 | | 2029 | Ubuntu 28.04 - Bitrise 2029 Edition | | ### Stack lifecycle Similar to macOS Bitrise stacks, the Linux ones have the following lifecycle: Edge, Stable, Frozen, Removed. A new stack is introduced as an edge stack first, then, after a year of testing and feedback, it becomes a stable stack. One year later it’s marked as frozen, then completely removed after one more year. Different stages of a single stack: ![stack-state-change.svg](/img/_paligo/uuid-5169df38-e851-52da-fb4f-d37c3f98e8d8.svg) Every year, around April and the release of the new Ubuntu version: - A new stack is introduced as an edge stack. - Last year’s edge stack becomes stable. - Last year’s stable stack becomes frozen. - Last year’s frozen stack gets removed. Changing states presented with previous and future stacks: ![multiple-stack-state-change.svg](/img/_paligo/uuid-bcc68f5e-feec-8292-2e57-1bfb0dd9d9b9.svg) Before a stack is removed, it’s flagged for removal, and you see the final removal date throughout the UI. Additionally, the remaining users of the stack receive an email notification from Bitrise. ### Which stack to choose? At any given time, you can choose from at least one edge, stable and frozen stack. The following table helps make this choice: | | Edge | Stable | Frozen | | --- | --- | --- | --- | | Stable stack ID which can be included in bitrise.yml | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Security updates to OS components, system libraries and preinstalled tools | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Updates to OS components and system libraries | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Addition of new tools and tool versions | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Breaking changes in stack updates to existing tools and tool versions | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | New experimental features and configuration changes | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | | Removal of tools and tool versions | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ![close-small.svg](/img/_paligo/uuid-5de915cb-051d-9584-d965-a36295c3f83c.svg) | ### Changelog June 2025 **New** Introduced the concept of Edge, Stable and Frozen stacks with regards to Linux, similar to the [macOS stack update policy](/bitrise-build-hub/infrastructure/build-stacks/macos-stack-update-policy). Defined the yearly cadence of new Linux stacks, as well as the deprecation and removal of older Linux stacks. --- ## macOS stack update policy(Build-stacks) ### Xcode stack updates You can select macOS stacks based on the Xcode version you need. Under the hood, one VM image contains multiple Xcode versions installed and your requested Xcode version is activated at runtime before your Workflow starts. As a rule of thumb, Xcode minor versions of the same major version share the same VM image, but there might be exceptions based on compatibility issues and other considerations. :::note[Versioning] When talking about versions, we use [semver](https://semver.org/) terminology, regardless of how the various tools define their versions. ::: Stacks have a lifecycle and have four different states: Edge, Stable, Frozen and Removed. ![stack-lifecycle.png](/img/_paligo/uuid-faa7bf60-0cae-0042-f910-e8e6240fc647.png) - **Edge**: These stacks are for previewing upcoming versions and changes. They are updated in-place regularly, and they include the latest stable release of Xcode, the latest beta release of Xcode (if available) and the latest stable version of pre-installed tools. Regular weekly updates could add or remove tools, as well as upgrade the OS. Backwards compatibility for weekly updates is not guaranteed on an Edge stack. Run builds on Edge stacks to preview upcoming tool version changes (such as Ruby 3.2 becoming the default) and get access to the latest pre-release Xcode (such as Xcode 15 Beta). - **Stable**: These stacks are only updated with Xcode patch versions, and with critical security fixes. For maximum reliability and reproducible builds, we recommend pinning exact tool versions in Workflows instead of relying on the stack defaults (for example, pinning a Ruby version). - **Frozen**: These stacks are no longer updated and flagged for removal in accordance with the [Stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). The stack is still available for yourbuilds but you will see the final removal date on the UI. Preinstalled tools are not updated, so it’s your responsibility to keep up with bugfixes and security patches. - **Removed**: These stacks are no longer available to use. #### State transitions for Xcode stacks During the lifecycle of a stack it will transition between states when triggered by new Xcode and macOS releases. Stacks transition as follows: - Edge to Stable. - Stable to Frozen. - Frozen to Removed. ##### Edge stack updates Edge stacks provide a way to preview and test upcoming changes. Xcode Beta versions become available as Edge stacks while final Xcode releases become available as new Stable stacks. Xcode Edge stacks change when: 1. The first Beta version of a new major Xcode version is released. 1. The first Beta version of a new minor Xcode version is released. 1. A new version of an Xcode Beta version is released. When an Xcode minor version is released as a beta, it becomes available as an Edge stack. Other Edge stacks do not transition to Stable until the beta version in question is released as a GA version. **First Beta version of a new major Xcode version** In this example: - The current latest Xcode version is 15.3. - A new Beta version of a new major Xcode version is released: Xcode 16.0 Beta 1. ![stack-updates-edge.png](/img/_paligo/uuid-1aecaab6-06d6-4a03-4d67-f6e4e5efaf7e.png) Once the new Beta version is released, we update our stacks: - The new Xcode release becomes available on Bitrise as an Edge stack. In our example, Xcode 16.0 Beta 1 becomes available as the Edge stack. - Current Edge stacks are phased out, and users are automatically migrated to the new Edge stack. This happens a few days after the new Xcode release. In this example, this means phasing out Xcode 15.x Edge stacks. - Stable stacks are not affected at this point. **First Beta version of a new minor Xcode version** In this example: - The current latest Xcode version is 15.2. - A new Beta version of a new minor Xcode version is released: Xcode 15.3 Beta 1. ![stack-updates-edge-minor.png](/img/_paligo/uuid-1045ef58-753d-f496-2c8a-4e4c9542ad63.png) Once the new Beta version is released, we update our stacks: - The new Xcode release becomes available as an Edge stack. In this example, Xcode 15.3 Beta 1 becomes available as an Edge stack. - Stable stacks are not affected at this point. **A new Beta version of an Xcode Beta version** In this example: - The current latest Xcode version is 16.0 Beta 1. - A new Beta version is released: 16.0 Beta 2. ![stack-updates-edge-beta.png](/img/_paligo/uuid-f91e8132-cff5-b5c3-142e-2184b4883382.png) Once the new Beta version is released, we update our stacks: - Xcode 16.0 Beta 2 replaces 16.0 Beta 1 on the Xcode 16.0 Edge stack. - Stable stacks are not affected at this point. ##### Stable stack updates Stable stacks change less often than Edge stacks as we want to avoid unexpected breaking changes on these stacks. Existing Stable stacks change when: 1. A new major Xcode version is released. 1. A new minor Xcode version is released. **A new major Xcode version** In this example: - The current latest Xcode version is 15.3.0. - A new major Xcode version is released: Xcode 16.0. ![stable-stack.png](/img/_paligo/uuid-0d392a7d-4fcd-13cb-e67a-7326e954c87a.png) When the new major version is released, we update our stacks: - New Stable stack: Xcode 16.0 becomes available on Bitrise as a new Stable stack. - Oldest Stable stacks become Frozen. In this example, Xcode 14.x stacks become Frozen, but still available for building. Tool versions are not changing on these stacks: their latest state is frozen. - Old Frozen stacks are removed: in this example, Xcode 13.x stacks are removed. The remaining users are migrated to newer stacks. **A new minor Xcode version** In this example: - The current latest Xcode version is Xcode 15.2. - A new minor Xcode version is released: Xcode 15.3. When the new minor version is released, we update our stacks: - New Stable stack: Xcode 15.3 becomes available on Bitrise as a Stable stack. - Xcode 15.3 Edge stack is updated with the final Xcode version. ![stack-updates-stable-xcode-minor.png](/img/_paligo/uuid-166098b3-ad6e-d65e-fe83-e0819fcf52a3.png) ##### macOS releases The exact macOS version is always highlighted on the [stack report pages](https://stacks.bitrise.io/stack_reports/). When a new major macOS version is released, we upgrade the Edge stacks to the new OS after an internal testing period. As a general rule, we don’t upgrade macOS on Stable stacks to avoid unexpected build failures. We wait until a future Xcode release starts requiring the new OS version (for example, Xcode 15.0, 15.1 and 15.2 are compatible with macOS Ventura, but 15.3 requires Sonoma). Once this happens, the Stable stack variant of this Xcode version is based on the new major OS version, while older Stable Xcode stacks remain on the older OS version. While the new major OS is not available as a Stable stack, we recommend testing it on one of the Edge stacks. We are looking for your feedback, including edge cases and performance regressions. ##### Events not triggering a state transition Not all Xcode releases trigger a transition. For example, Xcode beta minor version releases do not trigger an Edge to Stable stack transition: the new beta version simply replaces the old one. Xcode patch releases do not trigger an Edge to Stable stack transition. Instead, the Stable stacks will be updated in place with the new patch version. #### Simulator runtimes on Xcode stacks You can find the list of preinstalled tools, including simulator runtimes on our stacks on the [stack reports pages](https://stacks.bitrise.io/stack_reports/). You can expect the following simulator runtimes to be installed: - The matching runtime versions of a given Xcode version: these are the iOS, watchOS, tvOS and visionOS runtime versions that Xcode prompts you to download at first launch. - For iOS, we also install two additional versions: the two previous major versions, of which the latest minor version is installed. - For watchOS, we also install the previous major release’s latest minor version. For example, when selecting the Xcode 15.0 stack, you can expect: - iOS 17.0: the matching runtime of this Xcode. - iOS 16.4: the latest minor release of the previous major iOS version. - iOS 15.5: the latest minor release of the second-previous major iOS version. - watchOS 10.0: the matching runtime of this Xcode. - watchOS 9.4: the latest minor release of the previous major version. - tvOS 17.0: the matching runtime of this Xcode. - visionOS 1.0: the matching runtime of this Xcode ### Changelog #### June 2025 **Changed** Mentions of Linux stack update policy has been moved on its own page, [Linux stack update policy](/bitrise-build-hub/infrastructure/build-stacks/linux-stack-update-policy), with more information on Edge, Stable and Frozen stacks. It also describes the yearly cadence of new Linux stacks, as well as the deprecation and removal of older Linux stacks. Removed how to use previous versions of a stack from this page and added it to [Stack update policy](/bitrise-build-hub/infrastructure/build-stacks/stack-update-policy). #### July 2024 **Removed**: Mentions of dependency manager cache updates. Both Cocoapods and Homebrew have better mechanisms now than cloning the entire registry git repo, and these newer mechanisms (Cocoapods CDN, Homebrew API) are enabled on stacks now. When stacks are updated, you can expect the on-disk repos to be up-to-date, but Stable stacks are no longer strictly updated weekly if there are no other changes to release. **Changed**: The breaking changes to stable macOS stacks (once a year when a new Xcode major version is released) no longer apply to older, existing stable stacks, only the newly released stable stack. For example, when Xcode 16.0 is released, the planned breaking changes only apply to the Xcode 16.0 stable stack. Xcode 14.x and 15.x stable stacks won’t receive breaking changes. #### March 2024 **New**: Define what happens when an Edge stack is phased out in favor of a newer edge stack. **Removed**: When a new Xcode Edge stack is released, it no longer brings tooling changes to the Stable stacks. **Changed**: New, simpler simulator runtime policy. The same number of older iOS major versions are installed, but only the latest minor version is installed for each. --- ## Managing Java versions By default, every Bitrise stack comes with [multiple Java versions](https://stacks.bitrise.io/tools/java/) pre-installed and ready to use. If you do not switch to another version, your build will use the default Java versions. You can switch between the versions at any time. You can also install a different Java version. :::tip[Configuring other tools] For other tools, you can specify the version you want to use in your builds: [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions). ::: ### Setting Java version with the Set Java version Step Each Bitrise stack has multiple different [Java versions](https://stacks.bitrise.io/tools/java/) pre-installed and ready to use. You can easily switch between the different Java versions with our [**Set Java version** Step](https://www.bitrise.io/integrations/steps/set-java-version). The Step allows you to set the global Java version of the virtual machine that runs your build. This Step cannot install any Java version. It can only switch between the versions that are pre-installed on our stacks. 1. Add the **Set Java version** Step to your Workflow. We recommend setting it as the first Step of the Workflow. 1. Find the **Java version** input. 1. Set it to the version you need. **YAML example** In this example, we're setting the Java version to 17 in the `bitrise.yml` file. ```yaml primary: steps: - set-java-version@1: inputs: - set_java_version: '17' ``` --- ## Preinstalled tools on Bitrise stacks Every Bitrise stack comes up with a large number of preinstalled tools and applications to make sure the build process of your projects is as smooth and fast as possible. Every time we create or update a stack we publish a stack report for it as well. The stack reports include the list of preinstalled tools and their version on the stack. Both macOS and Linux stacks are updated regularly to provide the latest installed tool versions: - [macOS stack update policy](/bitrise-build-hub/infrastructure/build-stacks/macos-stack-update-policy). - [Linux stack update policy](/bitrise-build-hub/infrastructure/build-stacks/linux-stack-update-policy). You can find every available stack’s stack report on our dedicated page: [Bitrise stack reports](https://stacks.bitrise.io/stack_reports/). :::tip[Configuring tool versions] You can tell Bitrise which tool versions to use or to install tools not found on the build machines. For more information, see: [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions). ::: --- ## Stack deprecation and removal policy(Build-stacks) We don't keep all stacks around forever: our aim is to provide you with the latest tools to help you build the best app you can. However, we don't expect you to rework your build configuration every time a stack update comes out: you can keep using your reliable older stacks for a long time. Some older stacks are frozen when a new major version of Xcode is released. When a stack is frozen, you can still keep using it, but the stack will no longer get any updates, and at that point, we strongly recommend switching to a newer, active stack. After stacks have been frozen for a year, they are removed when the next major version of Xcode is released. ### Maintaining Xcode stacks We offer a wide variety of Xcode stacks in order to make sure you do not need to immediately switch when a new version comes out. Our policy is as follows: - Keep the three most recent major versions of Xcode. - Keep the two most recent minor versions for each major version of Xcode. We base our policy on Apple's current release cadence: first beta in June, general availability in September. 1. The life cycle of a major Xcode version on our stacks is 36 months. 1. For 24 months, the stack is active and maintained according to our stack update policy. 1. After 24 months, the stack becomes frozen for 12 months and it will no longer receive updates. At this point, we strongly recommend migrating to an active stack. 1. After the end of the 36th month, the stacks of the major Xcode version are removed. **Maintaining Xcode stacks** When Xcode version 15.2.x is released, we will keep: All the latest patch releases for the two most recent minor versions of Xcode 15: - 15.2 - 15.1 Xcode 15.0 will be removed. The two latest versions from the previous two Xcode major versions: - Xcode 14.3 - Xcode 14.2 - Xcode 13.4 (frozen) - Xcode 13.3 (frozen) In all cases, there will be a minimum of four weeks' notice provided for the removal of these stacks. You can see all upcoming stack deprecations [on this page](https://stacks.bitrise.io/announcements/upcoming-stack-deprecations/). We also recommend subscribing to [RSS updates](https://stacks.bitrise.io/tips/get-notified/) of important announcements about stacks. ### Deprecating Linux stacks A Linux stack is supported for about two years, roughly in sync with [Ubuntu LTS (long term support)](https://endoflife.date/ubuntu) releases. When a previous Linux stack reaches end of maintenance, we deprecate the stack and earmark it for removal. At that point you can no longer select the stack for your apps. But the apps that are already using those stacks can keep using them until removal. In all cases, there will be a minimum of four weeks' notice provided for the removal of these stacks. You can see all upcoming stack deprecations [on this page](https://stacks.bitrise.io/announcements/upcoming-stack-deprecations/). We also recommend subscribing to [RSS updates](https://stacks.bitrise.io/tips/get-notified/) of important announcements about stacks. --- ## Stack update policy(Build-stacks) Bitrise stacks include the most important tools for mobile development pre-installed and ready for use. Our goal is to make Workflows simple and make your builds fast and efficient. These tools change continuously: old versions become deprecated and unsupported while new versions are released with new features and breaking changes. Stacks on [bitrise.io](https://www.bitrise.io) are updated regularly. The updates contain one or more of the following kinds of changes: - Tool upgrade: An already installed tool is upgraded to the latest version (for example, the git CLI is upgraded from 2.9.1 to 2.9.5). - Tool addition: A new tool is added (for example, the latest Android emulator system image becomes preinstalled when a new Android version is released). - Tool removal: A tool version is removed if it reaches end-of-life and poses a security risk, making another version of the tool the default (for example, Ruby 2.7 is removed, making Ruby 3.0 the new default). - Platform changes: Changes to major components, like Xcode on macOS stacks, OS versions, Android SDK. If you wish to read more on our Linux and MacOS stack update policies, check out: - [macOS stack update policy](/bitrise-build-hub/infrastructure/build-stacks/macos-stack-update-policy) - [Linux stack update policy](/bitrise-build-hub/infrastructure/build-stacks/linux-stack-update-policy) :::note[Using the previous version of a stack] Updating a stack to a new version might cause problems with some builds. To help ease the transition, you can use the previous version of a stack for 2-3 days after an update: [Using the previous version of a stack](/bitrise-build-hub/infrastructure/build-stacks/stack-update-policy#using-the-previous-version-of-a-stack). ::: For more information on what tools are available on the different stacks, check out our relevant guide: [Preinstalled tools on Bitrise stacks](/bitrise-platform/infrastructure/build-stacks/preinstalled-tools-on-bitrise-stacks) ### Using the previous version of a stack We regularly update the Bitrise stacks based on user requests and external tooling changes. These updates can potentially introduce breaking changes, despite our efforts to avoid those. For those cases, we provide a temporary option to use the previous version of a given stack for a few days after the release of a new version. - This is meant to be a temporary mechanism only. Because of infrastructure reasons, we can't keep the previous release available forever. Usually, the previous version is removed a few days after a successful release. - Once the previous version becomes unavailable, new builds run on the latest version even if this feature is enabled. - If a previous version is not available for a given stack at a given time, the switch is inactive and the feature can't be turned on. Any build triggered will run on the current version of the stack. To use the previous version of your stack: **Workflow Editor** 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. ![workflows-button.png](/img/_paligo/uuid-99bb894c-3e79-91c8-9e62-7e475573495d.png) 1. Go to the **Stacks & Machines** tab. 1. Find the stack you want to configure: either the default stack or one of the Workflow-specific stacks. 1. Under the machine type for the chosen stack, toggle the **Use previous version** switch. This modifies the `bitrise.yml` file: it adds the previous version of the stack to the `meta` block. ![prev-vers.png](/img/_paligo/uuid-eefe9d3d-ab41-f2c3-9657-97994dab1f73.png) **Configuration YAML** 1. Find the `meta` block in your `bitrise.yml` file. 1. Add a `stack_rollback_version` field with the given version string. :::tip[Finding out the previous version number] To find out the previous version string, open an older build, switch to the **Details** tab, and look for the **Stack image version** field. ::: ```yaml meta: stack: osx-xcode-15.0.x machine_type_id: g2-m1.8core stack_rollback_version: 2-16-2 ``` --- ## The Android/Linux/Docker environment For our Linux-based stacks, we use standard Docker images, hosted on [Docker Hub](https://hub.docker.com/). You can find the available stacks, called **Ubuntu for Android & Docker**, in our [stack reports](https://stacks.bitrise.io/stack_reports/). :::note[Pre-installed tools] All stacks have a large number of pre-installed tools available: [Preinstalled tools on Bitrise stacks](/bitrise-platform/infrastructure/build-stacks/preinstalled-tools-on-bitrise-stacks) ::: Every build runs in a new VM, not just in a new container. The VM is destroyed right after the build. This allows us to grant you full control over `Docker` and the whole environment. When your build starts on a Docker-based stack, we volume mount the `/var/run/docker.sock` socket into your container (similar to calling `docker run -v /var/run/docker.sock:/var/run/docker.sock ...`. You can find a description about this access granting method [here](https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/)). The `docker` binary has to be installed inside the base Docker image because docker started to migrate from a single-binary solution to dynamically loaded components, and simply sharing the `docker` binary is not sufficient anymore. We install Docker in every one of our Docker images so that you don’t have to do anything if you use our image, or you base your own image on our Docker images. This means that you have access to `docker` in your container, and can use other tools which use docker, like [docker-compose](https://docs.docker.com/compose). You can, for example, configure and run tests and other automations on website projects using `docker-compose`. You can call `docker info`, `docker build`, `docker run`, `docker login`, `docker push` exactly how you would on your own machine. :::note[Shared volumes] If you want to run `docker` in your build and share volumes, please note that only those volumes can be shared that are shared with the base docker container (the one your build is running in). This is due to how `docker` handles volume sharing. Everything under `/bitrise` can be mounted as a volume, but no other path is guaranteed to work with `--volume` mapping. It means that if you use the standard paths and you use relative paths to mount volumes, it’ll work as expected, as the default source code directory is located inside `/bitrise` (by default it’s `/bitrise/src` in our Docker images). What WON’T WORK, however, is if you change the source code directory to be located outside of `/bitrise`, or you want to mount a folder with an absolute path outside of `/bitrise`. ::: --- ## Cleaning up persistent build environments On Bitrise, a new virtual machine is created every time a build starts and it is destroyed when the build is finished. You can, however run Bitrise builds in a persistent build environment: for example, you can use [our on-premise runner](/bitrise-platform/infrastructure/running-bitrise-builds-on-premise) or [run builds on an Amazon EC2 instance](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances). In such an environment, the products of one build might affect subsequent builds. On self-hosted infrastructure, one Bitrise runner executes multiple builds. This allows sharing data between builds on the local filesystem, but it also requires care in order to avoid one build affecting another. To avoid the problem, you can configure the Bitrise CLI to run in **agent mode**. Agent mode requires placing an `agent-config.yml` in the host machine's `~/.bitrise/` directory. In the file, you can specify which directories to clean up when starting a new build or at the end of a build. It also allows you to run your own custom scripts if you have a more advanced use case than a simple cleanup. :::note[Secrets in self-hosted environments] In a self-hosted environment, you might not be able to host your Secrets on bitrise.io. To make sure your build configuration can still use Secrets, check out our guide: [Secrets in self-hosted environments](/bitrise-ci/configure-builds/secrets#secrets-in-self-hosted-environments). ::: ### Configuring agent mode **macOS** 1. Add the `agent-config.yml` file to your `~/.bitrise/` directory. 1. If you wish to configure the exact folders in which you want to do cleanup operations, define a `bitrise_dirs` property. The property overrides the default settings: for example, you can set a different path for the BITRISE_DEPLOY_DIR environment variable than the default. 1. Under `bitrise_dirs`, define the directories that you wish to perform some action on at the start or at the end of builds in a `KEY: path` format. For example, you can define separate directories for all source code checkout, deployable artifacts, and deployable test result artifacts. ```yaml # Customize the common Bitrise directories bitrise_dirs: # Root directory for all Bitrise data produced at runtime BITRISE_DATA_HOME_DIR: /Users/ec2-user/bitrise # Directory for source code checkout. BITRISE_SOURCE_DIR: /Users/ec2-user/bitrise/workspace/$BITRISE_APP_SLUG # Directory for deployable artifacts. BITRISE_DEPLOY_DIR: /Users/ec2-user/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/artifacts # Directory for deployable test result artifacts. BITRISE_TEST_DEPLOY_DIR: /Users/ec2-user/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/test_results # Directory for the html reports BITRISE_HTML_REPORT_DIR: /Users/ec2-user/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/html_reports ``` :::caution[Multiple projects of the same Workspace] Don’t forget that multiple projects of the same Workspace could run on the same agent. Make sure to always include $BITRISE_APP_SLUG in the directory hierarchy to separate projects and their source code checkouts. ```yaml # wrong: BITRISE_SOURCE_DIR: /opt/bitrise/workspace # correct: BITRISE_SOURCE_DIR: /opt/bitrise/workspace/$BITRISE_APP_SLUG ``` ::: 1. Add a `hooks` property to the `agent-config.yml` file. This property will define the actions to perform at the start or end of builds. It has four different parameters: - `cleanup_on_build_start`: Defines a directory that is cleaned up when a new build is started. - `cleanup_on_build_end`: Defines a directory that is cleaned up whenever a build is finished. Not guaranteed to run in the case of build failure. - `do_on_build_start`: Defines a custom script that runs when a new build is started. - `do_on_build_end`: Defines a custom script that runs when a build is finished. Not guaranteed to run in the case of build failure. :::important[Nested Workflows] A [**Script**](https://github.com/bitrise-io/steps-script) Step in a Workflow can execute `bitrise run nested_workflow` and trigger a nested workflow. This nested Workflow inherits all the envs and parameters of the parent Workflow, and the parent Workflow waits for the completion of the nested Workflow. When the nested Workflow is launched this way, hooks and directory cleanups are not executed in this process to avoid unexpected behavior. ::: 1. To test the agent mode, start a build. The log should show the following message at the top: ```yaml Running in agent mode Config file: .bitrise/agent-config.yml ``` **Linux** 1. Add the `agent-config.yml` file to your `~/.bitrise/` directory. 1. If you wish to configure the exact folders in which you want to do cleanup operations, define a `bitrise_dirs` property. The property overrides the default settings: for example, you can set a different path for the BITRISE_DEPLOY_DIR environment variable than the default. 1. Under `bitrise_dirs`, define the directories that you wish to perform some action on at the start or at the end of builds in a `KEY: path` format. For example, you can define separate directories for all source code checkout, deployable artifacts, and deployable test result artifacts. ```yaml # Customize the common Bitrise directories bitrise_dirs: # Root directory for all Bitrise data produced at runtime BITRISE_DATA_HOME_DIR: /opt/bitrise # Directory for source code checkout. BITRISE_SOURCE_DIR: /opt/bitrise/workspace/$BITRISE_APP_SLUG # Directory for deployable artifacts. BITRISE_DEPLOY_DIR: /opt/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/artifacts # Directory for deployable test result artifacts. BITRISE_TEST_DEPLOY_DIR: /opt/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/test_results # Directory for the html reports BITRISE_HTML_REPORT_DIR: /opt/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/html_reports ``` :::caution[Multiple projects of the same Workspace] Don’t forget that multiple projects of the same Workspace could run on the same agent. Make sure to always include $BITRISE_APP_SLUG in the directory hierarchy to separate projects and their source code checkouts. ```yaml # wrong: BITRISE_SOURCE_DIR: /opt/bitrise/workspace # correct: BITRISE_SOURCE_DIR: /opt/bitrise/workspace/$BITRISE_APP_SLUG ``` ::: 1. Add a `hooks` property to the `agent-config.yml` file. This property will define the actions to perform at the start or end of builds. It has four different parameters: - `cleanup_on_build_start`: Defines a directory that is cleaned up when a new build is started. - `cleanup_on_build_end`: Defines a directory that is cleaned up whenever a build is finished. Not guaranteed to run in the case of build failure. - `do_on_build_start`: Defines a custom script that runs when a new build is started. - `do_on_build_end`: Defines a custom script that runs when a build is finished. Not guaranteed to run in the case of build failure. :::important[Nested Workflows] A [**Script**](https://github.com/bitrise-io/steps-script) Step in a Workflow can execute `bitrise run nested_workflow` and trigger a nested workflow. This nested Workflow inherits all the envs and parameters of the parent Workflow, and the parent Workflow waits for the completion of the nested Workflow. When the nested Workflow is launched this way, hooks and directory cleanups are not executed in this process to avoid unexpected behavior. ::: 1. To test the agent mode, start a build. The log should show the following message at the top: ```yaml Running in agent mode Config file: .bitrise/agent-config.yml ``` ### Common configuration examples **Fully isolated builds** To minimize state and maximize reliability, each build is assigned unique directories. Source code is checked out from scratch in each build. ```yaml bitrise_dirs: BITRISE_DATA_HOME_DIR: /opt/bitrise BITRISE_SOURCE_DIR: /opt/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/workspace BITRISE_DEPLOY_DIR: /opt/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/artifacts BITRISE_TEST_DEPLOY_DIR: /opt/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/test_results BITRISE_HTML_REPORT_DIR: /opt/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/html_reports hooks: # Since dirs are unique to each build, there is nothing to clean up here: cleanup_on_build_start: [] # Clean up everything after the build ends: cleanup_on_build_end: - $BITRISE_SOURCE_DIR - $BITRISE_DEPLOY_DIR - $BITRISE_TEST_DEPLOY_DIR - $BITRISE_HTML_REPORT_DIR ``` **Shared source code directory for warm checkouts** For faster source code checkouts, it’s possible to reuse a previous build’s source code directory. ```yaml bitrise_dirs: BITRISE_DATA_HOME_DIR: /opt/bitrise # Use a warm clone of the repo for all builds: BITRISE_SOURCE_DIR: /opt/bitrise/$BITRISE_APP_SLUG/workspace # For artifacts and test results, it's still a good idea to place them into unique dirs BITRISE_DEPLOY_DIR: /opt/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/artifacts BITRISE_TEST_DEPLOY_DIR: /opt/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/test_results BITRISE_HTML_REPORT_DIR: /Users/ec2-user/bitrise/$BITRISE_APP_SLUG/$BITRISE_BUILD_SLUG/html_reports hooks: # Since dirs are unique to each build, there is nothing to clean up here: cleanup_on_build_start: [] # Optional: clean up artifacts and test results. # Note that $BITRISE_SOURCE_DIR is NOT clean up here! cleanup_on_build_end: - $BITRISE_DEPLOY_DIR - $BITRISE_TEST_DEPLOY_DIR - $BITRISE_HTML_REPORT_DIR ``` --- ## Code security To guarantee the security of your code, every Bitrise build runs in its own, clean virtual machine and we discard the whole virtual machine after the build finishes, erasing every file your build uses and every change you make during your build. This is also true for the Android & Docker stacks, which use Docker containers to run the build. The build itself still gets a full virtual machine where no other Docker container is started, only the one used as the environment of the build. In short, we only use Docker containers to manage the environment, not for build environment isolation - that’s ensured by using full virtual machines for every build. This way your builds are always protected from changes made by others and from your previous builds, no one else can access your code and you can use a stable environment to define your build Workflow. Every build is completed in an isolated environment, unrelated to any previous or parallelly running builds. ### Source code We don’t store your source code. The source code is only accessed on the build machines (virtual machines) the way you define it in your [Bitrise configuration](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml). If you don’t have a **Git Clone** Step or some other Step that accesses your Git repository in your configuration, then the source code won’t be touched at all. At the end of the build the whole virtual machine is destroyed. As such, any change you made to your source code on the virtual machine will be lost unless you commit your changes and push them to a remote repository. ### Code signing and other files The files you upload in the **Code Signing** tab of the Workflow Editor are stored on `Amazon S3` in a way that it’s only accessible for the web servers. The required credentials are not stored in any database, it is only available in the web servers’ environment. Build servers can’t access the files directly either. When a build starts, the web server generates a read-only, time limited access URL for these files, using [Amazon S3 pre-signed URLs](https://docs.aws.amazon.com/aws-sdk-php/v3/guide/service/s3-presigned-url.html). ### Passwords Passwords are stored in a hashed, encrypted form. We are encrypting the passwords with [bcrypt algorithm](https://en.wikipedia.org/wiki/Bcrypt), using multiple stretches. --- ## Configuring runner pools You can run Bitrise builds on hardware you control. We offer two different options: - [Running builds on Amazon EC2 instances](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances). - [Using our on-premise runner](/bitrise-platform/infrastructure/running-bitrise-builds-on-premise) to run builds on your own machines, or at other cloud providers. Both options require setting up runner pools in your Bitrise Workspace. This reserves build runners for use in your self-hosted builds. Each reserved pool comes with a unique token: this token is required for both an Amazon EC2 instance and the on-premise runner to be able to connect to your Bitrise Workspace and run builds of the apps owned by the Workspace. You can configure and run these builds from the Workflow Editor, as any other build. To do so: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Infrastructure**. 1. Select the **Bitrise runners** tab. 1. In the **Runner pools** section, click **Add new**. ![_2025-11-03-runner-pool.png](/img/_paligo/uuid-3ca810bc-4569-859b-f0be-784644322a22.png) 1. Type a name into the **Name** field then click **Next**. ![add-pool.png](/img/_paligo/uuid-e5387f19-bcbb-472b-a2fa-9c9d9aeb1c6d.png) 1. You will receive a token. Copy this token: you will need it for authentication. 1. Open the app you need on Bitrise and click **Workflows**. 1. Click **Edit bitrise.yml** to go the Workflow Editor, and select **Stacks & Machines** on the left navigation menu. 1. Find your own stack in the stack selection dropdown menus: it will be called **Self-Hosted Runner: **. ![stack-select.png](/img/_paligo/uuid-1ec5901d-3577-8321-6e4f-faa9fa366c21.png) For example, if you named your pool `my-pool`, the stack will be called **Self-Hosted Runner: my-pool**. 1. Click **Save** in the top right corner. Now your builds will run using the reserved runner pools --- ## Customizable enterprise build platforms Bitrise offers fully-managed build platforms tailored to the needs of [enterprise](https://bitrise.io/pricing) customers. Using a custom enterprise build platform means running your Bitrise builds on virtual machines (VM) dedicated and specifically configured to your needs. With a private cloud, you have complete control over how and when your builds run. Bitrise offers three types of custom build platforms for enterprises: - Dedicated build platform: a set of dedicated machines behind the Bitrise firewall that serve our public and dedicated pools. These virtual build machines will be seen from [the same public IP address as any Bitrise build machine](/bitrise-platform/infrastructure/build-machines/configuring-your-network-to-access-our-build-machines) but the build nodes (the hypervisors running the virtual build machines) are reserved for your exclusive use during the build. - Dedicated plus build platform: same setup as the dedicated build platform with additional IP range reserved for the customer for increased network secure connection. - Private build platform: the private machines are reserved for your exclusive use at all times. The solution also is provisioned to you and includes your own firewall, more flexible storage capacity options, and a more flexible computing environment setup. It allows you to create custom virtualization configuration, as well as includes [site-to-site VPN option](/bitrise-platform/integrations/connecting-to-a-vpn-during-a-build). The private build platform is an advanced set-up with plenty of configuration options. To learn more about the details, [contact us](https://bitrise.io/contact)! Check out the most important differences between the dedicated and the private build platforms: | Available service | Dedicated build platform | Dedicated plus build platform | Private build platform | | --- | --- | --- | --- | | Reserved IP address | - | Yes | Yes | | Private network with a dedicated firewall | - | - | Yes | | High Availability continental US setup, served by multiple Bitrise Data Centers for redundancy | Yes | Yes | Yes | | Served from single EU Bitrise Data Center without redundancy | Yes | Yes | Yes | | macOS virtual machines tailored to unique Enterprise requirements | Served by M4 Pro 14-core, M4 10-core or M2 Pro 12-core machines up to 54 GB RAM | | | | Linux virtual machines tailored to unique Enterprise requirements | Offering machine types between 2 vCPU 8 GB RAM and 192 vCPU 768 GB RAM powered by AMD EPYC Zen5 and Zen4 architectures. | | | | Dedicated Customer Success Engineer, who is an expert in Mobile CI/CD. | Yes | Yes | Yes | | Initial onboarding assistance for the first month with weekly calls. | Yes | Yes | Yes | | Continued CI/CD best practices mentoring with monthly check-ins from Bitrise Account Managers and Customer Success Engineers. | Yes | Yes | Yes | | Weekly Infrastructure maintenance that includes licenses for virtualization, orchestration, and data storage. | Yes | Yes | Yes | --- ## About Docker containers on Bitrise Use any Docker image as the execution environment for your Steps or as a background service: spin up a database, HTTP server, or any dependency your tests need. Using containers comes with several potential benefits: - Full control over your build environment. Install any tool, any version, without waiting on Bitrise to support it. - Dependencies live in the image. This reduces build times and complexity. No need to install them during the build itself. This reduces build times and complexity. - You can use the same environment that you use locally to test and build the app. There are two types of containers supported on Bitrise: - [Execution containers](/bitrise-platform/infrastructure/docker-containers-on-bitrise/execution-containers): You can run Steps or Step bundles within execution containers. This provides an easy, clean and reliable way to provision a build environment. - [Service containers](/bitrise-platform/infrastructure/docker-containers-on-bitrise/service-containers): Define service containers and refer to them in Steps or Step bundles to run services in the background while running a Step or Step bundle. Examples of services might include an HTTP server, a database, or any other type of executable program that you wish to run in a distributed environment. :::important[Linux only] This is a Linux-only feature. macOS-based environments are not supported. ::: ### Container nesting rules Steps and Step bundles both support their own container configuration. This creates a natural hierarchy: a step can define containers that differ from its parent bundle, and bundles can be nested within other bundles — each level can override or extend what came before. Two rules govern how configurations at different levels combine: - Execution containers follow closest-wins inheritance. Each Step uses the execution container defined nearest to it in the hierarchy—its own definition takes priority, then its parent bundle's, then its grandparent's. Only one execution container is active per Step. - Service containers accumulate additively. A Step inherits service containers from every level of its ancestry, not just the nearest one. The deeper the nesting, the more service containers a Step may have. ### Docker authentication credentials We recommend logging in with your Docker credentials when using containers. To do so, you need to provide Docker credentials when setting up containers: - Registry server: It should be a fully qualified registry server URL. This is optional if the server is already part of the image reference. - Username. - Password. These credentials must be stored as [Secrets](/bitrise-ci/configure-builds/secrets). They are used when running the `docker login` command during container setup. ### Container resource options The `docker container create` (or shorthand: `docker create`) command creates a new container from the specified image, without starting it. In your container configuration on Bitrise, you can specify additional options for the command. It shares most of its options with the `docker run` command. Bitrise supports most options for container creation. The only exceptions are: - `--network` - `--volume (-v)` - `--entrypoint` For all available options, check out [docker container create](https://docs.docker.com/reference/cli/docker/container/create/). --- ## Building your own Docker image You can create your own Docker image and push it to a container registry during a Bitrise build with the [Docker Build & Push Step](https://github.com/bitrise-steplib/bitrise-step-docker-build-push/blob/main/step.yml). The Step uses the `docker build` [command](https://docs.docker.com/engine/reference/commandline/image_build/): it requires a [Dockerfile](https://docs.docker.com/engine/reference/builder/) that contains the build instructions and a build context. Build context means the set of files located at the specified path. The Step allows you to pass [options](https://docs.docker.com/engine/reference/commandline/image_build/#options) and [build arguments](https://docs.docker.com/build/guide/build-args/) to the build. To speed up your builds, the Step also supports [key-based caching](/bitrise-ci/dependencies-and-caching/key-based-caching/accessing-key-based-cache-archives). To build the image with build options, build arguments and caching used: **Workflow Editor** 1. Add the **Docker Build & Push** Step to your Workflow. 1. Configure the required inputs for the Step: - **Image tags**: A list of tags to be applied to the name of the built image. You can add one tag per line. For more information about image tags, their function, and their required format, check out [the Docker documentation](https://docs.docker.com/engine/reference/commandline/image_tag/). - **Build context path**: The path to the files that constitute your build context. It should be relative to your Bitrise working directory. - **Dockerfile path**: The path to the Dockerfile you wish to use. It should be relative to your Bitrise working directory. 1. If you want to push the built image to a container registry, set the **Push docker image** input to **true**. 1. To cache the image, set the **Use Bitrise key-value cache** input to **true**. The input uses the following cache keys: - `docker-imagename-{{ .OS }}-{{ .Arch }}-{{ .Branch }}-{{ .CommitHash }}` - `docker-imagename-{{ .OS }}-{{ .Arch }}-{{ .Branch }}` - `docker-imagename-{{ .OS }}-{{ .Arch }}` :::caution[Alternative caching method] The Step also supports caching using the `--cache-from` and the `--cache-to` options of the `docker build` command. The **Cache from arguments** and **Cache to arguments** inputs provide this function. If using key-based caching, do NOT use these inputs! Leave them empty. ::: 1. Optionally, customize the build command with build arguments and options. - Add [build arguments](https://docs.docker.com/build/guide/build-args/) in the **Build arguments** input: one argument per line in a `MY_ARG=my_value` format. - Add [options](https://docs.docker.com/engine/reference/commandline/image_build/#options) in the **Extra options** input: one extra option per line in the format of `--option value` or `--option=value`. :::caution[Values with quotes] When using values with quotes in them (for example, when the value contains spaces) do not use the equal sign. Separate it with spaces instead: `--option "value with spaces"`. ::: 1. Optionally, set the **Enables to use the host network with the buildkit build container** input to **true** to let the build container use the host's network. Set the **Verbose logging** input to **true** for additional troubleshooting output. **Configuration YAML** 1. Add the `docker-build-push` Step to your Workflow. 1. Configure the required inputs for the Step: - `tags`: A list of tags to be applied to the name of the built image. You can add one tag per line. For more information about image tags, their function, and their required format, check out [the Docker documentation](https://docs.docker.com/engine/reference/commandline/image_tag/). - `context`: The path to the files that constitute your build context. It should be relative to your Bitrise working directory. - `file`: The path to the Dockerfile you wish to use. It should be relative to your Bitrise working directory. ```yaml workflow: steps: - docker-build-push: inputs: - tags: myregistry.com/myimage:latest - context: "./path" - file: "./Dockerfile" ``` 1. If you want to push the built image to a container registry, set the `push` input to **true**. ```yaml workflow: steps: - docker-build-push: inputs: - tags: myregistry.com/myimage:latest - context: "./path" - file: "./Dockerfile" - push: "true" ``` 1. To cache the image, set the `use_bitrise_cache` input to **true**. The input uses the following cache keys: - `docker-imagename-{{ .OS }}-{{ .Arch }}-{{ .Branch }}-{{ .CommitHash }}` - `docker-imagename-{{ .OS }}-{{ .Arch }}-{{ .Branch }}` - `docker-imagename-{{ .OS }}-{{ .Arch }}` :::caution[Alternative caching method] The Step also supports caching using the `--cache-from` and the `--cache-to` options of the `docker build` command. The `cache_from` and `cache_to` inputs provide this function. If using key-based caching, do NOT use these inputs! Leave them empty. ::: ```yaml workflow: steps: - docker-build-push: inputs: - tags: myregistry.com/myimage:latest - context: "./path" - file: "./Dockerfile" - push: "true" - use_bitrise_cache: "true" ``` 1. Optionally, customize the build command with build arguments and options. - Add [build arguments](https://docs.docker.com/build/guide/build-args/) in the `build_arg` input: one argument per line in a `MY_ARG=my_value` format. - Add [options](https://docs.docker.com/engine/reference/commandline/image_build/#options) in the `extra_options` input: one extra option per line in the format of `--option value` or `--option=value`. :::caution[Values with quotes] When using values with quotes in them (for example, when the value contains spaces) do not use the equal sign. Separate it with spaces instead: `--option "value with spaces"`. ::: ```yaml workflow: steps: - docker-build-push: inputs: - tags: myregistry.com/myimage:latest - context: "./path" - file: "./Dockerfile" - push: "true" - use_bitrise_cache: "true" - build_arg: BUILD_ARG=my_value - extra_options: "--option value" ``` 1. Optionally, set the `buildx_host_network` input to **true** to let the build container use the host's network. Set the `verbose` input to **true** for additional troubleshooting output. ```yaml workflow: steps: - docker-build-push: inputs: - tags: myregistry.com/myimage:latest - context: "./path" - file: "./Dockerfile" - push: "true" - use_bitrise_cache: "true" - build_arg: BUILD_ARG=my_value - extra_options: "--option value" - buildx_host_network: "true" - verbose: "true" ``` --- ## Execution containers Step execution containers can be defined for any Bitrise project. You define the container in the top level of the configuration file and then refer to it in a Step or a [Step bundle](/bitrise-ci/workflows-and-pipelines/steps/step-bundles). The Step or the Step bundle will run in the referred execution container. Within the same Workflow or Pipeline, you can run different Steps and Step bundles in different execution containers. :::important Containers apply to individual Steps and Step bundles, not to entire Workflows or Pipelines. ::: To define the execution container, you need to set the following: - The ID of the container. It will be used to reference this container. - The type of the container: `execution`. - The name and version of the Docker image you want to use. :::important[Getting images] You can use any public Docker image from [Docker Hub](https://hub.docker.com/). ::: After the containers are defined, you can refer to them in a Step or Step bundle which will then run in the referred container during your build. ### File sharing across containers To enable file sharing across different containers and the host Bitrise environment, the following folders are shared each time you run a Docker container on Bitrise: - `/bitrise` - `/root/.bitrise:/root/.bitrise/` - `tmp:/tmp` By default, Bitrise will use `/bitrise/src` as its working directory, and everything created in either of these folders will be available across all Step execution containers. :::important[Step execution containers only] This applies only to Step execution containers. Volumes and file sharing with [service containers](/bitrise-platform/infrastructure/docker-containers-on-bitrise/service-containers) are not supported. ::: ### Defining an execution container Use the `container` property to define an execution container. You can define them either on the Workflow Editor or directly in your configuration YAML file. When you have at least one execution container defined, you can run Steps and Step bundles in them: [Running an execution container](/bitrise-platform/infrastructure/docker-containers-on-bitrise/execution-containers#running-an-execution-container). **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Containers**. 1. Go to the **Execution containers** tab and then click **Add container**. ![SCR-20260313-pnzl.png](/img/_paligo/uuid-35998534-7cfb-c0c6-7277-bb12dd6bc345.png) 1. Set the required properties for the container. They are: - **Unique ID**: This ID is used to refer to the container in your configuration YAML file. - **Image:** The name and version of the Docker image. You can use any image found on [Docker Hub](https://hub.docker.com/) or you can use other registries. For a Docker Hub image, use the `[name]:[version]` format. For other registries, use `[registry server]/[owner]/[name]:[version]`. 1. Optionally, add port mappings in the **Ports** field in the `[HostPort01]:[ContainerPort01]` format. Read more about port publishing and port mapping in [Docker's official documentation](https://docs.docker.com/engine/network/port-publishing/). 1. Click **Show more options** to access Docker authentication credentials, Environment Variables for your container, and Docker create options. 1. Optionally, set up your Docker credentials. The credentials are used for the `docker login` command. You can set up: - **Registry server**: It should be a fully qualified registry server URL. This is optional if the server is already part of the image reference. - **Username**. - **Password**. :::tip You must use [secrets](/bitrise-ci/configure-builds/secrets) to pass your Docker credentials to your configuration. ::: 1. Optionally, add options in the **Docker create options** field. These are Docker container resource options: parameters that will be passed to the `docker container create` command. ![SCR-20260313-pruq.png](/img/_paligo/uuid-683647fc-3131-1c5a-8667-2fa719d617cd.png) For a list of all available options, see [the Docker documentation](https://docs.docker.com/reference/cli/docker/container/create/#options). 1. When done, click **Create container**. **Configuration YAML** 1. Add the `containers` property to the top level of your configuration YAML. :::tip[YAML syntax reference] For detailed YAML syntax reference, see [Docker container properties](/bitrise-ci/references/configuration-yaml-reference#docker-container-properties). ::: 1. Set an ID for your container. It must be unique within the configuration. The ID is used to refer to the container in Steps or Step bundles. ```yaml containers: node-18: ``` 1. Set the required properties for the container. They are: - The name and version of the Docker image, in a `name:version` format. You can use any image found on [Docker Hub](https://hub.docker.com/). - The container type: `execution`. ```yaml containers: node-21: type: execution image: node:21.6 node-18: type: execution image: node:18 ``` 1. Optionally, set up a port mapping in the `[HostPort01]:[ContainerPort01]` format. Read more about port publishing and port mapping in [Docker's official documentation](https://docs.docker.com/engine/network/port-publishing/). ```yaml containers: node-21: type: execution image: node:21.6 ports: - 3000:3000 ``` 1. Optionally, set up your Docker credentials. The credentials are used for the `docker login` command. You can set up: - A server: It should be a fully qualified registry server URL. This is optional if the server is already part of the image reference. - A username. - A password. :::tip We recommend using secrets to pass your Docker credentials to your configuration. ::: ```yaml containers: node-21: type: execution image: node:21.6 credentials: username: $DOCKER_USERNAME password: $DOCKER_PASSWORD server: us-central1-docker.pkg.dev ``` 1. Optionally, use the `options` property to configure additional Docker container resource options: parameters that will be passed to the `docker container create` command. In this example, the service is configured to have [healthchecks](https://docs.docker.com/engine/reference/run/#healthchecks). ```yaml containers: node-21: type: execution image: node:21.6 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ``` For a list of all available options, see [the Docker documentation](https://docs.docker.com/reference/cli/docker/container/create/#options). ### Running an execution container You can run a Step or a Step bundle in an execution container. To do so, refer to [a defined container](/bitrise-platform/infrastructure/docker-containers-on-bitrise/execution-containers#defining-an-execution-container) in the Step or Step bundle configuration. You can: - Refer to the container in a Step or a Step bundle within a Workflow. When that Workflow runs, the Step or the Step bundle will run within that container. - [Refer to the container in the Step bundle definition](#running-an-execution-container). When that Step bundle is added to the Workflow, it will run within that container by default, unless you override it within the Workflow. This guide covers both options. :::note[Container nesting] You can define containers on different levels: Steps and Step bundles both support their own container configuration. This creates a hierarchy between different levels. For the principles governing the hierarchy, see [Container nesting rules](/bitrise-platform/infrastructure/docker-containers-on-bitrise/about-docker-containers-on-bitrise#container-nesting-rules). ::: **Workflow Editor** 1. Open the Workflow Editor. 1. Select a Step or a Step bundle in a Workflow. Alternatively, you can select **Step Bundles** on the left navigation menu and set a container in the Step bundle definition. The subsequent steps in the procedure are the same. :::important[Bundle definition override] By default, if you set a container in the Step bundle definition the Step bundle will run in the referred container in any Workflow you add it to. However, if you set a container in a Step bundle instance (the Step bundle within a Workflow), it overrides the container set in the Step bundle definition. ::: 1. Select **Containers**. 1. Under **Execution Container**, click **Add container** and select a container from the menu. 1. If your container is already running but you want to run a clean instance of the container, check the **Recreate container** option. By default, the Step or Step bundle will use an already running container if there is one. **Configuration YAML** 1. Open your configuration YAML file and find your Workflow. 1. Add the `execution_container` property with a container name to the Step or Step bundle you need. You can only refer to a single execution container. Add an execution container to a Step within a Workflow format: ```yaml workflows: ci: steps: - git-clone: {} - script: execution_container: node-21 ``` Add an execution container to a Step bundle within a Workflow: ```yaml workflows: ci: steps: - git-clone: {} - script: {} - bundle::test-bundle-id: execution_container: node-21 ``` Add the execution container to a Step bundle definition: ```yaml step_bundles: test-bundle-id: steps: - git-clone@8: {} - restore-cache@2: {} execution_container: test-container ``` :::important[Bundle definition override] By default, the Step bundle will run in the referred container in any Workflow you add it to. However, if you set a container for the Step bundle within a Workflow, it overrides the container set in the Step bundle definition. ::: 1. If your container is already running but you want to run a clean instance of the container, set the `recreate` property to `true` . By default, the Step or Step bundle will use an already running container if there is one. Use the property to change the default behavior. ```yaml workflows: ci: steps: - git-clone: {} - script: execution_container: node:21 - bundle::test-bundle-id: execution_container: node-21: recreate: true ``` --- ## Service containers Service containers are Docker containers that host services you might need to test or operate your apps during a Bitrise Workflow. The services will run in the background and the containers are cleaned up when all Steps are finished. When defining a service container, you need: - The ID of the container. - The type of the container: `service`. - The image name and version of the service. :::important[Getting images] You can use any public Docker image from [Docker Hub](https://hub.docker.com/). ::: You can then refer to the container within a Step or a Step bundle: the container will run during the execution of these Steps or Step bundles. For detailed configuration options, check out [Docker container properties](/bitrise-ci/references/configuration-yaml-reference#docker-container-properties). ### Defining a service container Define a service container for your Bitrise Workflows by using the `container` property. You can define containers either on the Workflow Editor or directly in your configuration YAML file. When you have at least one service container defined, you can run background services during Step execution: [Running a service container](/bitrise-platform/infrastructure/docker-containers-on-bitrise/service-containers#running-a-service-container). **Workflow Editor** 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. On the left, select **Containers**. 1. Go to the **Service containers** tab and then click **Add container**. 1. Set the required properties for the container. They are: - **Unique ID**: This ID is used to refer to the container in your configuration YAML file. - **Image:** The name and version of the Docker image. You can use any image found on [Docker Hub](https://hub.docker.com/) or you can use other registries. For a Docker Hub image, use the `[name]:[version]` format. For other registries, use `[registry server]/[owner]/[name]:[version]`. ![SCR-20260313-ptnr.png](/img/_paligo/uuid-b793f623-9381-97af-5a8b-72719a0223fa.png) 1. Optionally, add port mappings in the **Ports** field in the `[HostPort01]:[ContainerPort01]` format. Read more about port publishing and port mapping in [Docker's official documentation](https://docs.docker.com/engine/network/port-publishing/). 1. Click **Show more options** to access Docker authentication credentials, Environment Variables for your container, and Docker create options. 1. Optionally, set up your Docker credentials. The credentials are used for the `docker login` command. You can set up: - **Registry server**: It should be a fully qualified registry server URL. This is optional if the server is already part of the image reference. - **Username**. - **Password**. :::tip You must use [secrets](/bitrise-ci/configure-builds/secrets) to pass your Docker credentials to your configuration. ::: 1. Optionally, add options in the **Docker create options** field. These are Docker container resource options: parameters that will be passed to the `docker container create` command. For a list of all available options, see [the Docker documentation](https://docs.docker.com/reference/cli/docker/container/create/#options). 1. When done, click **Create container**. **Configuration YAML** 1. Add the `containers` property to the top level of your configuration YAML. 1. Set an ID for your container. It must be unique within the configuration. The ID is used to refer to the container in Steps or Step bundles. ```yaml containers: postgres: ``` 1. Set the required properties for the container. They are: - The name and version of the Docker image, in a `name:version` format. You can use any image found on [Docker Hub](https://hub.docker.com/). - The container type: `service`. ```yaml containers: postgres: type: service image: postgres:16 ``` 1. Optionally, set up a port mapping in a `[HostPort01]:[ContainerPort01]` format. Read more about port publishing and port mapping in [Docker's official documentation](https://docs.docker.com/engine/network/port-publishing/). ```yaml containers: postgres: type: service image: postgres:16 ports: - 5432:5432 ``` 1. Optionally, set up your Docker credentials. The credentials are used for the docker login command. You can set up: - A server. This is optional if the server is already part of the image reference. - A username. - A password. :::tip We recommend using secrets to pass your Docker credentials to your configuration. ::: ```yaml containers: postgres: type: service image: postgres:16 credentials: username: $DOCKER_USERNAME password: $DOCKER_PASSWORD server: us-central1-docker.pkg.dev ``` 1. Optionally, use the `options` property to configure additional Docker container resource options: parameters that will be passed to the `docker container create` command. In this example, the service is configured to have [healthchecks](https://docs.docker.com/engine/reference/run/#healthchecks). ```yaml containers: postgres type: service image: postgres:16 options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ``` For a list of all available options, see [the Docker documentation](https://docs.docker.com/reference/cli/docker/container/create/#options). ### Running a service container You can run service containers during the execution of a Step or a Step bundle. Refer to the containers in the Step or Step bundle configuration to run the defined services in the background during Step execution. You can: - Refer to the containers in a Step or a Step bundle within a Workflow. When that Workflow runs, the referred container will run background services. - Refer to the containers in the Step bundle definition. When that Step bundle is added to the Workflow, it will run those service containers. :::note[Container nesting] You can define containers on different levels: Steps and Step bundles both support their own container configuration. This creates a hierarchy between different levels. For the principles governing the hierarchy, see [Container nesting rules](/bitrise-platform/infrastructure/docker-containers-on-bitrise/about-docker-containers-on-bitrise#container-nesting-rules). ::: **Workflow Editor** 1. Open the Workflow Editor. 1. Select a Step or a Step bundle in a Workflow. Alternatively, you can select **Step Bundles** on the left navigation menu and set containers in the Step bundle definition. The subsequent Steps are the same. :::important[Bundle definition] By default, the Step bundle runs all service containers defined in the bundle definition. If you set service containers on the bundle in a specific Workflow, that list **replaces** the bundle definition's service containers entirely. To keep the bundle definition's containers running alongside your own, include them again in the Workflow-level list. ::: 1. Select **Containers**. 1. Under **Service Container**, click **Add container** and select a container from the menu. You can add multiple containers. 1. If your service container is already running but you want to run the services in a clean instance of the container, check the **Recreate container** option. By default, the Step or Step bundle will use an already running container if there is one. **Configuration YAML** 1. Add the `service_containers` property and the container name to the Step or Step bundle you need. You can add multiple service containers using YAML array syntax. Add service containers to a Step: ```yaml workflows: ci: steps: - git-clone: {} - script: service_containers: - postgres - redis ``` Add service containers to a Step bundle: ```yaml workflows: ci: steps: - git-clone: {} - script: {} - bundle::test-bundle-id: service_containers: - postgres - redis ``` 1. If your service container is already running but you want to run the services in a clean instance of the container, set the `recreate` property to `true` . By default, the Step or Step bundle will use an already running container if there is one. Use the property to change the default behavior. ```yaml workflows: ci: steps: - git-clone: {} - script: service_containers: - postgres - bundle::test-bundle-id: service_containers: - postgres recreate: true - redis ``` ### Network access for service containers Service containers are all joined to the same [docker network](https://docs.docker.com/network/) called `bitrise`. This ensures that all of them are accessible from any other service container and Step execution container. :::tip[Running your own background workers] You can run your own background workers by executing the Docker commands yourself or by using something like `docker-compose` but make sure you use the same network. ::: Service containers can be used even when the Step group is not using a Step execution container. The only difference is how to access the services. Use the `` (name of the service) to access it when you are using Step execution container. For example, `http://postgres:5432`. Use localhost to access your service if you are not using a Step execution container. For example, `http://localhost:5432`. --- ## Infrastructure overview Bitrise is a platform, above all: you do not have to download anything to use it, you do not have to run it on your own computer or servers - we take care of all of that. That also means you do not have to worry about infrastructure, either: maintenance, tools, virtualization are all our job and our concern. On Bitrise, we use virtual machines (VM) to run your builds: every build runs in a new VM, and each VM is discarded immediately after the build has finished. A stack is the type of virtual machine we can use to run your build. For example, for a native iOS app, the best stack is one of our Xcode stacks. Stacks come with all of the necessary tools pre-installed, and are regularly updated to make sure they will serve all of your needs. --- ## Running Bitrise builds on-premise You can run Bitrise builds on self-hosted infrastructure - that is, that hardware or virtualized environments that you control - while taking advantage of every feature the Bitrise website offers. To do so, you just need to install the Bitrise agent on your own infrastructure and connect it to your Workspace. Once that is done, you can run builds from your Bitrise account, using the Bitrise UI as usual. ![bitrise-runner-diagram.png](/img/_paligo/uuid-d50cbc2f-3b77-a344-44dc-2a45449893e1.png) ### When to use the on-premise runner If you need to run Bitrise builds on infrastructure that you control, Bitrise offers two options: using Amazon EC2 Mac or Linux instances, or the on-premise runner option. We only recommend using the on-premise runner if you have the necessary machines or use a cloud provider other than AWS for your infrastructure needs. The on-premise runner is NOT plug and play: you need to make sure all necessary tools and services are installed on your machines. If you do have an AWS account for managing your infrastructure, we recommend checking our [AWS offering](/bitrise-platform/infrastructure/bitrise-on-aws--manual-setup/advanced-options-for-ec2-instances). ### Setting up Bitrise on-premise To be able to run Bitrise builds on your own infrastructure, you need to get the Bitrise runner from [Homebrew](https://brew.sh/) and then configure your network to be able to access two Bitrise service endpoints. :::note[Tools and services] Please note that when using the Bitrise runner this way, you have to make sure you have all the tools you need installed on the machine. For now, we don't provide preinstalled tools for this on-premise solution. ::: **macOS** 1. Configure Bitrise runner pools in your **Workspace settings** page on bitrise.io: [Configuring runner pools](/bitrise-platform/infrastructure/configuring-runner-pools). Make sure to get the token from the process. 1. Fetch the `bitrise-den-agent` formula from Homebrew. ```bash brew tap bitrise-io/den-agent ``` 1. Install the latest version. ```bash brew install bitrise-den-agent ``` :::tip[Installing a specific version] You can also install a specific version by amending the version number to the command: ```bash brew install bitrise-den-agent@2.1.26 ``` ::: 1. Install [the Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli). The CLI runs the builds based on YAML configurations. ```bash brew install bitrise ``` 1. Configure your network to be able to access the following two services: - `https://den.services.bitrise.io` - `https://build-log.services.bitrise.io` The agent needs to be able to access both of these to run your builds and communicate with the Bitrise website. 1. Generate a service daemon template. You need the runner pool token to finish the process. ```bash sudo $(brew --prefix)/bin/create_bitrise_daemon.sh --bitrise-agent-intro-secret=YOUR_TOKEN --enable-agent-self-update ``` 1. Configure agent mode to clean up your build environment after a build: [Cleaning up persistent build environments](/bitrise-platform/infrastructure/cleaning-up-persistent-build-environments). **Linux** 1. Configure Bitrise runner pools in your **Workspace settings** page on bitrise.io: [Configuring runner pools](/bitrise-platform/infrastructure/configuring-runner-pools). Make sure to get the token from the process. 1. Add a GPG public key. ```bash curl -fsSL https://bitrise-den-agent-deb.s3.amazonaws.com/DEB-GPG-KEY-bitrise.pub | sudo gpg --dearmor -o /usr/share/keyrings/DEB-GPG-KEY-bitrise.gpg ``` 1. Add the Bitrise DEN agent deb package repository. ```bash echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/DEB-GPG-KEY-bitrise.gpg] https://bitrise-den-agent-deb.s3.amazonaws.com stable main' | sudo tee /etc/apt/sources.list.d/den-agent-deb.list ``` 1. Install the runner and connect it on your machine to your Bitrise workspace. You need the runner pool token to finish the process. ```bash sudo apt update sudo apt install bitrise-den-agent /opt/bitrise/releases/bitrise-den-agent-configure.sh $TOKEN --enable-agent-self-update ``` 1. Configure agent mode to clean up your build environment after a build: [Cleaning up persistent build environments](/bitrise-platform/infrastructure/cleaning-up-persistent-build-environments). --- ## Running your build locally in Docker :::warning[Docker Hub rate limit] From July 15, 2024, rate limiting will apply on downloads from Docker Hub. If you pull a Docker image from Docker Hub without authentication during a Bitrise build on our Linux machines, you may run into issues because of rate limiting. Bitrise is mirroring some of the popular public docker images, but to avoid these potential issues with rate limiting, you can either: - Authenticate your Docker image pulling requests towards Docker Hub. For the details and Docker's full policy, refer to [Docker Hub rate limit](https://docs.docker.com/docker-hub/download-rate-limit/). - Switch to another Docker registry to store your images. ::: To be able to run your Linux stack builds locally, you’ll need [docker](https://www.docker.com/): - For Linux, just follow the [official install instructions](https://docs.docker.com/engine/installation/linux/). - For Mac, you can use Docker for Mac, which is the easiest way to get started. In this guide, we’ll use [this Bitrise Android sample project](https://github.com/bitrise-samples/sample-apps-android-sdk22). :::caution[Large images ahead] The official Bitrise Docker images are quite large because they include a wide variety of preinstalled tools. You’ll need at least 20-25 GB FREE DISC SPACE! ::: If you’re not familiar with the [Bitrise CLI](https://www.bitrise.io/cli), you should try that first. You don’t have to master the CLI, if you know what `bitrise run WORKFLOW` does, that should be enough for this tutorial. ### Downloading docker images 1. Install [docker](https://www.docker.com/). 1. Make sure you have your `bitrise.yml` in your repository. You don’t have to commit it, but the file must exist in your repository’s root directory. 1. `cd` into your repository’s directory on your Mac/Linux. 1. Pull the image from its registry: ```bash docker pull bitriseio/android-20.04:latest ``` 1. Run the following command: ```bash docker run --privileged --env CI=false --volume "$(pwd):/bitrise/src" --volume "/var/run/docker.sock:/var/run/docker.sock" --rm bitriseio/android-20.04:latest bitrise run WORKFLOW ``` If you want to just jump into the container and experiment inside, you can replace `--rm bitriseio/android-20.04:latest bitrise run WORKFLOW` with `-it bitriseio/android-20.04:latest bash` to start an interactive bash shell inside the container. For example: ```bash docker run --privileged --env CI=false --volume "$(pwd):/bitrise/src" --volume "/var/run/docker.sock:/var/run/docker.sock" -it bitriseio/android-20.04:latest bash ``` In general, if your project is an Android project but you don’t use Android NDK, to preserve precious disk space, you should use the [bitriseio/android](https://quay.io/repository/bitriseio/android) docker image. You can find other official Bitrise docker images on our [Quay page](https://quay.io/organization/bitriseio). In this example, we’re using the `bitriseio/android` one. 1. Download docker images from the [Quay](https://quay.io/organization/bitriseio): ```bash docker pull bitriseio/android-20.04:latest ``` Be aware that this can take quite a bit of time, as this image is over 10 GB. If the download fails or hangs, you can restart it any time by running the same command again. 1. Download your Bitrise build configuration (`bitrise.yml`) to the root directory of your repository. You can [download](/bitrise-ci/configure-builds/configuration-yaml/accessing-a-build-s-bitrise-yml-file) your project’s `bitrise.yml` from the **bitrise.yml** tab of your Workflow Editor on [bitrise.io](https://www.bitrise.io). 1. In your Terminal / Command Line go to (`cd`) the root directory of your repository. Check if your `bitrise.yml` is at this location. If you try to reproduce an issue, you should `git clone` your repository into a NEW DIRECTORY, so that the directory will only contain the files which are committed into the repository! It’s a frequent reproducibility issue that you try to run the commands in your normal working directory, where you most likely have files which are not committed into your repository, for example, files which are in `.gitignore`. ### Running the build Run your build with the following command: ```bash docker run --privileged --env CI=false --volume "$(pwd):/bitrise/src" --volume "/var/run/docker.sock:/var/run/docker.sock" --rm bitriseio/android:latest bitrise run WORKFLOW ``` - `--rm bitriseio/android:latest bitrise run WORKFLOW` with `-it bitriseio/android:latest bash` to start an interactive bash shell inside the container. For example: ```bash docker run --privileged --env CI=false --volume "$(pwd):/bitrise/src" --volume "/var/run/docker.sock:/var/run/docker.sock" -it bitriseio/android:latest bash ``` This command will share the current directory (the directory of your repository) as a shared volume with the docker container, and will make it available inside the container at the path `/bitrise/src`. After this, you can run `bitrise run WORKFLOW`, which will run the workflow inside the container. To exit from the container, just run `exit`. - Don’t forget to replace `WORKFLOW` with the actual ID of your workflow in your `bitrise.yml`, with something like `primary`! - The `--env CI=false` flag sets the environment variable `CI` to `false` - this will make Bitrise CLI skip certain steps that only make sense to run in a CI environment. For example, our `Git Clone` Step - you already have your code, so there’s no need to git clone it again inside the docker container (that’s why we shared the code directory as a `--volume`). - The `--rm` flag tells docker to discard the container after the `docker run` command finishes. This means that if you run the command again, the only thing which will persist between the `docker run ..` commands are the files stored at the shared `--volume` (in your repository’s directory). Every other file that is generated into a temp or any other location will be discarded / won’t be kept. If you want to debug the container after a failed build, feel free to remove the `--rm` flag, and check out a Docker tutorial about how you can connect to an existing docker container. Please note that simply running the command again will not use the same container, but will create a new one! - The `--privileged` flag allows access control of the host from the docker container, so you should never use this flag unless you trust the docker image you will use! This flag is required for allowing VPNs to work (to change network configs of the host), for example. - The `--volume "/var/run/docker.sock:/var/run/docker.sock"` flag exposes the docker socket from the host for the container - this is required if you want to run other docker containers from within the container, or if you want to run any `docker` command during your build / inside the container. --- ## About integrations After your Bitrise account and your Workspaces are set up, the next step is to make sure that you can connect your Bitrise account to other services and that Bitrise can access your code during [a CI build](/bitrise-ci/run-and-analyze-builds/starting-builds/starting-builds-manually). ### Connecting to services Each Bitrise user can connect their account to a GitHub, Bitbucket, and GitLab account. Doing so ensures that you can easily and quickly [add new projects](/bitrise-ci/getting-started/adding-a-new-project) from repositories at those Git provider accounts without having to manually enter the URL: [Repository access with OAuth](/bitrise-platform/repository-access/repository-access-with-oauth). If you ever develop iOS apps, you need to be able to connect to Apple services. On Bitrise, you can connect to an Apple account via either an Apple ID or by API key authentication: [Apple services connection](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services). An important part of communicating with other services is the service credential user. It is a user with a connected Git account which is used to, for example, [send status reports](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider) back to the Git provider: [The service credential user](/bitrise-platform/integrations/the-service-credential-user). ### Accessing your code during a build Bitrise needs to be able to access and clone your repositories during the build process. We recommend using SSH keys for authentication for private projects. You can automatically generate and add SSH keys to your Git account during the process of adding a new project, or at any point in the **Project settings** menu: [Configuring SSH keys](/bitrise-platform/repository-access/configuring-ssh-keys). :::note[Public projects] [Public projects](/bitrise-platform/projects/public-projects) can't have SSH keys as they do not require authentication and always use HTTP URLs. ::: You can use repositories with submodules or private repo dependencies, too. In this case we recommend adding the same SSH key to all repository dependencies, or use a machine user: [Apps with submodules or private repo dependencies](/bitrise-platform/repository-access/apps-with-submodules-or-private-repo-dependencies). You might need to use a VPN to be able to connect to your code. Bitrise allows you to do this and we have examples for connecting with several different VPN services: [Connecting to a VPN during a build](/bitrise-platform/integrations/connecting-to-a-vpn-during-a-build). ### Webhooks Webhooks are an important part of using Bitrise: an incoming webhook set up in your repository notifies Bitrise about code events (such as pushes, tags, and pull requests) and allows [automatically triggering builds](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers). Incoming webhooks can be set up at a number of different Git providers, both manually and automatically: [Adding incoming webhooks](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks). Outgoing webhooks configured on Bitrise allows you to send build event notifications to any service. You can configure custom headers for the webhook payload, and check the deliveries of the webhooks on the web interface: [Adding outgoing webhooks](/bitrise-platform/integrations/webhooks/adding-outgoing-webhooks). --- ## AI code reviewer Bitrise now helps you unblock your teams by providing helpful information and suggestions for every pull request via an AI code reviewer. The AI code reviewer creates a comment every time a new pull request is opened on GitHub, and every time a user adds a new commit to the pull request. The code reviewer can provide the following features: - A summary: Highlights key code changes and their potential impact. - Walkthrough: Generates context-aware documentation to help team members quickly understand code changes. - Code review: Detects potential issues, suggests improvements, and enhances code quality. When you enable the code review, you can select which of the above features you want to use. ### How the code reviewer works To use the AI code reviewer, you must have a GitHub repository with one of the following connection types: - [GitHub app integration](/bitrise-platform/repository-access/github-app-integration) with the **write** permission enabled. The comments will be posted by the Bitrise GitHub app. We strongly recommend using this method. - [GitHub OAuth connection](/bitrise-platform/repository-access/repository-access-with-oauth). The comments will be posted in the name of the [service credential user](/bitrise-platform/integrations/the-service-credential-user). :::tip[Bot user] If you use the OAuth connection, we recommend creating a bot user for this purpose and connect it as the service credential user on Bitrise. This makes it clear that the comments on the pull request come from a bot, not from an actual team member. ::: :::important[HTTPS connection] The AI code reviewer doesn't work with an HTTPS connection. We recommend switching to the GitHub app. ::: The AI code reviewer runs a Bitrise build that shows up in your list of Bitrise CI builds. This build: - Doesn't count towards any of your resource limits (credits, build count, build minutes). - Doesn't count towards concurrency limits. - Increases the actual [build number](/bitrise-ci/run-and-analyze-builds/build-numbering-and-app-versioning). - Is included in [Insights](/insights) data. For each new commit on a pull request, the code reviewer starts a new review and a new build. There is a limit of 10 reviews per PR. There is no limit on how many new PRs you can have reviewed. :::important[Third-party API vendor] Bitrise AI uses a third-party API vendor for this feature so data will leave Bitrise in order to generate the PR reviews. See our [AI FAQ](/bitrise-platform/ai/ai-faq---how-bitrise-leverages-ai-technologies-in-its-features-and-services) for more information on how Bitrise leverages AI. ::: To configure the code reviewer: 1. Enable AI features for your workspace: [Enabling AI features on Bitrise](/bitrise-platform/ai/enabling-ai-features-on-bitrise). 1. Enable the AI code reviewer for specific projects: [Enabling the AI code reviewer](/bitrise-platform/integrations/ai-code-reviewer#enabling-the-ai-code-reviewer). ### Enabling the AI code reviewer To enable the AI code reviewer for a project: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Bitrise AI**. 1. Toggle **Code reviewer** on. 1. In the dialog, select the features you want to enable: - **Summary** - **Walkthrough** - **Code review** You must enable at least one of them. 1. Click **Save changes**. --- ## About connecting to Apple services Both [Bitrise CI](/bitrise-ci) and [Release Management](/release-management) helps you automate Mobile DevOps processes that require Apple's online services. To connect to these services, such as the Apple Developer Portal or App Store Connect, you need to provide authentication data to Bitrise and select the established authentication method for your project. You can authenticate with Apple’s official API key or with Apple ID and password. ### Apple two-factor authentication requirements Apple’s [two-factor authentication](https://developer.apple.com/support/authentication/) (2FA) provides an extra layer of security on your Apple account. If you have been authenticating with the API key so far, you are not affected by the two-factor authentication requirement. If, however, you have been authenticating with an Apple ID and a password, and the [new 2FA requirement](https://developer.apple.com/support/authentication/) affects you, then you’ll have to reconnect your Apple Developer Account on the **Connected accounts** page of your Bitrise profile. You’ll also have to provide the two-factor authentication/two-step verification code and an app-specific password as well. Please find the official Apple documentation on [how to generate an app-specific password](https://support.apple.com/en-us/HT204397). ### Steps that require connecting to your Apple Developer account The following Steps require connection to Apple services (such as App Store Connect or the Apple Developer Portal). If you’re using any of these Steps, make sure you establish connection with the right method. | Steps | Connection type | | --- | --- | | Manage iOS Code Signing | API key authentication, Apple ID authentication, API key authentication through Step inputs | | Xcode Archive & Export for iOS | API key authentication, Apple ID authentication, API key authentication through Step inputs | | Export iOS and tvOS Xcode archive | API key authentication, Apple ID authentication, API key authentication through Step inputs | | Xcode Build for testing for iOS | API key authentication, Apple ID authentication, API key authentication through Step inputs | | fastlane | API key authentication, Apple ID authentication, API key or Apple ID authentication through Step inputs | | Deploy to App Store Connect with Deliver (formerly iTunes Connect) | API key authentication, Apple ID authentication, API key or Apple ID authentication through Step inputs | | Deploy to App Store Connect - Application Loader (formerly iTunes Connect) | API key authentication, Apple ID authentication, API key or Apple ID authentication through Step | Depending on which authentication you can use in your project, you have the following options: - API key authentication: If you can, we recommend you use this authentication method. It does not require two-factor authentication. All it takes is connecting to the Apple services by providing **Name**, **Issuer ID**, **Key ID** and upload a **Private Key (.p8)**, then selecting an account under the **Stores** tab in your app’s settings. The data you give automatically populates the respective fields of the Steps that work with API key authentication. - Apple ID authentication: If you cannot use the API key authentication, you can authenticate with your Apple ID and password. Provide your **Apple ID**, **password**, **2FA code** and **app-specific password** then select an account under the **Stores** tab in your app’s settings. The data you give automatically populates the respective fields of the Steps that work with the Apple ID authentication. - API key or Apple Id authentication through Step inputs: If you wish to deploy to multiple teams or deploy to a team where authentication is different from the connected one you’ve been using, then you can add your preferred authentication into the Step’s inputs. Some Steps, such as Xcode Archive & Export for iOS, only have an API key authentication override option, while some Steps, like fastlane, have options for both API key and Apple ID Step level authentication override. ### Apple service permissions In order to successfully connect Bitrise to Apple services, you need to set up the right roles and accesses in your Apple account for your Apple ID and your API keys. You must set up the appropriate access rights to be able to: - Use automatic code signing. - Deploy your app to the App Store. The exact roles and accesses you need depend on a number of factors: your authentication method, whether you use Xcode managed signing, and the details of your app deployment process, among other things. In this guide, we'll list the roles based on the two main [authentication methods](/bitrise-platform/integrations/apple-services-connection/steps-requiring-apple-authentication): API key authentication and Apple ID authentication. #### Required access with API key authentication To use Bitrise Steps with Apple API key authentication, you need to create an App Store Connect API key with the appropriate access level. The appropriate level depends on what you need to do. If, for example, you use Xcode managed signing in your project and wish to export the generated IPA file with a Distribution certificate and an App Store provisioning profile, the App Store Connect API key must have **Admin** access. The following table contains the required access for automatic code signing. In the table, we grouped code signing actions based on the type of the IPA file we're attempting to export. There are two main types: - Development IPA: this is an IPA exported with the **development** method. - Distribution IPA: this is an IPA exported with the **app-store**, **ad-hoc**, or **enterprise** distribution method. | Code signing action | Required access with Xcode managed signing turned ON | Required access with Xcode managed signing turned OFF | | --- | --- | --- | | Exporting Development IPA. This can include: - Creating development provisioning profiles. - Deleting development provisioning profiles. - Downloading provisioning profiles. - Registering and configuring App IDs. - Adding device UDIDs | Developer | Developer | | Exporting App Store IPA. This can include: - Creating development and distribution provisioning profiles. - Deleting development and distribution provisioning profiles. - Downloading provisioning profiles. - Registering and configuring App IDs. - Adding device UDIDs | Admin | Developer | The following table contains the required roles for deploying your app to the App Store. For App Store deployment, the required access depends on how you wish to upload the generated IPA file. You can either: - Upload only the IPA without any additional steps. - Upload the IPA with metadata and screenshots, and submit the app for review. | App Store deployment actions | Required access for API key | | --- | --- | | Uploading a new IPA without any metadata | Developer | | Uploading a new IPA and: - Updating app metadata. - Uploading screenshots. - Submitting the app for App Store review. | App Manager | #### Required access with Apple ID authentication To use Bitrise Steps with Apple ID authentication, you need to make sure that your Apple ID has the appropriate role in your Apple Developer team. The following table contains the necessary roles for using automatic code signing on Bitrise. In the table, we grouped code signing actions based on the type of the IPA file we're attempting to export. There are two main types: - Development IPA: this is an IPA exported with the **development** method. - Distribution IPA: this is an IPA exported with the **app-store**, **ad-hoc**, or **enterprise** distribution method. Read more about the different distribution methods: [Creating a signed IPA for Xcode projects](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects). :::note[Xcode managed signing] If you use Apple ID authentication on Bitrise, Xcode managed signing is automatically turned off in your project. Instead, Bitrise uses its own automatic code signing logic. ::: | Code signing action | Required role | | --- | --- | | Exporting development IPA. This can include: - Creating development provisioning profiles. - Deleting development provisioning profiles. - Downloading provisioning profiles. - Registering and configuring App IDs. - Adding device UDIDs | App Manager | | Exporting an App Store IPA. This can include: - Creating development and distribution provisioning profiles. - Deleting development and distribution provisioning profiles. - Downloading provisioning profiles. - Registering and configuring App IDs. - Adding device UDIDs | App Manager | The following table contains the required roles for deploying your app to the App Store. For App Store deployment, the required access depends on how you wish to upload the generated IPA file. You can either: - Upload only the IPA without any additional steps. - Upload the IPA with metadata and screenshots, and submit the app for review. | App Store deployment actions | Required role for Apple ID | | --- | --- | | Uploading a new IPA without any metadata | Developer | | Uploading a new IPA and: - Updating app metadata. - Uploading screenshots. - Submitting the app for App Store review. | App Manager | --- ## Connecting to an Apple service with API key [Connecting to an Apple service](/bitrise-platform/integrations/apple-services-connection/about-connecting-to-apple-services) (such as the App Store Connect or the Apple Developer Portal) with the API key requires generating an API key, adding the authentication data on Bitrise, and assigning the key to the app. The API key authentication is the recommended way when connecting Bitrise to Apple Services. You can have 50 API keys added to the **Apple Services connection** page but your app can use only one. :::important[No Step input modifications needed] With this method, all Step inputs related to authenticating with an Apple API key are automatically populated once the connection is set up. You don't have to manually modify those Step input fields at all. ::: ### Adding API key authentication data on Bitrise You can add API key authentication data on the **Workspace settings** page. You can add multiple API keys here. You can select between different API keys for each project, using them either for Bitrise CI or Bitrise Release Management. 1. On [App Store Connect](https://appstoreconnect.apple.com/login), [generate a new API key with Admin access](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api) under **Users and Access**. You will need the name of the key, the key ID and the issuer ID on Bitrise. :::warning[Requirements] - The API key must be [a team API key](https://developer.apple.com/documentation/appstoreconnectapi/creating-api-keys-for-app-store-connect-api#Generate-a-Team-Key-and-Assign-It-a-Role). An individual API key won't work. ![apple-app-store-connect.png](/img/_paligo/uuid-b104fac1-d553-69d3-ebcb-b8260e8a3595.png) - The API key must be set up with the **Admin** role on the App Store. Your builds will fail otherwise. - On Bitrise, you must be a workspace **Owner** or **Manager** to be able to add the API key data. For more information, check out [Workspace-level roles](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces#workspace-level-roles). ::: 1. On Bitrise, select your workspace from the dropdown menu and go to **Settings**. 1. On the left, select **Integrations**. 1. Select **App Store Connect**. 1. Click **Add API key**. :::note[Required roles] If you can't see the button, it's because you only have a **Viewer** or **Contributor** role in the workspace. You need to be either an **Owner** or a **Manager**. For more information, check out [Workspace-level roles](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces#workspace-level-roles). ::: ![api-key-app-store.png](/img/_paligo/uuid-1bbd8347-eb11-4439-9ece-315d004d74fe.png) 1. Fill out all required fields: - **Name**: Your generated API key's name. - **Issuer ID**: To get your issuer ID, log in to App Store Connect and select **Users and Access**, then select the **API Keys** tab.The issuer ID appears near the top of the page. To copy the issuer ID, click **Copy** next to the ID. - **Key ID**: When you successfully generate a new API key, App Store Connect shows you the key ID. ![api-key-dialog.png](/img/_paligo/uuid-22e6048e-7f47-9480-fea3-958eb9a0348b.png) 1. If your API key is an Apple Enterprise API key, check **Use for Enterprise Program API**. ![api-key-enterprise.png](/img/_paligo/uuid-7dc1ff71-7abf-8c37-8117-a2f7abb13861.png) 1. Upload the `.p8` file: either drag and drop it to the upload field, or click it and select the file from your computer. 1. Click **Add API key**. Once done, you can now assign this API key to any app that you have access to on this account. From then, the app will use that API connection to access App Store Connect. ### Assigning API key authentication to your project To use API key authentication for Apple services for your project, you must: - [Add an API key on Bitrise](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key#adding-api-key-authentication-data-on-bitrise): You can add multiple API keys to the same account. If your API key is an Apple Enterprise API key, check **Use for Enterprise Program API** when adding it. - Assign an API key to your project: Each project can only have one API key assigned to it. To assign the API key to the project: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Integrations**. 1. Select the **Stores** tab. 1. Find the **App Store Connect** section. ![add-api-key-apple.png](/img/_paligo/uuid-95e5fcc6-46bd-1efe-69a0-538ef9c8c8cb.png) 1. Find the **API key authentication (recommended)** option. 1. Click **Add API key**. :::note[Multiple projects with the same API key] With the **Add API key** button, you can add a new App Store Connect API key to your Bitrise account. Other projects you have access to can use this API key, too. ::: 1. Select the API key you want to use for this project. The Step is now able to connect to the App Store Connect or the Apple Developer Portal during your build. ### API key authentication for Apple Enterprise users Apple accounts that are part of the Enterprise developer program can also use API key-based authentication. If your Enterprise account still uses Apple ID authentication, we strongly recommend switching to API key authentication because: - It's more reliable and secure. - It doesn't have to be re-authorized every 30 days. - The Apple ID authentication method will be deprecated at some point. To change your authentication method: 1. If you haven't already, [add an API key on Bitrise](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key#adding-api-key-authentication-data-on-bitrise), making sure to check **Use for Enterprise Program API**. 1. [Assign the API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key#assigning-api-key-authentication-to-your-project) to your project(s) on Bitrise. :::caution[Keep the Apple ID connection] We strongly recommend not to remove your Apple ID connection. If there are any issues with the API key connection, you can safely roll back to Apple ID-based authentication. ::: 1. Adjust all Step inputs that use Apple ID authentication to access Apple services. The following Steps are affected: - **Xcode Archive & Export for iOS**: version 5.3.0 and above. Set the `automatic_code_signing` input to `api-key`. - **Xcode Build for Testing**: version 3.1.0 and above. Set the `automatic_code_signing` input to `api-key`. - **Manage iOS Code Signing**: version 2.1.0 and above. Set the `apple_service_connection` input to `api-key`. - **Export iOS and tvOS Xcode archive**: version 4.6.0 and above. Set the `automatic_code_signing` input to `api-key`. #### Multiple API keys for the same project You can only set up one API connection for each project on the Bitrise website. That means the project can handle the code signing files of only one Apple developer team: API keys only give authorization to a single developer team. ![api-key-chart.png](/img/_paligo/uuid-ea47d90b-0ff0-7cd5-2f80-4013e10f7fb3.png) If your Bitrise project needs to handle the code signing of multiple developer teams, you can pass additional API keys as Step inputs. Doing so overrides the Bitrise-managed API connection. The available inputs differ by Step: | Step | Inputs | | --- | --- | | Xcode Archive & Export for iOSXcode Build for TestingManage iOS Code SigningExport iOS and tvOS Xcode archive | `api_key_path`: A local file path or download URL for the API key.`api_key_id`: The key ID from App Store Connect.`api_key_issuer_id`: The issuer ID from App Store Connect.`api_key_enterprise_account`: `yes` or `no`, whether the key belongs to an Apple Enterprise Program account. | | fastlaneDeploy to App Store Connect with Deliver | `api_key_path`: A local file path or download URL for the API key. Embed the key ID in the file name — there's no separate key ID input.`api_issuer`: The issuer ID from App Store Connect. | :::note[Inputs on the GUI] On the graphical UI of the Bitrise Workflow Editor, you can find these inputs under the **App Store Connect connection override** input group on the **Configuration** tab of each Step that can access Apple services. ::: --- ## Connecting to an Apple service with Apple ID Connecting to an Apple service (such as the App Store Connect or the Apple Developer Portal) with the Apple ID requires that you first add your Apple ID and password on the **Connected accounts** page, then select an app to use Apple ID authentication while the build is running. If you cannot use the API key authentication, we recommend you try this option. Please note that you can only connect one Apple ID to Bitrise. :::important[Apple accounts with two-factor authentication enabled] If two-factor authentication is enabled on your Apple account, you will have to provide the App-specific password during this process. Learn [how to generate an app-specific password on the Security section of your Apple ID account page](https://support.apple.com/en-us/HT204397). ![appspecificpassword.jpg](/img/_paligo/uuid-635b3416-2294-9063-b841-674935c2f4ab.jpg) ::: ### Adding Apple ID authentication data on Bitrise 1. Log in to Bitrise, and select **Bitrise CI** from the left navigation menu. 1. In the upper right corner, click the profile image to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. On the left, select **Connected accounts**. 1. On the **Apple services** tab, click **Connect**. 1. Provide your **Apple ID**, **Password**, and **app-specific password** in the dialog. Click **Next**. 1. Enter your **verification code** in the **Two factor authentication** dialog. Click **Verify**. 1. Your authentication expires in 30 days and you will have to authenticate again. When that happens, go to the **Connected accounts** page and click **Re-authenticate**. This automatically asks for the two-factor authentication (2FA) code to authenticate again. 1. Continue with Assigning an Apple Developer Account for your app. ### Assigning Apple ID authentication to your app Connecting to an Apple service (such as the App Store Connect or the Apple Developer Portal) with Apple ID authentication requires that you first add your Apple service authentication data on bitrise.io and then assign your Apple credentials to the app. With this method, you don't have to worry about authentication when using Steps that connect to Apple services: all Step inputs related to Apple authentication are automatically filled in. :::important[Can't assign other users' Apple credentials] You can only set your own user account's Apple ID authentication data to an app. If you have an app that needs someone else's Apple credentials, that user must log in and make the change themselves. ::: To assign Apple ID authentication data to your app: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Integrations**. 1. Scroll down to the **Connection to Apple services** section. 1. Find the **Apple ID authentication** option. ![add-api-key-apple.png](/img/_paligo/uuid-95e5fcc6-46bd-1efe-69a0-538ef9c8c8cb.png) 1. Click **Change to me**. If you can't find this option, you probably haven't set up your Apple credentials on bitrise.io. Note that changing the selected user removes the previous user. If you need to use the previous user's Apple credentials again, that user must log in and change it themselves. Steps are now able to connect to an Apple service during your build. --- ## Connecting to an Apple Service with Step inputs If you wish to deploy to multiple teams or deploy to a team where authentication is different from the connected one you’ve been using, then you can add your preferred authentication into the Step’s inputs. This will override the connection previously set in **Bitrise Developer Connection**. This way connection is restricted to the given Step where you set up authentication. :::important[2FA and Apple ID authentication] If 2FA is required for your Apple ID, then you must use the Apple ID authentication with the [**Deploy to App Store Connect with Deliver (formerly iTunes Connect)**](https://github.com/bitrise-steplib/steps-deploy-to-itunesconnect-deliver) and the [**fastlane**](https://github.com/bitrise-io/steps-fastlane) Steps instead of authenticating through Step inputs. ::: ### Authenticating in a Step with API key **API-key & Apple ID** 1. Add one of the following Steps to your Workflow: - fastlane - Deploy to App Store Connect with Deliver (formerly iTunes Connect) - Deploy to App Store Connect - Application Loader (formerly iTunes Connect) :::caution[Either API key or Apple ID authentication in Step inputs] You can only add one type of authentication into the Step, either the API key one or the Apple ID one. In either case, make sure the **Bitrise Apple Developer Connection** input is set to `off`, otherwise the Step will go with the configured authentication method found in **Apple Service connection** (unless you decide to remove the connection on the **Stores** tab). ::: 1. Upload the API key to the **GENERIC FILE STORAGE** section of the **Code Signing & Files** tab. 1. Set the **Bitrise Apple Developer Connection** input to `off`. 1. Set the **Issuer ID** as a secret Environment Variable in the respective field of the Step. 1. Configure the **API Key path** and **API Issuer** inputs. 1. Save your changes and run a new build. **API-key only Steps** 1. Add one of the following Steps to your Workflow: - Manage iOS Code Signing - Xcode Archive & Export for iOS - Export iOS and tvOS Xcode archive - Xcode Build for testing for iOS 1. Upload your App Store Connect API private key file (.p8 file) to the **Generic File Storage** in the **Code Signing & Files** tab. 1. Set the **Automatic code signing method** to `api-key`. For Manage iOS Code Signing, the equivalent input is named **Apple service connection method**. 1. Set the following Step inputs under the **App Store Connect connection override** input group: - **App Store Connect API private key**: Local path or remote URL to the private key (.p8 file) for App Store Connect API. Set this input to the automatically generated Env Var connected to the App Store Connect API private key file (.p8 file) you uploaded to the Generic File Storage in step 2. - **App Store Connect API key ID**: Private key ID used for App Store Connect authentication. - **App Store Connect API issuer ID**: Private key issuer ID used for App Store Connect authentication. ### Authenticating in a Step with Apple ID and password :::caution[Either API key or Apple ID authentication in Step inputs] You can only add one type of authentication into the Step, either the API key one or the Apple ID one. In either case, make sure the **Bitrise Apple Developer Connection** input is set to `off`, otherwise the Step will go with the configured authentication method found in **Apple Service connection** (unless you decide to remove the connection on the **Stores** tab). ::: 1. Add the Step to your Workflow. 1. Set the **Apple ID** and **Password**. 1. Set the **Bitrise Apple Developer Connection** input to `off`. 1. Save your changes and run a new build. --- ## Steps requiring Apple authentication In this guide we list all the Steps that require authentication and the authentication methods that you can choose from depending on your app’s requirement. ### [Manage iOS Code Signing](https://github.com/bitrise-steplib/bitrise-step-manage-ios-code-signing) Step [This Step](https://www.bitrise.io/integrations/steps/manage-ios-code-signing) takes care of setting up the required code signing assets before your project is built on Bitrise. The Step uses your API key or your Apple ID and password authentication to connect to an Apple service. Once connection is configured, the Step will: - Generate, update and download the provisioning profiles needed for your iOS project. - Verify and register the project's Bundle IDs on the Apple Developer Site. - Register the iOS devices connected to your Bitrise account with the App Store Connect. [Connecting to an Apple service with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) [Connecting to an Apple service with Apple ID](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) [Authenticating in a Step with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-step-inputs#authenticating-in-a-step-with-api-key) ### [Xcode Archive & Export for iOS](https://github.com/bitrise-steplib/steps-xcode-archive) Step The Step archives your Xcode project by running the `xcodebuild archive` command and then exports the archive into an IPA file with the `xcodebuild -exportArchive` command. This IPA file can be shared, installed on test devices, or uploaded to the App Store Connect. The Step can also perform iOS code signing if the **Automatic code signing method** input specifies a method. By default, it's turned off. To perform iOS code signing, it can use API key or Apple ID authentication. [Connecting to an Apple service with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) [Connecting to an Apple service with Apple ID](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) [Authenticating in a Step with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-step-inputs#authenticating-in-a-step-with-api-key) ### [Export iOS and tvOS Xcode archive](https://github.com/bitrise-steplib/steps-export-xcarchive) Step Exports an IPA from an existing iOS and tvOS .xcarchive file. You can add multiple [Export iOS and tvOS Xcode archive](https://github.com/bitrise-steplib/steps-export-xcarchive) Steps to your Workflows to create multiple different signed IPA files. The Step can also perform iOS code signing if the **Automatic code signing method** input specifies a method. By default, it's turned off. To perform iOS code signing, it can use API key or Apple ID authentication. [Connecting to an Apple service with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) [Connecting to an Apple service with Apple ID](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) [Authenticating in a Step with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-step-inputs#authenticating-in-a-step-with-api-key) ### [Xcode Build for testing for iOS](https://github.com/bitrise-steplib/steps-xcode-build-for-test) Step The Step runs Xcode's `xcodebuild` command with the build-for-testing option. This builds your app and associated tests so that you can, for example, upload it to a third-party testing service to run your tests on a real device. The Step also creates an `.xctestrun` file. To be able to run your tests on a real device it needs code signing. The **Automatic code signing method** Step input allows you to log you into your Apple Developer account based on the Apple service connection you provide on Bitrise and download any provisioning profiles needed for your project based on the **Distribution method**. [Connecting to an Apple service with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) [Connecting to an Apple service with Apple ID](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) [Authenticating in a Step with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-step-inputs#authenticating-in-a-step-with-api-key) ### Deploy to App Store Connect with Deliver Step With [this Step](https://www.bitrise.io/integrations/steps/deploy-to-itunesconnect-deliver), you can upload screenshots, metadata and binaries to [https://appstoreconnect.apple.com/](https://appstoreconnect.apple.com/) and submit your app for App Store review using the fastlane [deliver](https://docs.fastlane.tools/actions/deliver/) action. The [**Deploy to App Store Connect with Deliver (formerly iTunes Connect)**](https://github.com/bitrise-steplib/steps-deploy-to-itunesconnect-deliver) Step can connect to your Apple Developer Account either with Apple ID or with the App Store Connect API, or through Step inputs. Please note that in the case of 2FA enabled Apple ID, the **Deploy to App Store Connect with Deliver (formerly iTunes Connect)** Step can only work with Apple ID authentication which you can set on the Apple Service page of your profile. The default method is the API key authentication. Choose the connection method that works with your project: [Connecting to an Apple service with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) [Connecting to an Apple service with Apple ID](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) [Connecting to an Apple Service with Step inputs](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-step-inputs) ### Deploy to App Store Connect - Application Loader (formerly iTunes Connect) Step With [this Step](https://www.bitrise.io/integrations/steps/deploy-to-itunesconnect-application-loader), you can upload binaries (.ipa or .pkg files) to [https://appstoreconnect.apple.com/](https://appstoreconnect.apple.com/). The [**Deploy to App Store Connect - Application Loader (formerly iTunes Connect)**](https://github.com/bitrise-steplib/steps-deploy-to-itunesconnect-application-loader) Step can connect to your Apple Developer Account either with the App Store Connect API, the Apple ID and password, or through Step inputs. Choose the connection method that works with your project: [Connecting to an Apple service with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) [Connecting to an Apple service with Apple ID](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) [Connecting to an Apple Service with Step inputs](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-step-inputs) ### [fastlane](https://github.com/bitrise-io/steps-fastlane) Step With this Step you can run your [*fastlane*](https://fastlane.tools/) lanes on Bitrise just like you would locally. Please note that in the case of 2FA enabled Apple ID, the [**Fastlane**](https://github.com/bitrise-io/steps-fastlane) Step can only work with Apple ID authentication which you can set on the **Apple Service** page of your profile. :::note[Two-factor authentication fails with the Fastlane Step] In some cases, the [**Fastlane**](https://github.com/bitrise-io/steps-fastlane) Step doesn't get the value of the FASTLANE_SESSION variable correctly when attempting to connect to the Apple Developer portal, causing two-factor authentication to fail. Check out the [potential workaround](https://support.bitrise.io/hc/en-us/articles/360017174577) for this issue. ::: [Connecting to an Apple service with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) [Connecting to an Apple service with Apple ID](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-apple-id) [Connecting to an Apple Service with Step inputs](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-step-inputs) --- ## Connecting a Google service account to Bitrise You can connect a Google Console Service account to a Workspace. The service account will be available to use for all the projects owned by that Workspace. It allows you to seamlessly deploy your Android apps to Google Play with [Release Management](/release-management). You can add multiple service accounts to a Workspace but a Bitrise project can only have a single service account connected to it at any given time. However, you can change the connected account at any time. ### Connecting a Google service account to a Workspace To create a new service account and link it to a Bitrise Workspace: 1. Set up a Google Play service account in Google Play console: [Using a service account](https://developers.google.com/android-publisher/getting_started#service-account). 1. Grant the necessary rights to the service account with your [Google Play Console](https://play.google.com/apps/publish). Go to **Settings**, then **Users & permissions**, then **Invite new user**. Due to the way the Google Play Publisher API works, you have to grant at least the following permissions to the service account: - Access level: View app information. - Release management: Manage production releases, manage testing track releases. - Store presence: Edit store listing, pricing & distribution. 1. Create a JSON key for the service account: [Create a service account key](https://cloud.google.com/iam/docs/keys-create-delete#creating). 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Integrations**. 1. Find and click **Google Play**. ![google-service-account_png.png](/img/_paligo/uuid-86e5dd1c-f147-0a08-49bb-da4f53b9a960.png) 1. Click **Add service account**. 1. Type a name in the **Name** field. 1. In the **Credentials** section, drag and drop your JSON key file or click **Upload a JSON file** to upload it from your computer. ![add-json-file.png](/img/_paligo/uuid-48a9ebfc-c07d-81f3-7b87-09f6fdcc1794.png) 1. Once done, click **Add account**. ### Connecting a Google service account to a project To configure a Bitrise project to use a given Google Play Console service account: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select the **Integrations** menu option. 1. Go to the **Stores** tab. 1. Find the **Google Play Store** section. 1. Click the **Select...** button. ![select-button.png](/img/_paligo/uuid-d9ad5624-810e-4fbf-507a-f900e03620e5.png) 1. In the pop-up window, select an account from the dropdown menu labeled with **Select an account**. ![attach-service-account.png](/img/_paligo/uuid-f8d70389-5398-fa2c-3a98-db70ffa63853.png) 1. Click **Save**. --- ## Connecting to a VPN during a build You might require a VPN connection for your build, to be able to connect to your server, either to `git clone` your repository or to access a private API. To connect to a VPN, you need to: 1. Make sure your local network address space does not clash with the [Bitrise virtual machines' address space](/bitrise-platform/infrastructure/build-machines/configuring-your-network-to-access-our-build-machines) as this can cause an error with the VPN. 1. Install and configure the required VPN components. 1. Connect to the VPN. You can configure and connect a VPN anywhere in your Workflow - BEFORE you would use the VPN connection, of course. For example, if you require a VPN connection to access your repository, you have to connect before the [**Git Clone Repository**](https://github.com/bitrise-steplib/steps-git-clone) Step. :::caution[SSH sessions] When you choose your VPN tool and do the setup/configuration, you have to be careful NOT TO RESTART OR ABORT existing SSH sessions! The [bitrise.io](https://www.bitrise.io) workers will abort the build if the SSH connection between the build’s Control/Master machine and the build virtual machine terminates! ::: ### Accessing a repository via VPN If the repository of your Bitrise project can be only accessed via VPN, you have two things to keep in mind above all: - During builds, the VPN connection must be established before cloning the repository to our virtual machines: in practice, this means the Step establishing the connection must be placed before the **Git Clone**Step in your Workflow. - When adding a new project, you need a workaround: use a dummy repository that can be accessed without a VPN during the process of adding the project. Let’s go through this workaround! 1. Create an empty repository that is accessible without a VPN connection. 1. Add a new project, using this repository as the source. Make sure it is a private project! There is no need to register a [webhook](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks). 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Repository** and click **Change**. 1. In the dialog, paste the new repository URL. ![SCR-20260331-przw.png](/img/_paligo/uuid-fa95efd5-ff6f-a7a3-2dc3-7ccc5878cd47.png) 1. Click **Save**. 1. Place the Step or Steps establishing the VPN connection before any Steps that have to access your repository in your Workflow. And you’re done. For the different methods of establishing a VPN connection, take a look at our example configurations. ### Example VPN configurations In this section, we present three example configurations for connecting to a VPN during a build: - [Using an OpenVPN server](#using-the-connect-to-openvpn-server-step). - [Using Strongswan VPN](#using-strongswan-vpn). - [Using Cisco VPN](#using-cisco-vpn). #### Using the Connect to OpenVPN Server Step To use the **Connect to OpenVPN Server** Step, you need to build an OpenVPN server in advance, and then encode your certificate files and your private key. 1. [Set up an OpenVPN Server](https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-18-04). 1. Encode the following in Base64: - CA certificate - client certificate - client private key You can base64 encode files with the following command: ```bash $ base64 ``` 1. Open your project on Bitrise and go to the Workflow Editor. 1. Register the encoded certificates and the key as [Secrets](/bitrise-ci/configure-builds/secrets). We recommend using the following keys as they are the default inputs for the VPN Step: - CA certificate: `$VPN_CA_CRT_BASE64` - Client certificate: `$VPN_CLIENT_CRT_BASE64` - Private key: `$VPN_CLIENT_KEY_BASE64` 1. Add the **Connect to OpenVPN Server** Step to your Workflow. Add the Step before any Steps that might require VPN connection. 1. Add the previously created Secrets to their respective inputs: - **Base64 encoded CA Certificate** - **Base64 encoded Client Certificate** - **Base64 encoded Client Private Key** If you created the Secrets with the recommended keys, you do not have to change the inputs. 1. Fill in the other required inputs. - **Host**: the Open VPN Server IP or hostname - **Port**: OpenVPN Server Port number - **Protocol**: OpenVPN Server Protocol #### Using Strongswan VPN This is an example script which you can either save into your repository and run it from there, or just copy paste its content into a **Script Step** in your `bitrise` configuration (`bitrise.yml` / Workflow). The script uses Strongswan VPN to connect to a VPN. It works on either macOS or Linux. Once the script has run successfully, any subsequent Bitrise Step can access devices and services over the VPN connection. ```bash #!/usr/bin/env bash set -e echo "WAN IP" # This prints the servers Internet IP adress to the log, useful for debugging curl http://httpbin.org/ip case "$OSTYPE" in linux*) echo "Configuring for Linux" # Variables etc_dir=/etc etc_sudo='sudo' # Sudo is needed for Linux Strongswan configuration # Install strongswan echo "Installing Strongswan..." sudo apt-get install -y strongswan ;; darwin*) echo "Configuring for Mac OS" # Variables etc_dir=/usr/local/etc etc_sudo='' # Sudo is NOT needed for Mac OS Strongswan configuration # Install Strongswan using homebrew echo "Installing OpenSSL..." # Manually install OpenSSL first to save time, since installing Strongswan directly compiles OpenSSL from source instead brew install openssl echo "Installing Strongswan..." brew install strongswan ;; *) echo "Unknown operative system: $OSTYPE, exiting" exit 1 ;; esac # Method for rendering a template string file (when run, returns the input string with $VARIABLES replaced from env) render_template() { eval "echo \"$(cat $1)\"" } # Create a temporary directory to hold files temp_dir=/tmp/vpn-config mkdir $temp_dir # IPsec config file, see examples at https://wiki.strongswan.org/projects/strongswan/wiki/IKEv1Examples and https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2Examples echo "Downloading ipsec.conf..." wget https://www.example.com/ipsec.conf.template -O $temp_dir/ipsec.conf.template # IPsec credentials file, see documentation at https://wiki.strongswan.org/projects/strongswan/wiki/IpsecSecrets echo "Downloading ipsec.secrets..." wget https://www.example.com/ipsec.secrets.template -O $temp_dir/ipsec.secrets.template # In some cases you might need to download the certificate, or certificate chain, of your other VPN endpoint echo "Downloading server.crt..." wget https://www.example.com/server.crt -O $temp_dir/server.crt echo "Rendering config templates" render_template $temp_dir/ipsec.conf.template > $temp_dir/ipsec.conf render_template $temp_dir/ipsec.secrets.template > $temp_dir/ipsec.secrets echo "Installing configuration" $etc_sudo cp $temp_dir/ipsec.conf $etc_dir/ipsec.conf $etc_sudo cp $temp_dir/ipsec.secrets $etc_dir/ipsec.secrets $etc_sudo cp $temp_dir/server.crt $etc_dir/ipsec.d/ocspcerts/server.crt # Start the ipsec service echo "Starting ipsec" sudo ipsec start # We're sleeping between commands, mostly since Mac OS seems to have some problems otherwise sleep 1 # Output some helpful status to the log echo "Status ipsec" sudo ipsec statusall sleep 1 # Switch out myconnection with the name of your connection in ipsec.conf echo "Initiating VPN connection" sudo ipsec up myconnection sleep 1 case "$OSTYPE" in linux*) ;; darwin*) # In Mac OS El Capitan, the `sudo ipsec up` command consistently fails the first time, but succeeds after a restart of the ipsec service echo "Restarting ipsec" sudo ipsec restart sleep 1 echo "Initiating VPN connection" sudo ipsec up myconnection sleep 1 # This step might apply if you are routing all traffic trough the IPsec connection (that is, if your remote IP range is 0.0.0.0/0) # Mac OS El Capitan seems to have problems getting the DNS configuration from the Strongswan interface. Also IPv6 sometimes causes issues. So we're manually turning off IPv6 and forcing a new DNS configuration. echo "Disabling IPv6 and forcing DNS settings" # Fetch main interface main_interface=$(networksetup -listnetworkserviceorder | awk -F'\\) ' '/\(1\)/ {print $2}') # Completely disable IPv6 sudo networksetup -setv6off "$main_interface" # Switch 10.0.0.1 with your DNS server sudo networksetup -setdnsservers "$main_interface" 10.0.0.1 ;; *) ;; esac # Your VPN connection should be up and running. Any following steps of your Bitrise workflow can access devices over your VPN connection 🎉 ``` #### Using Cisco VPN You can use the **Cisco VPN connect** Step: it connects with Cisco VPN provided by VPN3000 Concentrator, Juniper/Netscreen, IOS and PIX using vpnc. 1. 1. Log in to Bitrise and select **Bitrise CI** on the left, then select your project. 1. Click the **Workflows** button on the main page. 1. Add the **Cisco VPN connect** Step at the start of your Workflow. 1. Provide VPN client settings and credentials required for the Step either by: - Using the existing vpnc configuration file: `vpnc.conf` - Using the **Commandline options** input of the Step. The options specified in this input will take precedence over the configuration file! For more information on setting up vpnc, check the [vpnc homepage](https://www.unix-ag.uni-kl.de//~massar/vpnc/) and the [vpnc manual](https://linux.die.net/man/8/vpnc). --- ## Endpoint Detection and Response ### No EDR on Bitrise CI runners Endpoint Detection and Response (EDR) tools monitor endpoint activity and alert security teams about suspicious behavior. They are commonly used on employee laptops and long‑lived servers. Bitrise does use EDR internally as part of our corporate security program. This use does not extend to EDR agents on Bitrise‑hosted CI runners. Bitrise build VMs are ephemeral, short‑lived environments optimized for CI/CD performance. Running EDR in this context introduces tradeoffs: - Performance and reliability impact: EDR agents consume CPU, memory, and I/O, and can slow down or interfere with performance‑sensitive builds. Since Bitrise build VMs commonly run at or near 100% CPU during builds, additional overhead can negatively affect build times and reliability. - Most commercial EDR solutions are primarily optimized for long‑lived endpoints. On short‑lived, compute‑intensive CI/CD runners, their effectiveness is more limited, while the performance and operational costs remain. - Alternative controls: Instead of EDR on build VMs, Bitrise focuses on other security controls better suited to the CI/CD context (for example, hardened base images and image scanning). ### Options for users who require EDR Customers with strict EDR requirements can deploy and manage their own EDR solution on suitable Bitrise infrastructure. Customers using private or dedicated clusters can: - Use pre‑warm or similar mechanisms to install and configure their own EDR agents before builds start. - Use their own EDR licenses, policies, and backend systems. In this model: - The customer is responsible for selecting, installing, configuring, and maintaining the EDR solution. - All alerts, telemetry, and incident response activities are handled by the customer’s own security operations capabilities. - Bitrise does not operate, monitor, or manage the customer’s EDR agents. :::tip[Contact us] If you have any questions regarding your security requirements, contact us at letsconnect@bitrise.io. ::: --- ## OIDC authentication overview OpenID Connect (OIDC) is an identity authentication layer built on the OAuth 2.0 framework. It allows third-party applications to verify the identity of the end user, including using Single Sign-On across applications. OIDC works by issuing ID tokens (typically JSON Web Tokens or JWTs) that provide information about the authentication operation's outcome and about the user's identity. The data about the authentication outcome and the user information are called claims. The service that receives the token evaluates the token's claims against its OIDC policy. If the token's claims match the policy, the request is permitted; if they don't, it is rejected. Bitrise supports the use of OIDC tokens in two ways: - To enable your Bitrise builds to authenticate to external systems such as AWS, GCP, Azure, container registries, secret management or artifact stores. - To use foreign OIDC tokens to authenticate to Bitrise and receive short-lived Bitrise tokens. ### Authentication to external services with OIDC OIDC enables your builds to authenticate to external systems (such as AWS, GCP, Azure, container registries, secret management or artifact stores) without embedding long-lived credentials in your Workflows. Bitrise can mint one or more identity tokens tied to a specific build, with claims such as a build number, commit hash, repository slug, app slug, or Workflow name. These tokens are: - Issued for a particular build interaction so third-party services can grant access scoped only to that run. - Short-lived to minimize the consequences of potential exposure. - Consumable by federated services that accept OIDC: for example, you can exchange a Bitrise OIDC token for temporary cloud credentials. #### Request an identity token for your build To use an OIDC token to authenticate to a service from a Bitrise build, you need to fetch the token and then perform the credential exchange with the service. Bitrise offers Steps that handle parts of the process. ##### Get OIDC Identity Token Step Use an OIDC token in your build for any service with the **Get OIDC Identity Token** Step. This Step lets your Workflows and Pipelines request temporary, auditable access to cloud resources or external services at runtime, without storing secrets in the repository or build configuration. Set the **Token audience** input to configure the Step. This could be the URL of the service you want to access with the token or a specific identifier provided by the service. ![2025-11-12-get-oidc-token-step.png](/img/_paligo/uuid-aad02a5a-3899-01eb-0842-76bfcc14b1d4.png) The Step exports an Environment Variable with the key BITRISE_IDENTITY_TOKEN, containing the relevant information of the token. Use it to exchange credentials with the service you want to access. ##### Dedicated Steps for specific services The **Get OIDC Identity Token** Step lets you fetch an OIDC token for any service but it doesn't perform the credential exchange for you. For some services, we have Steps that take the care of the whole process: - **Authenticate with Google Cloud Platform (GCP)**: Generates a Google auth token using a service account key, and authenticates to GCP. - **Authenticate with Amazon Web Services (AWS)**: Generates an identity token based on an AWS IAM identity provider. You can read our full guide here: [OIDC for AWS](/bitrise-platform/integrations/oidc-authentication/oidc-for-aws). #### Information in the OIDC token Bitrise includes the following information in the OIDC token: :::important[Limitation] As Bitrise is considered a generic identity provider, AWS keeps only two claims from our token: `aud` and `sub`. You can only use these in your policies. You can find more information about claim fields in the [AWS documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_String). ::: | `Name` | `Description` | | --- | --- | | `aud` | Customizable audience field | | `sub` | The subject that triggered the ID token creation It will be in the `app:APP_SLUG:workflow:WORKFLOW` format. | | `exp` | The token expiration time | | `iat` | The time of the token generation | | `iss` | Who issued the token | | `jti` | Token unique identifier | | `nbf` | The current time | | `sha` | Git commit hash | | `repository_url` | The url of the app's associated git repo | | `repository_owner` | The git repository owner | | `repository_slug` | Git repository slug | | `app_slug` | App slug | | `workspace_slug` | Workspace slug | | `trigger_by` | What entity triggered the build | | `branch` | The branch that is getting built | | `branch_dest` | PR target branch | | `tag` | The tag which triggered the build | | `build_number` | Build number | | `workflow` | Name of the triggered workflow | ### Authentication to Bitrise with OIDC Bitrise supports using external OIDC tokens to authenticate to Bitrise and receive short-lived Bitrise [workspace access tokens](/bitrise-platform/workspaces/workspace-api-token). The issued token will be matched against your Bitrise trust policy. A service that receives a Bitrise token essentially becomes a temporary member of your workspace that can perform certain actions defined in your trust policy. For example, it can receive data from a build triggered on a specific branch of a given repository. #### Trust policy An OIDC trust policy defines who to trust, under what conditions, and how to validate the OIDC tokens. A Bitrise trust policy defines: - The OIDC issuers that Bitrise will trust. Claims from OIDC providers that aren't listed as issuers in our trust policy are automatically rejected. - The duration of the short-lived token: how long it is valid. - Its level of access: the roles and permissions it grants in workspaces and projects. - The matching rules of the token: the claims that must be matched. For example, the claim can include the repository, the branch of the repository, the Workflow that should be triggered. The matching rules are in a JSON format. #### OIDC token request After a policy is successfully created, Bitrise automatically generates a unique policy ID. This policy ID must be included in every token request. When a service sends an OIDC token to request a short-lived Bitrise workspace access token, Bitrise matches the policy ID in the request to the corresponding trust policy and checks that trust policy's matching rules. If the rules match the OIDC token's claims, the short-lived token is granted. --- ## OIDC for AWS Generate OpenID Connect (OIDC) tokens during your Bitrise build to exchange them for AWS Identity and Access Management (IAM) roles with AWS-scoped permissions. To use OIDC tokens for AWS, you'll need to: - Create an IAM OIDC provider in your AWS account. - Add a custom trust policy: this means writing the rules for the identity tokens. On Bitrise, you can get the tokens by using either the [**Get OIDC identity token**](https://github.com/bitrise-steplib/bitrise-step-get-identity-token) Step or the [**Authenticate with Amazon Web Services (AWS)**](https://github.com/bitrise-steplib/bitrise-step-authenticate-with-aws) Step. ### Adding an OIDC identity provider in IAM Set up an IAM OIDC provider in your AWS account. :::tip[AWS user guide] Read more about IAM OIDC providers in the [official AWS user guide](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html). ::: 1. Log in to your AWS account. 1. Go to **IAM**. 1. On the left, find **Access Management** and select **Identity providers**. 1. Click **Add Provider**. 1. Select **OpenID Connect**. 1. Set the **Provider URL** field to https://token.builds.bitrise.io. 1. Set the **Audience** field to `sts.amazonaws.com`. 1. Click **Add provider**. ![2025-11-11-aws-iam-provider.png](/img/_paligo/uuid-019f250f-8d48-a51c-738b-db46d0829339.png) 1. On the **Identity providers** page, select the newly created identity provider and copy the ARN. The ARN looks something like this: `arn:aws:iam::ACCOUNT_NUMBER:oidc-provider/token.builds.bitrise.io`. ### Adding a custom trust policy Add a custom trust policy in AWS IAM to write the rules for the Bitrise identity tokens. :::tip[AWS docs] Our guide helps you set up your AWS policy for your Bitrise builds. You can read more about trust policies in the AWS documentation: [Create a role using custom trust policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-custom.html). ::: 1. Log in to your AWS account. 1. Go to **IAM**. 1. On the left, find **Access Management** and select **Roles**. 1. Click **Create role**. ![2025-11-11-aws-roles.png](/img/_paligo/uuid-8fc9a70b-c1a9-6ce2-4369-8701e891f0d5.png) 1. Select **Custom trust policy**. ![2025-11-11-custom-trust-policy.png](/img/_paligo/uuid-2aed5814-692a-476b-f993-617cdb2c338f.png) 1. Create a statement in the custom trust policy editor to set the rules for OIDC tokens: :::tip[Creating policies] You can read detailed information about how to create policies in the AWS documentation: [Creating IAM policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_create-console.html#access_policies_create-start). ::: - Add a `Principal`: the type should be a federated user session, with your previously created ARN. See `Federated` in the example below. - Add an `Action` with the `sts:AssumeRoleWithWebIdentity` value. - Under `Conditions`, match against the claims in the identity token. :::important[Limitation] As Bitrise is considered a generic identity provider, AWS keeps only two claims from our token: `aud` and `sub`. You can only use these in your policies. You can find more information about claim fields in the [AWS documentation](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_String). ::: The example below checks the audience, the Bitrise project slug, and the Workflow name: ```json { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Federated": "arn:aws:iam::ACCOUNT_NUMBER:oidc-provider/token.builds.bitrise.io" }, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "token.builds.bitrise.io:aud": "sts.amazonaws.com", "token.builds.bitrise.io:sub": "app:APP_SLUG:workflow:run-tests" } } } ] } ``` You can also use wildcards with the `StringLike` operation instead of `StringEquals`: [Wildcard matching](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_String-wildcard). 1. When done, click **Next**. 1. Select the required permission for the role. The required permission depends on what service you're trying to access on AWS. For example, to upload files to an S3 bucket during a build, you can select **AmazonS3FullAccess**. :::note[Custom access policy] You can also create your own custom policy in AWS to set up the exact permissions you need. ::: 1. When done, click **Next**. 1. Name your role and optionally, add a description. 1. Click **Create a role** when done. ### Fetching and exchanging tokens After you successfully configured an OIDC identity provider with a custom trust policy on AWS, your Bitrise builds can exchange tokens with the service of your choice. You can: - Use the **Authenticate with AWS** Step to handle the whole process. - Fetch the token with **Get OIDC Identity Token** Step, then perform the credential exchange with a script. :::note[Information in the OIDC token] Bitrise includes the following claims in the OIDC token: [Information in the OIDC token](/bitrise-platform/integrations/oidc-authentication/oidc-authentication-overview#information-in-the-oidc-token). ::: #### Using the Authenticate with AWS Step The **Authenticate with AWS** Step requests an OIDC token and performs the credential exchange with AWS. That means you don't have to create your own script to perform the authentication, the Step will handle it for you. 1. Open the Workflow Editor on Bitrise. 1. Add the **Authenticate with AWS** Step to your Workflow. 1. Set the **Token audience** input to `sts.amazonaws.com`. 1. Set the **AWS Role ARN** to the value of the IAM role ARN that you created earlier. :::tip[Docker login] Another convenience feature of the Step is that it can log in Docker to the EC2 Container Registry automatically. Find the **Docker** input group in the Step configuration, and set it to `true`. This is only supported on Linux stacks. ::: #### Using the Get OIDC Identity Token Step 1. Open the Workflow Editor on Bitrise. 1. Add the **Get OIDC Identity Token** Step to your Workflow. 1. Set the **Token audience** input to `sts.amazonaws.com`. 1. Use the BITRISE_IDENTITY_TOKEN Environment Variable: it can be fed to any CLI tool or API endpoint. You can create a script in a **Script** Step to perform the token exchange and extract credentials from the response. You'll need three Env Vars as credentials: - AWS_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY - AWS_SESSION_TOKEN After they are exported, the AWS CLI will automatically pick them up and use them. Any kind of action through the CLI will just simply work. For example, getting short term credentials and printing the current authenticated session details with the AWS CLI would look like this: ```bash # Perform the token exchange and save the response AWS_RESPONSE=$(aws sts assume-role-with-web-identity \ --role-arn "arn:aws:iam::065600603509:role/OIDC-TEST" \ --role-session-name "bitrise-${BITRISE_BUILD_NUMBER}" \ --web-identity-token "$BITRISE_IDENTITY_TOKEN" \ --output json) # Extract the credentials from the reponse export AWS_ACCESS_KEY_ID=$(echo "$AWS_RESPONSE" | jq -r '.Credentials.AccessKeyId') export AWS_SECRET_ACCESS_KEY=$(echo "$AWS_RESPONSE" | jq -r '.Credentials.SecretAccessKey') export AWS_SESSION_TOKEN=$(echo "$AWS_RESPONSE" | jq -r '.Credentials.SessionToken') # The AWS cli will automatically pick up the env vars from the section above aws sts get-caller-identity ``` --- ## OIDC for Bitrise Create an Open ID Connect (OIDC) trust policy and send an OIDC token with `app.bitrise.io` as the audience for an OIDC credential exchange. This allows third-party services to authenticate to your Bitrise workspace and access Bitrise resources. For more information on how OIDC works, see [Authentication to Bitrise with OIDC](/bitrise-platform/integrations/oidc-authentication/oidc-authentication-overview#authentication-to-bitrise-with-oidc). ### Creating a trust policy on Bitrise Create an OIDC trust policy to grant external services access to Bitrise resources via an OIDC token exchange. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Select **Security** and then go to the **OIDC trust policies** tab. ![2026-03-11-oicd-trust-policies.png](/img/_paligo/uuid-3424f770-b6c1-749a-b936-6d073bab7469.png) 1. Click **New OIDC policy**. 1. Fill out the policy details: - **Policy name**: The policy identifier. - **Issuer (iss)**: The HTTPS URLs for identity providers that Bitrise will trust. - **Session duration**: How long the token will be valid. ![2026-03-11-oicd-new-policy.png](/img/_paligo/uuid-fb66f7d5-2c56-4480-4a54-4d79a29c6c67.png) 1. On the next page, set matching rules in a JSON format. Matching rules define which claims Bitrise must see in the token to match the trust policy. :::important You must have at least one matching rule. The `sub` claim is mandatory: it identifies the subject that triggered the token exchange. ::: For example, you can create matching rules for a specific branch of a repository and names a Workflow: ```json { "sub": "repo:my-org/my-repo:environment:prod", "workflow": "CI", "ref": "refs/heads/main", "repository": "my-account/my-repo" } ``` 1. On the next page, set up a workspace role for the short-lived token. The workspace role determines the access level of the token. Read more: [Roles and permissions in workspaces](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces). 1. On the next page, configure product access. Grant full admin access to all products, or grant granular access to either Bitrise CI or Release Management or both: - Select **Admin access** to grant admin access to all projects owned by the workspace. - Select **Bitrise CI** and/or then select the projects or Release Management apps and access roles for the token. It can have different levels of access on different projects! Read more: [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) - Select **Release Management** then select the Release Management apps and access roles for the token. It can have different access levels on different Release Management apps. Read more: [Release Management roles and permissions](/release-management/configuring-connected-apps/release-management-roles-and-permissions) 1. When ready, click **Create policy**. ### Crafting a token request After you create at least one trust policy on Bitrise, you can create OIDC token exchange requests to receive short-lived tokens from Bitrise. 1. Get an OIDC token from the service you want to authenticate to Bitrise. The exact method of getting the token depends on the service. For example: [Request a token from GitHub Actions](https://docs.github.com/en/actions/reference/security/oidc#methods-for-requesting-the-oidc-token). 1. Use the token in the exchange request to Bitrise. The request must contain the policy ID and it must be submitted to `app.bitrise.io`. ```yaml curl -i -X POST https://app.bitrise.io/oidc/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \ -d "subject_token_type=id_token" \ -d "policy_id=" \ -d "subject_token=" ``` You can also send a request as `application/json`: ```yaml curl -i -X POST https://app.bitrise.io/oidc/token \ -H "Content-Type: application/json" \-d "{ \"grant_type\": \"urn:ietf:params:oauth:grant-type:token-exchange\", \"subject_token_type\": \"id_token\", \"subject_token\": , \"policy_id\": }" ``` --- ## OIDC for GCP Generate OIDC tokens during your Bitrise build to exchange them for scoped access tokens with Google Cloud Platform (GCP). To use OIDC tokens for GCP, you'll need to: - Create a workload identity pool. - Connect a Google service account to the identity pool. On Bitrise, you can get the tokens by using either the [**Get OIDC Identity Token**](https://github.com/bitrise-steplib/bitrise-step-get-identity-token) Step or the [**Authenticate with Google Cloud Platform (GCP)**](https://github.com/bitrise-steplib/bitrise-step-authenticate-with-gcp) Step. ### Creating a workload identity pool Create a workload identity pool in GCP to enable Workload Identity Federation. :::tip[Workload Identity Federation] Read more about how authentication with Workload Identity Federation works on GCP in the [official Google documentation.](https://cloud.google.com/sap/docs/abap-sdk/on-premises-or-any-cloud/latest/authentication-wif) ::: 1. In the Google Cloud console, go to **IAM & Admin** then **Workload Identity Federation**. 1. In the **Create an identity pool** section, enter a value for the following fields: - **Name**: The name for the pool. The name is used as the pool ID and you can't change the pool ID later. - **Description**: The purpose of the pool. 1. Under **Add a provider to pool**, add Bitrise as a provider: - In the **Select a provider** field, select **OpenID Connect (OIDC)**. - **Provider name**: Enter a name. For simplicity, we recommend using `Bitrise`. - **Issuer URL**: https://token.builds.bitrise.io. - **Audience**: Select **Allowed audience**. When using the token, GCP will check if the allowed audience matches the audience encoded in the `aud` claim. On Bitrise, you can set the audience in our Steps providing OIDC services: [Fetching and exchanging tokens with GCP](/bitrise-platform/integrations/oidc-authentication/oidc-for-gcp#fetching-and-exchanging-tokens-with-gcp). 1. Click **Continue**. 1. Under **Configure provider attributes**, configure the required attribute mapping values: - The `google.subject` key is a unique identifier for the user. You can use `assertion.sub` to identify the build that requests the token. - Use the `attribute.NAME` format to add up to 50 custom attributes, each with a value in the `assertion.VALUE` format. You can find the list of available attributes in the Bitrise token here: [Information in the OIDC token](/bitrise-platform/integrations/oidc-authentication/oidc-authentication-overview#information-in-the-oidc-token). :::important[Explicit mapping required] You must map all the attributes you want to use. Google only lets you use the attributes which are explicitly mapped. Read more about [attribute mappings in Google's documentation](https://cloud.google.com/iam/docs/workload-identity-federation?_gl=1*1sz7kri*_ga*MTM0MTUyNjA1OC4xNzYyNTMwMjA5*_ga_WH2QY8WWF5*czE3NjM0Nzc1MzYkbzIkZzEkdDE3NjM0Nzc4MDEkajUwJGwwJGgw#mapping). ::: 1. Optionally, add attribute conditions. You will also be able to filter identity tokens based on attributes directly at the pool level when creating the service account. ### Connecting a Google service account to the workload identity pool To start using OIDC authentication for GCP services, you need to connect a workload identity pool to a Google service account. This involves: - Creating a service account. - Granting access to the identity pool using a service account impersonation. #### Create a service account 1. In Google Cloud console, go to **IAM & Admin** and then **Service accounts**. 1. Click **Create service account**. 1. Add a display name, a unique service account ID, and a description. 1. Click **Create and continue**. 1. Under **Permissions**, add all roles that you need. :::note[IAM conditions] Optionally, you can add IAM conditions based on the previously mapped attribute values by clicking **Add IAM condition**. ::: 1. Click **Done**. #### Granting access to the workload identity pool 1. In Google Cloud console, go to **IAM & Admin** and then **Workload Identity Federation**. 1. Select your identity pool. 1. Click **Grant access**. 1. Select the **Grant access using service account impersonation** option. 1. Select the service account you've created. 1. Select the principals: identities that can access the service account. The available options are limited to the keys from the provider attribute mapping of the identity pool. For example, if you use the attribute mapping `google.subject=assertion.sub`, set **Attribute name** to `subject` and **Attribute value** to `sub`. You can see the available values in the Bitrise token here: 1. Click **Save**. 1. In the dialog, select the provider you created for Bitrise OIDC tokens. 1. Add the OIDC ID token path: https://token.builds.bitrise.io and set the format to **text**. 1. Click **Download config** and save the file somewhere you can access it. ### Fetching and exchanging tokens with GCP After you successfully configured a workload identity pool and connected it to a Google service account, your Bitrise builds can exchange tokens with GCP. You can: - Use the **Authenticate with GCP** Step to handle the whole process. - Fetch the token with **Get OIDC Identity Token** Step, then perform the credential exchange with a script. :::note[Information in the OIDC token] Bitrise includes the following claims in the OIDC token: [Information in the OIDC token](/bitrise-platform/integrations/oidc-authentication/oidc-authentication-overview#information-in-the-oidc-token). ::: #### Using the Authenticate with GCP Step 1. Open the Workflow Editor on Bitrise. 1. Add the **Authenticate with GCP** Step to your Workflow. 1. Set the **Client config** and the **Token audience** inputs: - The token audience should match the allowed audience you set when configuring the workload identity pool on Google Cloud. - The **Client config** input should point to the file you downloaded at the end of the process. #### Using the Get OIDC Identity token Step 1. Open the Workflow Editor on Bitrise. 1. Add the **Get OIDC Identity Token** Step to your Workflow. 1. Use the BITRISE_IDENTITY_TOKEN Environment Variable: write it to a file and update the [client library configuration file](/bitrise-platform/integrations/oidc-authentication/oidc-for-gcp#connecting-a-google-service-account-to-the-workload-identity-pool) to reference the file containing the Env Var. You can set this up in a **Script** Step: ```bash tmpfile="$(mktemp)" printf '%s' "$BITRISE_IDENTITY_TOKEN" > "$tmpfile" # Replace the token path in client library configuration gcloud auth login --cred-file=/path/to/updated-client-library-config.json gcloud auth list ``` After, the gcloud CLI will automatically pick them up and use them. Any kind of action through the CLI will just simply work. --- ## The service credential user The service credential is a user whose connected Git provider account (GitHub, GitLab or Bitbucket) is used to access those Git services for certain actions that Bitrise can execute. :::important[GitHub project] The service credential user is NOT required if you use the [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) to connect to your Git repositories. ::: You need to set a service credential user, among other things, to: - Send [build status reports](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider) back to your Git provider. - Use the [Selective builds](/bitrise-ci/configure-builds/configuring-build-settings/selective-builds) feature that allows you to specify certain files or directories in your repository that need to be modified to trigger an automatic Bitrise build. - [Store the `bitrise.yml` file in your repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository). :::tip[Actions and requirements] For the full list of actions and their access requirements, see [Service credential user actions and their required repository access](/bitrise-platform/integrations/the-service-credential-user#service-credential-user-actions-and-their-required-repository-access). ::: By default, the user who added the project to Bitrise is set as the service credential user. Even if you change it, it should always be a user who has access to the project's repository. It isn't mandatory to have a service credential user: you can use the **No service credential user** setting to not have one. You'll still be able to run builds and trigger builds automatically but Bitrise won't be able to send build status reports to your Git provider, you won't be able to use the [Selective builds](/bitrise-ci/configure-builds/configuring-build-settings/selective-builds) feature or to store the bitrise.yml file in your repository. ### Changing the service credential user The service credential user can be changed at any time but you can only set yourself as the service credential user on a Bitrise project. :::important[Role requirement] To change the service credential user, you need to have **Admin**[role on the project's team](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) on Bitrise. ::: To change the service credential user: 1. Log in to Bitrise with the account that will be the new service credential user. 1. Make sure that account has **Admin** role on the [project's team](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. Go to your workspace's main page. 1. Select the project where you want to change the service credential user. 1. Click on **Project Settings**. 1. On the left, select **Integrations** from the menu options. 1. Scroll down to the **Service credential user** part. 1. Click **Change SCU** (or **Set SCU** if no service credential user is set yet). :::note[Disabling OAuth project access restrictions for your GitHub organization] If you receive an error while trying to connect or change the service credential user for your project, make sure that the user has the project access to the GitHub repository and that **Third-party app access policy restrictions** are disabled. For more information on how to disable the Third-party app access policy on GitHub, check out [Disabling OAuth project access restrictions for your organization](https://docs.github.com/en/organizations/managing-oauth-access-to-your-organizations-data/about-oauth-app-access-restrictions). ::: 1. To confirm, click **Change**. ### Service credential user actions and their required repository access :::important[GitHub project] The service credential user is NOT required if you use the [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) to connect to your Git repositories. ::: The service credential user allows Bitrise to execute a number of different actions that require access to your project's Git repository. Different actions require different levels of access: for example, [to use a `bitrise.yml` file from the repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository) requires **read** access on GitHub while [registering a new SSH key](/bitrise-platform/repository-access/configuring-ssh-keys) requires **admin** access. The following table contains all the actions that require the service credential user, as well as the access level of the service credential user's account at the the three main Git providers | Action | Required access level on GitHub | Required access level on Bitbucket | Required access level on GitLab | | --- | --- | --- | --- | | [Using a `bitrise.yml` from the repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository) | read | read | reporter | | List the branches of the repository | read | read | reporter | | [Selective builds](/bitrise-ci/configure-builds/configuring-build-settings/selective-builds) | read | read | reporter | | [Sending Git status reports](/bitrise-ci/configure-builds/configuring-build-settings/reporting-the-build-status-to-your-git-hosting-provider) | write | write | GitLab.com: developer Self-hosted GitLab: maintainer | | [Registering SSH keys to the repository](/bitrise-platform/repository-access/configuring-ssh-keys) | admin | admin | maintainer | | [Register a webhook](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks#registering-an-incoming-webhook-automatically) | admin | admin | maintainer | | Checking the Git connection on bitrise.io | admin | admin | maintainer | --- ## Adding incoming webhooks An incoming webhook on Bitrise serves one purpose: to start builds automatically when a certain code event (code push, Git Tag, pull request) happens. You need to register an incoming webhook to your repository and [configure build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers). :::note[Webhook issues] If your builds triggers don't work, there might be a problem with your webhooks: [Builds aren't getting triggered](https://support.bitrise.io/hc/en-us/articles/360014238237). ::: ### Registering an incoming webhook automatically Automatic webhook registration is supported for projects that have their code hosted on GitHub, GitLab and Bitbucket. If you use one of the above services as your source code hosting provider, Bitrise automatically sets up a webhook for it with a click of a button at the end of your [project setup journey](/bitrise-ci/getting-started/adding-a-new-project). :::note[GitHub App integration] If you use [the Bitrise GitHub App](/bitrise-platform/repository-access/github-app-integration) to connect your Bitrise Workspace to a Git account or organization, you don't need a webhook. The app can trigger builds or send status updates without it. ::: However, you can always change this webhook later or add a new one if you skipped registering a webhook when adding the project. You can automatically register a webhook to the repository on the **Project settings** page. Automatic registration means that Bitrise registers the webhook at the repository, so you don't have to manually go there and add it on your Git provider's website. This requires: - That you have admin rights to the repository. - That the account that hosts the repository is connected to your Bitrise account. To register a webhook automatically: 1. Make sure your Bitrise account is connected to the Git provider account that hosts the repository and that your Git account has admin rights to the repository. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Integrations**. 1. On the top of the Integrations page, select the **Webhooks** tab. ![webhooks-tab.png](/img/_paligo/uuid-00d7e0d5-df77-2b41-222b-c7ff05829144.png) 1. In the **Incoming webhooks** section, select **Add webhook**. Bitrise will automatically register a webhook at the project's repository. ### Registering an incoming webhook manually You can manually setup or change your webhooks after you registered your project on Bitrise. The process is different depending on your Git provider but on Bitrise, the basic steps are the same for each. :::note[Create your own webhook implementation] [Our webhook processor is Open Sourced](https://github.com/bitrise-io/bitrise-webhooks). If you are looking for an unsupported solution, you can create an issue on the GitHub page or create a pull request with the implementation. You can also run your own webhook provider behind your own firewall if required. ::: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Integrations**. 1. On the top of the Integrations page, select the **Webhooks** tab. ![webhooks-tab.png](/img/_paligo/uuid-00d7e0d5-df77-2b41-222b-c7ff05829144.png) 1. Scroll down to the **Incoming webhooks** section and open **Manual webhooks**. ![manual-webhooks.png](/img/_paligo/uuid-c1dec9c9-49a4-90c6-40b3-c3d69088567b.png) 1. Copy the webhook URL and register it at your Git provider. --- ## Adding outgoing webhooks You can configure Bitrise CI to send build event notifications to any service you would like. A build event is: - When a build is started. - When a build ends. You can also configure outgoing webhooks for Bitrise Release Management. These webhooks are triggered by release management events: [Outgoing webhooks in Release Management](/release-management/releases/configuring-a-release/outgoing-webhooks-in-release-management). You can use this notification to share build statuses with your Git provider if we don’t support it yet, notify only the right team about build success or failure, or use it to automate your in-house release pipeline. You can add, remove and edit your webhooks on the website interface. :::tip[Accessing services that are behind a firewall] If you need to access a service that is behind a firewall, you can't use outgoing webhooks: the payload won't get past the firewall. To access such a service, we recommend configuring the firewall to allow the Bitrise build machines to access it, and then make the request from within the build machine. For more information on how to do so, check out the relevant guides: - [Configuring your network to access our build machines](/bitrise-platform/infrastructure/build-machines/configuring-your-network-to-access-our-build-machines) - [Connecting to a VPN during a build](/bitrise-platform/integrations/connecting-to-a-vpn-during-a-build) ::: ### Adding an outgoing webhook to a Bitrise project You can set up and configure the webhooks sent by Bitrise on the web UI. Let’s see how! 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Integrations** and then select the **Webhooks** tab. 1. Scroll down to **Outgoing Webhooks**. 1. Click **Add webhook**. 1. Enter the URL of the service where you wish to send the notification in the **URL** field. ![add-outgoing-webhook.png](/img/_paligo/uuid-6c73acd6-91b0-2cf7-80bb-b0ef7e8b6618.png) 1. Select either the **Send me everything** or the **Select individual events** option. - **Send me everything**: every supported event type will trigger the webhook. Currently, only build events are supported but there will be other options in the future! - **Select individual events**: you can specify the individual events that should trigger the webhook. 1. Optionally, add custom headers to your webhook: in the **Headers** section, specify a name and a value for the header. When done, click **Add header**. For example, if you have an API listening to the webhook, you can track the requests with API keys set as a custom header. :::tip[Hiding the header value] You can hide the value of your headers by checking the box under **Hide**. Please note that if you do this, you won't be able to view or change the value again. ::: 1. Click **Create webhook**. And you’re done! You can modify your webhook at any time by clicking the pencil icon next to the webhook. If you created the webhook to use it for Release Management, check out the detailed guide: [Outgoing webhooks in Release Management](/release-management/releases/configuring-a-release/outgoing-webhooks-in-release-management). ### Adding custom headers to outgoing webhooks You can add extra headers to your outgoing webhooks via the **Webhooks** tab of the web interface. For example, if you have an API listening to the webhook, you can track the requests with API keys set as a custom header. You can add custom headers either when: - [Creating a new outgoing webhook](/bitrise-platform/integrations/webhooks/adding-outgoing-webhooks#adding-an-outgoing-webhook-to-a-bitrise-project). - Modifying an existing outgoing webhook by clicking the **Edit** button next to the URL. To add the header: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Integrations** and then go to the **Webhooks** tab. 1. In the **Outgoing webhooks** section, find your webhook and click the **Edit** button. ![edit-outgoing-webhook.png](/img/_paligo/uuid-73d46a9a-1191-00d2-578e-184d0bb3cb3d.png) 1. In the **Headers** section, add a key and a value. You need both to be able to save the header. 1. Click **Add header**. 1. Click **Update webhook**. ### Checking outgoing webhook deliveries You can check the recent deliveries of your outgoing webhooks at any time, and resend them if necessary. The deliveries are marked with appropriate status code, depending on whether the delivery was successful. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Integrations** and then the **Webhooks** tab. 1. Scroll down to **Outgoing Webhooks**. 1. Find your webhook and select the ![recent-deliveries.svg](/img/_paligo/uuid-78124fdc-5f54-e675-590c-e3b54a083649.svg) icon. 1. Select a delivery and expand it to show the full request and the response. ![webhooks-redeliver.png](/img/_paligo/uuid-b09fdf6d-9e83-e454-23c7-005f1344b4aa.png) 1. You can redeliver the webhook payload at any time. Find the delivery you need and click the ![redeliver.svg](/img/_paligo/uuid-f5c2904f-3e0b-71ae-b96a-b6059f61bed2.svg) icon next to it. :::tip[Editing the payload] Before trying to deliver the webhook payload again, you can edit the webhook configuration. Close the **Recent deliveries** pop-up window and click the ![edit-webhook.svg](/img/_paligo/uuid-fe3755f8-efba-2923-17e8-fa4ffd1ef16e.svg) icon next to the webhook to edit it. When finished, click **Update webhook**. ::: --- ## Webhooks overview A webhook is a user-defined callback that is triggered by some event, such as pushing code to a repository. Bitrise makes extensive use of webhooks: - Incoming webhooks, registered with your Git service provider, are used to [automatically trigger builds](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) on Bitrise and to enable the use of [Git Insights](/insights/git-insights). :::note[Webhook issues] If your builds triggers don't work, there might be a problem with your webhooks: [Builds aren't getting triggered](https://support.bitrise.io/hc/en-us/articles/360014238237). ::: - Outgoing webhooks are used to send reports of build events to other services, such as Slack. You can add an incoming webhook automatically either when creating an app or later; it’s also possible to manually add a webhook to any supported service. Outgoing webhooks can be added either on the website or [via the Bitrise API](/bitrise-ci/api/incoming-and-outgoing-webhooks). --- ## Mobile DevOps Platform Bitrise is a Mobile DevOps platform for every step of the mobile development process, from planning to monitoring. The platform equips mobile development teams with the necessary resources to build high-quality applications using their preferred tools, all while eliminating the interruptions and overhead that come with managing infrastructure and environments. Signing up and creating a workspace provides the basis for everything Bitrise offers: - [Bitrise CI](/bitrise-ci): Save time spent on testing, onboarding, and maintenance with automated workflows and triggers. - [Release Management](/release-management): Simplify distributing your iOS and Android apps to testers or directly to app stores—all from one platform, from the CI you choose. - [Build Cache](/bitrise-build-cache): A fully managed remote caching solution that reduces CI build and test durations for applications built with Gradle, Bazel, or Xcode, and for React Native projects. - [Insights](/insights): With Insights’ build, test, and credit data, know what to prioritize and optimize your CI/CD workflows. The platform documentation provides information on the shared structure of these products. This includes: - [Accounts](/bitrise-platform/accounts/accounts-overview): How to sign up for a Bitrise account and what options you have to manage them. - [Workspaces](/bitrise-platform/workspaces/workspaces-overview): Workspaces allow you to manage your projects and collaborate with team members. You need a workspace to run CI builds, to manage Release Management apps, or to utilize the Bitrise Build Cache. - [Projects](/bitrise-platform/projects/projects-overview): A Bitrise project can handle all stages of the Mobile DevOps process, including building, testing, and distributing mobile apps. - [Integrations](/bitrise-platform/integrations/about-integrations): Bitrise supports a number of integrations to make sure you can use your preferred tools and environments every step of the way. --- ## Changing the owner of a project Workspaces own projects. When you add a project to Bitrise, you select the workspace that will act as the owner of the project. From that point, only the owners of the workspace can change the ownership of the project. It can happen that you need to transfer a project on [Bitrise](https://www.bitrise.io) to another workspace. This can be done in two ways: - You can select the projects you want to transfer from the **Workspace settings** page's **Projects** menu. - Any given project can be transferred from the project's **Project settings** page. When transferring a project, its custom settings are also transferred. These include: - All Workflows and Pipelines. - Build triggers. - Environment Variables. - Build artifacts. Users on the project's team might lose their access in the event of a transfer. - Users of the project who are owners of the workspace that receives the project will retain access. - Contributors will be transferred and retain their access if the workspace that receives the project allows outside contributors. If the workspace doesn't allow outside contributors, they will lose their access. - Users belonging to groups listed on the **Groups** tab will lose their access to the project, as the groups belong to the workspace that previously owned the project. ### Transferring projects on the Workspace settings page :::important[Owners only] You must be an owner of the Workspace to transfer its projects to another Workspace. ::: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Projects** from the menu options. 1. Click the **Move project (↔)** button next to the project's name to select a project. :::note[Projects with outside contributors] When transferring projects with outside contributors to a Workspace that doesn't allow outside contributors, the existing contributors are automatically removed from the project's team. ::: 1. Select a user or Workspace to transfer the project to them. ![move-project.png](/img/_paligo/uuid-5aa8c4c0-1851-b6c3-810b-11ca0c3dda28.png) 1. Click **Move project** to finalize. :::warning[Transferring ownership is permanent] Only the new owner can change the project's ownership after the transfer has been completed! ::: ### Transferring a project on the Project settings page 1. Log in with an account that is an owner of the project. 1. Open the **Project settings** page. 1. Select **Basic settings** on the left and find the **Move or delete project** section. 1. Click the **Move project** button. ![move-project-button.png](/img/_paligo/uuid-2ce0bbbd-d455-1840-7b19-0bcfc6da8e12.png) 1. Select a Workspace to transfer the project to it. ![move-project-dialog.png](/img/_paligo/uuid-4c68fb66-ab5a-75a7-bb14-ab0f2617444f.png) 1. Click **Move project** to finalize. :::warning[Transferring ownership is permanent!] Only the new owner can change the project's ownership after the transfer has been completed! ::: --- ## Configuring the repository URL and the default branch When adding a new project to Bitrise, you specify a repository that is used to store your source code, and a branch that Bitrise uses as the default branch. Once the project is set up, you can change these at any time. ### Changing the repository URL The repository URL is the address where your repository can be accessed by Bitrise. It can be either an SSH URL or an HTTPS URL: we strongly recommend using SSH URLs for all private projects for security reasons. :::tip[Using an HTTPS URL] You can use HTTPS Git URLs, using a personal access token for authorization: in this case, you don't need an SSH key: [Configuring HTTPS authorization credentials](/bitrise-platform/repository-access/configuring-https-authorization-credentials). ::: If you move your project's repository, or the URL changes for any other reason, you can update it on Bitrise and continue building without an issue. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. From the menu on the left, select **Repository**. 1. On the **Repository URL** card, click **Change**. 1. Enter the new URL in the dialog. ![SCR-20260331-przw.png](/img/_paligo/uuid-fa95efd5-ff6f-a7a3-2dc3-7ccc5878cd47.png) 1. Click **Save** to save changes. ### Changing the default branch The default branch is the branch of your repository that Bitrise will use if no other configuration indicates otherwise. You can change the default branch at any time. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. From the menu on the left, select **Repository**. 1. On the **Repository URL** card, click **Change**. 1. In the dialog, enter the branch name in the **Default branch** field. ![SCR-20260331-przw.png](/img/_paligo/uuid-fa95efd5-ff6f-a7a3-2dc3-7ccc5878cd47.png) 1. Type the name of the branch you want to use as default branch. 1. Click **Save** to save changes. --- ## Creating white label app versions This guide explains how to create different versions of your white label project and build all or just one version by chaining Workflows and setting differences in [Environment Variables](/bitrise-ci/configure-builds/environment-variables). In this article, we’re building three individual versions (red, green, white) of our white label project. What you’ll need for this setup: - A main Workflow that launches each version-specific Workflow. - One or more version-specific Workflow(s) where you can set all the parameters that distinguish your versions from each other. - A utility Workflow which describes your build logic, and refers to the version-specific options as parameters. [Utility Workflows are Workflows that have an underscore before their Workflow ID](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#utility-workflows). Utility Workflows cannot be executed with the `bitrise_run` command: you need to reference them with the `before_run` or `after_run` properties. You can [chain utility Workflows with your regular Workflows](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#chaining-workflows-together) in the Workflow Editor. ### Prepping Workflows of a white label app 1. [Add your project](/bitrise-ci/getting-started/adding-a-new-project) to Bitrise in the usual way. 1. Select your project on the [Bitrise CI](https://app.bitrise.io/ci) page and click **Workflows**. ![getting-to-workflows.png](/img/_paligo/uuid-32b5ff3d-8431-8fe3-9971-89d8aca076f4.png) 1. Open the dropdown menu of available Workflows and click **Create Workflow** to create your main Workflow. ![create-workflow.png](/img/_paligo/uuid-426d42b4-ca6f-d5de-d91a-b9e8a4fd8ba1.png) 1. Add a new Workflow based on **An empty Workflow**. In this example, our main Workflow is called **allcolor**. This Workflow will start running your version-specific Workflows in the chain. 1. Click **+** again to create your version-specific Workflow. Keep adding as many Workflows as many different versions you wish to create. 1. Select **Env Vars** on the left navigation menu and add your version-specific parameters to each Workflow you’ve just created. In this example we’re adding Workflow Environment Variables to our **green**, **red** and **white** Workflows but leaving **allcolor** intact. ![env-ars-whitelabel.png](/img/_paligo/uuid-68837c3f-707c-19aa-86e2-bbac732be5a5.png) 1. Go back to **Workflows** and create a [utility Workflow](/bitrise-ci/workflows-and-pipelines/workflows/managing-workflows#utility-workflows). Make sure you give a name that starts with an underscore, for example, **_runner**, otherwise Bitrise CLI will not treat it as a utility Workflow. 1. Add Steps to your utility Workflow. In this example, we’re adding a **Script** Step which will inherit the Environment Variable from the Workflows and print out the value in the build log. ![script-param.png](/img/_paligo/uuid-52def735-231b-d0ea-e01e-b8b12cfbe86a.png) ### Chaining Workflows for a white label app Now that we have a bunch of Workflows ready, it’s time to chain them together in the right order. 1. Select your main Workflow (**allcolor** in this example). This is the Workflow that should be triggered by your [build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers). 1. Click **Chain Workflows** on the Workflow's card. Select a version Workflow (for example, **white**) and click **Add after**. 1. Add each version-specific Workflow the same way (such as white, green, and red in our example) and add your utility Workflow after each of them, as seen in this image: ![chained-workflows.png](/img/_paligo/uuid-dada2b23-2bc7-5796-3d98-9131dbaa2a87.png) 1. Go back to your Build’s page and click **Start build**. 1. In the **Start build** dialog, select your main Workflow under **Target**. This will kickstart your chained Workflows and build the app versions of your white label app. --- ## Embedding a project status badge You can embed a Bitrise status badge on your site and show visitors the state of your latest build. You can choose to display the status of any build, regardless of the repository branch it was built from, or you can select a specific branch. You can get the embed code from the **Project settings** page of the app, using a status image API token. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Builds**. 1. Scroll down to the **Build status badge** section and click **Get code**. ![build-status-badge.png](/img/_paligo/uuid-b2225b17-758e-9676-2e0a-615aebd28335.png) 1. Optionally, type a branch name in the **Branch** field. If you type a valid branch name, the status of builds from this branch will be shown. If you leave the field empty, the status of any build of the project will be shown. ![status-badge-dialog.png](/img/_paligo/uuid-a3ebc86e-b8db-eedf-bcff-64947885e344.png) 1. Choose the format of the embed code in the **Format** menu: you can choose between **Image URL** (a simple HTTPS URL to an image) or **Markdown**. 1. Copy the embed code from the **Embed** section. 1. Paste the code to your website. ### The status image API token The status image API token is a special token which can only be used for the status badge update. No other information can be retrieved with this token. It returns a simple JSON object. For example, if the latest build is successful: ```json { "status": "success" } ``` The possible status responses are: - `success`: If the last finished build was successful. - `error`: If the last finished build failed or was aborted. - `unknown`: In any other case, for example, if there was no finished build. --- ## Enabling the Bitrise Support user for your project In this article we describe how you can enable the **Bitrise Support Access** so that our Support team can have access to your project, specifically your Workflow, build log, project settings or your `bitrise.yml` file. With the toggle function, you can easily turn the **Bitrise Support Access** on and off. No need to add us as a user to your project's Team. The Bitrise Support user, when enabled, has Admin access to your project. That means it can do anything that a regular user with Admin access rights on a project can do: it has access to your builds and Workflows, to all the settings in the Workflow Editor and to the **Project settings** page. :::important[No access to billing information] The Bitrise Support user can’t see your **Account information** or any **Billing** information. Only the owner of the account has access to this information and has the right to modify any account-related records. The Support user can’t see your other projects where the Support user is not enabled. For details, see [What the Bitrise Support user can/can't do?](https://support.bitrise.io/hc/en-us/articles/4405741488017) ::: :::note[How long does the Bitrise Support Access remain active?] Due to security reasons once you toggle the Bitrise Support Access on, it will remain active for two weeks after which it automatically gets revoked. ::: Let’s see how to set it up! 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Basic settings** from the menu options. 1. Scroll down to the **Support access** section and toggle **Grant temporary access**. It might take a couple of seconds to work and you might need to refresh your page to see the enabled status. In case of a failing Workflow, our best practice is to create a new and correct version of the failing Workflow called `support-testing`. You can compare our `support-testing` with your own and update yours or keep the `support-testing` Workflow, rename it as you wish, and develop it further. --- ## Managing user access to a project Each Bitrise project is owned by a workspace - but this doesn't mean that all members belonging to that workspace have access to a given project. In order to be able to collaborate on a project, users must be assigned to the project. There are three ways to be invited to collaborate on a project: - [Adding outside contributors](#adding-an-outside-contributor-to-a-project). - [Adding one of the groups from the workspace that owns the project](#adding-workspace-groups-to-a-project). - [Assigning a workspace member to the project](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). This also allows to set [user roles](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) at the same time. Similarly, there are two ways to revoke access to a project: - [Revoking access from a group](#revoking-access-to-a-project-from-a-group). - [Revoking access from a user](#revoking-access-to-a-project-from-a-single-user). ### Adding an outside contributor to a project An outside contributor is a user who is assigned to a project but isn't [a member of the workspace](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration) that owns the project. To add outside contributors, your workspace must have them enabled. :::important[Admins and owners only] You need to be a project admin or a workspace owner to be able to add outside contributors to a project. ::: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. From the menu on the left, select **Collaboration**. 1. Go to the **Contributors** tab. ![2025-08-05-project-settings.png](/img/_paligo/uuid-63ec803d-7551-ebbb-ca47-b3915c746ea2.png) 1. Click **Add contributor**. 1. Select **Add outside contributor** 1. Type their email address and [select their role](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). If they are not registered on Bitrise, we will send out an invitation email for them. 1. Click **Next**. 1. Configure product access by enabling one or more toggles and then selecting a role in the dialog. You have the option to grant universal access or to set roles on a product basis: - **Admin access** allows the contributor to manage all aspects of the project, including both the Bitrise CI configuration and the Release Management apps. Note that this gives full access to an outside contributor! - Select a product to assign the contributor specific roles that only apply to that product. If the project doesn't have a [CI configuration](/bitrise-ci) or a [Release Management app](/release-management), the respective option won't be available. 1. Click **Confirm access**. ### Adding Workspace groups to a project Assigning a workspace group to a project means that all members of that workspace group will have the same role on the project. Roles are different based on product access: both [Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) and [Release Management](/release-management/configuring-connected-apps/release-management-roles-and-permissions) have their own roles. **An project consisting of workspace groups** Let’s say the workspace called *TestSpace* owns a project called *TestProject*. *TestOrg* has the following groups: - **Group Alpha**: they are assigned to *TestProject* with an **Admin** role. Members of this group can assign other groups to the project or add outside contributors, change project settings, manage roles and Workflows. - **Group Beta**: they are assigned to *TestProject* with a **Developer** role. Members of this group can run builds, view build logs and view builds. - **Group Gamma**: they are assigned to *TestProject* with a **Tester/QA** role. They can only view builds. There are two ways to assign workspace groups to a Bitrise project: - You can assign it from the **Collaboration** menu of the **Workspace settings** page. - You can assign it on the **Project settings** page of the project. #### Assigning a group from the Workspace settings page 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. ![workspace-settings.png](/img/_paligo/uuid-b9660c7d-79af-481d-c05a-17356619dd07.png) 1. On the left, select **Collaboration** then go to the **Groups** tab. 1. Choose the group you wish to assign, and click the options menu (⋮). ![2025-08-07-assign-group-from-workspace.png](/img/_paligo/uuid-42c797d6-13f2-d5b3-c183-c48546d78983.png) 1. Select **View details** and go to the **Projects** tab. 1. Click **Manage access**. 1. Configure product access by enabling one or more toggles and then selecting a role for your project in the dialog. You have the option to grant universal access or to set roles on a product basis: - **Admin access** allows the contributor to manage all aspects of the project, including both the Bitrise CI configuration and the Release Management apps. Note that this gives full access to an outside contributor! - Select a product to assign the group specific roles that only apply to that product. If the project doesn't have a [CI configuration](/bitrise-ci) or a [Release Management app](/release-management), the respective option won't be available. ![2025-08-07-access-in-rm-dialog.png](/img/_paligo/uuid-5b7fd557-dadc-4d73-eaa5-39119cd3b63f.png) :::tip[Role cheatsheets] You can check out the role cheatsheets here: . - [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) - [Release Management roles and permissions](/release-management/configuring-connected-apps/release-management-roles-and-permissions) ::: 1. Click **Save changes** to finalize changes. #### Assigning a group from the Project settings page 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. ![project-settings-button.png](/img/_paligo/uuid-14defaa4-472c-2d09-84df-145dc3aef4f5.png) 1. On the left, select **Collaboration**. 1. Go to the **Groups** tab. 1. Click on **Add group**. 1. In the dropdown menu, select the group you need then click **Next**. ![2025-08-07-add-group-to-project.png](/img/_paligo/uuid-4023a0e5-a889-7041-05ab-f31969f8e898.png) 1. Configure product access by enabling one or more toggles and then selecting a role in the dialog. You have the option to grant universal access or to set roles on a product basis: - **Admin access** allows the group members to manage all aspects of the project, including both the Bitrise CI configuration and the Release Management apps. - Select a product to assign the group specific roles that only apply to that product. If the project doesn't have a [CI configuration](/bitrise-ci) or a [Release Management app](/release-management), the respective option won't be available. 1. Click **Confirm access**. ### Revoking access to a project from a group 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. From the menu on the left, select **Collaboration**. 1. Go to the **Groups** tab. 1. Search for the group you would like to remove and click "![remove_png.png](/img/_paligo/uuid-ac29f14a-dd0f-9360-8e51-6bc1c83f724d.png)". ![remove-group.png](/img/_paligo/uuid-464e4d9f-1911-a722-1008-2b9f67b6bc5c.png) 1. Click **Remove** in the dialog to revoke the group's access from the project. ### Revoking access to a project from a single user 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. From the menu on the left, select **Collaboration**. 1. Go to the **Contributors** tab. 1. Find the user you would like to remove and click "![remove_png.png](/img/_paligo/uuid-ac29f14a-dd0f-9360-8e51-6bc1c83f724d.png)". ![remove-people.png](/img/_paligo/uuid-84805be3-7557-14df-e78e-44edaea87777.png) 1. Click **Remove** in the dialog. --- ## Projects overview [A Bitrise project](/bitrise-platform/projects/projects-overview) is the container for the entire Mobile DevOps process of your development work. Each workspace can own multiple projects. A project allows you to: - Create a CI configuration: a project's CI configuration is tied to a Git repository. - Set up Release Management to distribute your mobile app to testers and to online stores. Projects can add individual users and workspace groups as collaborators with granular access rights. Once you have access to a [workspace](/bitrise-platform/workspaces/workspaces-overview), you can start adding and managing projects. You can configure pretty much every aspect of your project at any time after the initial setup. Among other things, you can: - [Change your project's repository URL](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-repository-url). - [Setting up service credentials](/bitrise-platform/integrations/the-service-credential-user#changing-the-service-credential-user). - [Update your project's SSH keys](/bitrise-platform/repository-access/configuring-ssh-keys). - [Register new webhooks and update existing ones](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks). --- ## Public projects Open source projects are great - we all love them! They can be a pain to maintain, however, especially with CI/CD in the picture. That’s why we have introduced the Public projects feature for Bitrise: to make everyone’s life a lot easier! If your Bitrise project is public, anyone who has the build URL can see the build logs. For example, if the CI status check on GitHub fails on a pull request, anyone can click on the build URL and view the build logs. To create a public project, simply [add a new project](/bitrise-ci/getting-started/adding-a-new-project) to Bitrise. In the **Build settings** step, set the privacy of the project to **Public**. :::warning[Can't modify privacy later] You can't change this setting later! Once you've added an project as a public project, you can't set it back to private. You would have to add the project again. ::: When you have a public project, outside contributors can troubleshoot issues easier, find out why, for example, a pull request of theirs resulted in a failed build. They do not have to be invited to a Bitrise team to be able to view Bitrise logs and they do not need the help of a Bitrise team member, either. Of course, this does not mean anyone can do anything with your public project on Bitrise. If the user viewing the logs is not invited to work on the project in [some role](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci), they will only be able to: - View the [build logs](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/build-logs). - Download the build logs. - View [the build’s `bitrise.yml` file](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml). :::caution[Public project’s build logs are available for anyone] Remember: a public project’s build logs and `bitrise.yml` file can be seen by anyone - make sure these files do not expose anything you do not want to be seen! ::: --- ## Roles and permissions for Bitrise CI Roles provide access control on Bitrise: they limit what actions a user can and cannot perform on a Bitrise project. Bitrise CI has its own dedicated roles. :::note[Release Management] This page is about roles and permissions for Bitrise CI. Release Management has its own roles and permissions: the only role they share with Bitrise CI is that of the project admin. For more information, see [Release Management roles and permissions](/release-management/configuring-connected-apps/release-management-roles-and-permissions). ::: Roles work on a project basis: the same user can have different roles on different projects. You can also assign roles to [workspace groups](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups). The roles work the same way and each user within a group receives all permissions associated with the group's assigned role. There are four types of roles that you can assign to a user on a project's team: - [Admin](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci#admins) :::note[Full access to Release Management] A project admin has full access to both the project's Bitrise CI configuration and its Release Management apps, too! ::: - [Platform Engineer](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci#platform-engineers) - [Developer](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci#developers) - [Tester/QA](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci#testersqa) In addition, each project has Owners. ### Owners Bitrise projects are owned by Workspaces. On the project's team, users who are owners in the Workspace have the **owner** access right to the project. Owners have unlimited access to projects. Only owners can destroy projects or transfer the ownership of projects, and only they have access to payment information. ### Admins A project admin cannot delete a project but can invite other members to work on the project in two ways: - They can add workspace groups to the project team: [Adding Workspace groups to a project](/bitrise-platform/projects/managing-user-access-to-a-project#adding-workspace-groups-to-a-project). - They can invite outside contributors to the team: [Adding outside contributor to a project](/bitrise-platform/projects/managing-user-access-to-a-project#adding-an-outside-contributor-to-a-project). The admin can also give admin rights to other users. However, they cannot transfer ownership of the project: only Owners can do that. Admins are able to manage the project's contributors and their roles, including [Release Management](/release-management/configuring-connected-apps/release-management-roles-and-permissions) roles, such as Release Manager and App Tester. ### Platform Engineers Platform Engineers can do everything that Developers can, and in addition to that, they can also edit Workflows. They can't access the project settings, manage team members or billing, and they can't delete the project. ### Developers Developers cannot change team member roles, add new team members, remove existing team members or create, edit or delete Workflows. They can, however, run builds and view build logs. They have no access to sensitive data such as payment information, access tokens or even webhooks. ### Testers/QA Testers can only view builds. They cannot access build logs and they cannot modify the project in any way or form. They have no access to sensitive data such as payment information, access tokens or even webhooks. --- ## About repository access To run builds, Bitrise CI must be able to access a Git repository: when a build starts, we create a virtual machine and clone your repository on it, which requires authentication. Bitrise can authenticate to the Git repository in one of three ways: - [GitHub app](#github-app): Bitrise provides a GitHub app for both GitHub Cloud and GitHub Enterprise. - [SSH keys](#ssh-key-authorization): Create a public and private key, and register the public key at your Git provider, allowing Bitrise to authenticate when running builds. - [Personal access token](#https-authorization): Generate a personal access token at your Git provider and register it at Bitrise. You can use this for HTTPS authorization. You configure repository access when adding a new project but you can change every setting, including the authentication method and the repository URL itself, later. There are two ways to select a repository when [adding a new project](/bitrise-ci/getting-started/adding-a-new-project): - Manually pasting a repository URL. - Connect your Bitrise account to a Git provider account. This allows you to select from a list of available repositories when adding a new project. Selecting a repository URL is not final: you can always [change it later](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-repository-url). If you connect your Bitrise account to a Git provider account, authentication depends on the connection type: - The GitHub app uses short-lived access tokens and therefore doesn't require either an SSH key or a personal access token. - The OAuth connection requires either an SSH key or a personal access token, depending on the repository URL. ### GitHub app The best way to connect your Bitrise account to your GitHub repositories is by integrating with [a GitHub app](https://docs.github.com/en/apps/overview). The Bitrise GitHub app has a number of features that make integration easier: - The app eliminates the need for an SSH key, a Personal Access Token, and a service credential user. For access, it generates a temporary access token before every build, significantly increasing security. - It provides granular access to your repositories: no need to grant access to an entire GitHub organization, instead select the specific repositories the app can access. - With the app installed, you automatically receive Bitrise status updates directly on GitHub with the GitHub Checks app. No need for configuring status reports separately. Note that while only one GitHub account can be connected to a Bitrise Workspace, GitHub Checks can still be configured for repositories owned by other GitHub accounts. :::important[HTTPS URL required] The GitHub App requires an HTTPS URL for your repository instead of an SSH one. Normally, you don't have to worry about this: setting up the GitHub App connection changes the URL of your project. If there's an issue, you can change the URL manually: [Changing the repository URL](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-repository-url). ::: Repository access with the GitHub app is configured differently for GitHub Cloud and GitHub Enterprise users. - [GitHub Cloud guide](/bitrise-platform/repository-access/github-app-integration) - [GitHub Enterprise guide](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise) ### OAuth connection An OAuth connection allows a third-party application to access a user's data on a service without sharing their login credentials. On Bitrise, an OAuth connection means connecting your Bitrise account to your Git provider account. Bitrise supports an OAuth connection with three Git providers: GitHub, GitLab, and Bitbucket. With an OAuth connection, Bitrise can: - Retrieve and display a list of the available repositories when [adding a new project](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache#adding-a-new-connection-to-the-build-cache). - [Automatically register webhooks](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks#registering-an-incoming-webhook-automatically). Webhooks allow setting up build triggers and enable the use of [Git Insights](/insights/git-insights). - [Automatically register SSH keys](/bitrise-platform/repository-access/configuring-ssh-keys). To set up an OAuth connection, check out: [Repository access with OAuth](/bitrise-platform/repository-access/repository-access-with-oauth). ### SSH key authorization If your repository URL is an SSH URL and you use an OAuth connection, you can authorize Bitrise with SSH keys. SSH key authorization requires a public and private SSH key. The public key is registered to your Bitrise project's Git repository. Information encrypted with the public key requires the private key, registered at Bitrise, to be decrypted. You can add an SSH key pair when adding a new project on Bitrise or you can configure them later at the **Project settings** page. You have the option to: - **Auto-add a generated SSH key to your repository**: Bitrise automatically registers a public SSH key to your GitHub repository. Choose this if you have administrator rights to the repository. - **Copy a generated SSH key to your Git provider manually**: Bitrise generates an SSH keypair for you, and you have to manually register the public key to your Git repository. - **Add your own SSH key to Bitrise**: You provide your own SSH keypair for authentication, and you have to manually register the public key to your Git repository. Set up SSH key authorization: [Configuring SSH keys](/bitrise-platform/repository-access/configuring-ssh-keys). ### HTTPS authorization If your repository URL is an HTTPS URL and you use an OAuth connection, you can authorize Bitrise with a personal access token. HTTPS authorization requires a personal access token for private projects. You create the token at your Git provider and register it at Bitrise. For most projects with OAuth connection, we recommend SSH URLs and SSH key authorization. We recommend using HTTPS URLs only for [public projects](/bitrise-platform/projects/public-projects): those can't have SSH keys. Set up HTTPS authorization: [Configuring HTTPS authorization credentials](/bitrise-platform/repository-access/configuring-https-authorization-credentials). --- ## Apps with submodules or private repo dependencies :::note[GitHub App integration] If your project uses a GitHub App installation to connect to your repository, you can simply [link additional repositories](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app). You don't need any of the workarounds described in this document. ::: If you have a project with one or more submodules or other private repository dependencies (for example, CocoaPods repositories), Bitrise needs access to all repositories or submodules for a successful build. For private projects with OAuth connections, Bitrise uses SSH to access Git repositories: to grant access, you need to make sure all the repositories can be accessed with the public [SSH key generated](/bitrise-platform/repository-access/configuring-ssh-keys) for your Bitrise project. There are two ways to achieve this: - [Register the same SSH key](/bitrise-platform/repository-access/configuring-ssh-keys) for every repository you have to access during the build. - Register the SSH key with a bot user and add that user to all repositories. Registering the same SSH key for every repository is the best, most secure way - but not all services support it. GitLab and Bitbucket does support it, GitHub, however, doesn’t. If your code is stored on GitHub and you use an OAuth connection, read on! We’ll go through the other option, using a bot user or machine user - GitHub calls them machine users - in detail. In brief, the concept is simple: you register the Bitrise public SSH key to a user and add that user to all repositories that have to be accessed for your Bitrise build. :::note[Machine user with read only access] It is not required to use a special bot/machine user: you can add the SSH key to your own account on the git hosting service. The best practice, however, is to use a machine user, with read only access, for those repositories you want to access during the build. ::: [GitHub recommends this method](https://docs.github.com/en/developers/overview/managing-deploy-keys#machine-users) for accessing multiple repositories. Let’s quickly go through an example. **The MultiBit project** We have a Bitrise project we’ll call MultiBit. It has a main repository and it needs to pull additional data from two other, private repositories during a Bitrise build. Our main user is called BitMan and his GitHub account is linked to his Bitrise account. To access the private repositories during the build, BitMan creates another user on GitHub, called BitBot. BitBot will be the machine user. Now, BitMan accesses the **Project settings** page of his Bitrise project, and copies the public SSH key. BitMan then adds the SSH key to the BitBot user on GitHub and adds BitBot to the two private repositories as a collaborator. Now BitBot has the Bitrise public key and has access to the private repositories as necessary. It’s time to test if BitMan’s setup works. BitMan goes to Bitrise and opens the Workflow Editor. He has the **Activate SSH Key** Step in his repository so the SSH key will work. BitMan adds a [**Script**](https://github.com/bitrise-io/steps-script) Step to clone the private repositories - as the **Git Clone** Step only works with the main repository! Once all that is done, the build should work as expected. ### Using a machine user to access private repositories A [machine or bot user](https://docs.github.com/en/developers/overview/managing-deploy-keys#machine-users) is a GitHub user that is not used by humans, instead it is exclusively used for automation. This is the best way to access a private repository: you create a machine user, add a public SSH key to the user, and then provide the user read access to the repository. #### Adding the machine user to your repository 1. Create a new GitHub user account, one that will serve as the machine user. 1. Go to your repository on GitHub and select the **Settings** tab. 1. On the left side menu, select **Collaborators & teams**. ![Can_I_add_projects_with_submodules_or_with_private_repo_dependencies_.png](/img/_paligo/uuid-987a7495-6bb7-2c5e-0a19-6871b2ca8f1f.png) 1. Scroll down to the **Collaborators** window. 1. In the search input field, search for the username of your newly created account. 1. Click **Add Collaborator**. 1. Change the user permission to **Read**. By default, the invited collaborator’s permission is **Write**. You can keep it that way, of course, but a Read permission is enough for Bitrise. #### Adding the SSH key to the machine user In order for Bitrise to be able to use the machine user to access your repository, you must add the same SSH key to the machine user and the project on Bitrise. ##### When adding a new project 1. Start the process of [adding your project on Bitrise](/bitrise-ci/getting-started/adding-a-new-project). 1. When prompted to setup repository access, you can choose from three options: **Auto-add a generated SSH key to your repository**: Bitrise automatically registers a public SSH key to your GitHub repository. **Copy a generated SSH key to your Git provider manually**: Bitrise generates an SSH keypair for you, and you have to manually register the public key to your Git repository. **Add your own SSH key**: You provide your own SSH keypair for authentication, and you have to manually register the public key to your Git repository. 1. Finish the process. 1. Add the same SSH key to your machine user that you added to the project. ##### When your project already exists 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Repository**. 1. In the **Authorization** section, find the **Authorization method** card, and click **Copy public key**. ![SCR-20260401-pvvq.png](/img/_paligo/uuid-f021126a-47d0-41a9-56f7-79b9c8461a0e.png) 1. [Add it to your GitHub machine user](https://help.github.com/en/articles/adding-a-new-ssh-key-to-your-github-account). ### Git cloning submodules and repository dependencies You have three options when it comes to accessing multiple repositories during a Bitrise build: - Cloning all the repositories on the virtual machine, and accessing them as needed. - Adding the additional repositories as submodules to your main repository. - Using the [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) and [linking additional repositories](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app). In the latter case, you do not need to worry about cloning them: if you set up [SSH access](/bitrise-platform/repository-access/configuring-ssh-keys) correctly, the **Git Clone** Step will take care of everything. If you don’t want to or can’t add your repository dependencies as submodules, read on: we’ll talk about how to clone them. :::note[The Git Clone Step] The **Git Clone** Step only works with the main repository. If you need to access multiple private repositories, do not add multiple **Git Clone** Steps. Use **Script** Steps to clone those repositories on the Bitrise virtual machine. ::: To clone additional private repositories during the build: 1. Make sure you added a user with the Bitrise public SSH key to all the repositories. 1. Make sure you have the **Activate SSH Key** Step and the **Git Clone** Step at the start of your Workflow. 1. Add one or more **Script** Steps to clone the additional private repositories to the build. 1. Run a build. :::note[Cloning issues] If you encounter issues with git cloning - for example, not all submodules are cloned - try the following command after cloning: ```bash git submodule update –recursive –remote –merge –force ``` ::: #### Public vs private projects There is one important detail to keep in mind when you want to give access to all submodules or private repository dependencies for a Bitrise project: the project’s privacy settings determine what [git URL should you use](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-repository-url). - If you have a private project: use SSH URLs everywhere! Most services support SSH key based authentication only for SSH URLs (for example, `git@github.com:bitrise-io/bitrise.git`). Therefore every private repository you want to use have to be addressed with the SSH URL. If you have direct private git repo references in your CocoaPods Podfile, you’ll have to use the SSH URL there as well. The same applies for submodules and every other private git repository URL you want to use with [the SSH key you register](/bitrise-platform/repository-access/configuring-ssh-keys) on [bitrise.io](https://www.bitrise.io/). - If you have a public project: use HTTPS URLs everywhere! SSH URLs require SSH keys even if the repository is public. For security reasons, public projects CANNOT have SSH keys. As HTTPS git clone URLs do not require any authentication in the case of public repositories, they should be used for public Bitrise projects. --- ## Configuring HTTPS authorization credentials For private projects, you can authorize Bitrise to access your repository via an HTTPS URL, using a Personal Access Token. This is necessary for Bitrise to be able to clone your repository to the [virtual machine](/bitrise-platform/infrastructure/build-machines/about-build-machines) when starting a new build. You can set up authorization: - [When adding a new project](/bitrise-ci/getting-started/adding-a-new-project). - At any time on the **Project settings** page. To configure authorization for a repository with HTTPS URL on the **Project settings** page: 1. Create a Personal Access Token at your Git provider and save it. - [GitHub](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) - [Gitlab](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) - [Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/create-a-repository-access-token/) :::note[Fine-grained access] The Personal Access Token needs to have **read** access to the repository. We recommend using fine-grained Personal Access Tokens that do not have any additional rights to the repository or your Git provider account. ::: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. Make sure you have an HTTPS URL: on the left, select **Basic settings**, and find the **Repository URL**. 1. On the left, select **Repository**. 1. In the **Authorization** section, find the **Authorization method** card, and click **Add credentials**. ![SCR-20260331-prho.png](/img/_paligo/uuid-3de8dcba-e678-997e-20f0-3055cd889bb0.png) 1. In the dialog, add the Personal Access Token. :::note[Bitbucket username] If your repository is on Bitbucket, you'll also have to provide your Bitbucket username. ::: ![change-https-credentials.png](/img/_paligo/uuid-c1bacf0c-d211-9674-a2d6-625665e9b381.png) 1. Once done, click **Save changes**. --- ## Configuring SSH keys SSH keys are the primary method of authentication. To access your project's repository, Bitrise needs a public-private SSH keypair, with the public key registered to your project's Git repository. There is one exception to this: if you use the [Bitrise GitHub App](/bitrise-platform/repository-access/github-app-integration) to connect your Bitrise Workspace to GitHub, you do not need an SSH key. :::tip[Using an HTTPS URL] You can use HTTPS Git URLs, using a personal access token for authorization: in this case, you don't need an SSH key: [Configuring HTTPS authorization credentials](/bitrise-platform/repository-access/configuring-https-authorization-credentials). ::: You can add an SSH key when you first add a project to Bitrise but you can update your keys at any point. You can even skip SSH key configuration when adding the project and register SSH keys later. :::tip[Accessing multiple repositories] If your project needs to access multiple repositories during the build, the best practice is to generate an SSH keypair, and register the public key to every repository you need. Alternatively, you can create a machine user and register the SSH key to that user. To learn more, see [Apps with submodules or private repo dependencies](/bitrise-platform/repository-access/apps-with-submodules-or-private-repo-dependencies). ::: ### Generating your own SSH keypair You can always generate your own SSH keypair on your own device and use the generated public and private keys for your Bitrise project. This is completely optional as Bitrise can generate and automatically register SSH keys for you, either during the process of adding the project to Bitrise or later in the **Project settings** menu. Generate your own SSH keypair with a simple Command Line/Terminal command: ```bash ssh-keygen -t rsa -b 4096 -P '' -f ./bitrise-ssh -m PEM ``` This generates two files in the current directory (the directory where you run the command): - `bitrise-ssh` (private key) - `bitrise-ssh.pub` (public key) Copy and paste the **public key** to your Git hosting service (for example, GitHub), and when you add your project on [bitrise.io](https://www.bitrise.io), you’ll have to provide the **private key**. ### Configuring SSH keys for your Bitrise project To configure SSH keys on [bitrise.io](https://www.bitrise.io/): 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Repository**. 1. Find the **Authorization** section and the **Authorization method** card. 1. Next to the SSH key, click **Replace**. If you haven't had an SSH key added before, the button will show **Add SSH key** instead. ![SCR-20260401-pvvq.png](/img/_paligo/uuid-f021126a-47d0-41a9-56f7-79b9c8461a0e.png) 1. Choose from one of three options: **Auto-add a generated SSH key to your repository**: Bitrise automatically registers a public SSH key to your GitHub repository. Choose this if you have administrator rights to the repository. **Copy a generated SSH key to your Git provider manually**: Bitrise generates an SSH keypair for you, and you have to manually register the public key to your Git repository. **Add your own SSH key**: You provide your own SSH keypair for authentication, and you have to manually register the public key to your Git repository. 1. Click **Auto-add SSH key** if you chose the auto-add option, or **Save changes** for the other two options. --- ## Connecting Bitbucket Server instances Connect your Bitrise workspace to Bitbucket Server to access your privately hosted repositories for CI builds. You need to: - Create a new Application Link on your server. - Authorize Bitrise and assign the required permissions. - Copy the necessary credentials to your workspace settings. 1. Log in to your Bitbucket Server instance with **admin** privileges. 1. Click the settings icon on the top menu bar to access **Administration**. 1. On the left menu bar, find the Integrations section, and select **Application Links**. 1. Click **Create link**. ![2025-11-13-bitbucket-app-links.png](/img/_paligo/uuid-f87af39b-bb44-1167-0051-389e3b38c612.png) 1. Select **External Application**, and **Incoming** as the direction. 1. In the Name field, enter a name that clearly identifies the application. For the sake of simplicity, we recommend **Bitrise**. 1. In the **Redirect URI** field, enter https://app.bitrise.io/users/auth/bitbucket_server/callback. 1. Under **Application permissions**, find **Repositories** and select **Admin**. 1. Click **Save**. You will be taken to the **Credentials** page. ![20251113-bitbucket-credentials.png](/img/_paligo/uuid-dbf18dae-38c9-f32a-fb61-6afbb08edb2f.png) 1. Copy the **Client ID** and the **Client secret**. 1. Open the **Workspace settings** page on Bitrise and select **Integrations**. 1. Select **Bitbucket Server** and then click **Add credentials**. ![2025-11-13-bitbucket-server-integration.png](/img/_paligo/uuid-6657cf32-779e-915b-aaea-453f88b28ec8.png) 1. Add your credentials: - **App ID**: The Client ID you copied from Bitbucket Server - **Secret**: The Client secret you copied from Bitbucket Server - **URL**: Your server's base URL --- ## Connecting self-hosted GitLab instances For Workspaces, Bitrise supports connecting to self-hosted GitLab instances. Connecting is simple, and once it’s done, you can add projects to Bitrise from privately hosted repositories. All functions that you got used to with publicly hosted repositories will be available! Bitrise needs to be authorized as an application for the entire GitLab instance and then the **Application Id** and the **Secret** value belonging to the Bitrise OAuth application must be added to the Workspace on [bitrise.io](https://www.bitrise.io). ### Configuring the GitLab connection To access privately hosted GitLab repositories on Bitrise, you need to create a new OAuth application on your GitLab account, and assign the appropriate credentials to access your server. :::warning When you create a new Bitrise project, you must pick the dedicated **GitLab Self-hosted** option in the provider picker. If you paste your repository URL into the **Other** field instead, Bitrise will save the project as a generic Custom-provider repository, and the following features will be silently unavailable: - The [Service Credential User](/bitrise-platform/integrations/the-service-credential-user) UI in App Settings. - The [Store bitrise.yml in repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository) option. - Build status reporting back to GitLab merge requests. This cannot be fixed by editing the repository URL afterwards. If you have already created the project this way, contact support to have the provider type corrected. ::: :::warning[Publicly resolvable IP address] Your self-hosted instance must have a publicly resolvable IP address, otherwise Bitrise won’t be able to connect to it. ::: The connection requires two URLs: a Bitrise OAuth callback URL and a **GitLab instance** URL: | URL | Where it goes | Example | | --- | --- | --- | | Bitrise's OAuth callback URL | In GitLab, in the OAuth application's **Callback URL** field | `https://app.bitrise.io/users/auth/gitlab/callback` | | Your GitLab instance URL | In Bitrise, in the Workspace Integrations **GitLab instance URL** field | `https://gitlab.example.com` | 1. Allowlist the Bitrise backend workers for your GitLab instance: [Configuring your network to access our build machines](/bitrise-platform/infrastructure/build-machines/configuring-your-network-to-access-our-build-machines). Be aware that the Bitrise backend workers that power, among other things, app.bitrise.io and the Bitrise build machines have a different IP address range. Allowlisting the build machines is not sufficient for this feature. If allowlisting the backend workers is not an option for you, [reach out to Bitrise](https://www.bitrise.io/contact) so we can discuss other options. 1. Log in to your GitLab instance with **root** privileges. If you connect to Bitrise **without root privileges**, your Workspace’s other team members will **not have access to the repository on the GitLab instance**. 1. Go to the admin area by clicking the little wrench icon on the top menu bar. 1. On the left menu bar, select **Applications**, then click **New Application**. ![New_Application.png](/img/_paligo/uuid-c139a2c3-3f9a-980e-41f0-a85bc3ea6bbb.png) 1. In the **Name** field, enter a name that clearly identifies the application. For the sake of simplicity, we recommend `Bitrise`. 1. In the **Callback URL** field, enter `https://app.bitrise.io/users/auth/gitlab/callback`. This is Bitrise's URL. GitLab will redirect users here after they authenticate. 1. In the **Scopes** menu, check **api**. ![New_Application_settings.png](/img/_paligo/uuid-9e8a91b7-c03a-f513-62a7-0e91426f1676.png) 1. Set the **Confidential** option to **No**. If the newly created app is configured to be confidential, Bitrise won't be able to access it! 1. Click **Submit**. On the next page, you should find the **Application Id** and a **Secret**. You’ll need both to connect to your GitLab instance on [bitrise.io](https://www.bitrise.io). ![Connecting_self-hosted_GitLab_instances.png](/img/_paligo/uuid-94e2570d-ce4b-720a-db91-52b46de0a96a.png) 1. Log in to Bitrise and select your workspace. 1. On the left, select **Integrations**. 1. Find the **GitLab self-managed** section. 1. Click **Add credentials** and add your self-hosted GitLab credentials: - **App ID** - **Secret** - **GitLab instance URL** This is your GitLab instance's URL (for example, https://gitlab.example.com). It is not the same as the Bitrise callback URL that you pasted in the GitLab instance configuration! :::note Optionally, you can add custom HTTP headers: [Connecting through a proxy](/bitrise-platform/repository-access/connecting-self-hosted-gitlab-instances#connecting-through-a-proxy). ::: You are done! Now you are able to access your privately hosted repositories with Bitrise. ### Service credential user role Bitrise uses [a Service Credential User (SCU)](/bitrise-platform/integrations/the-service-credential-user) on your GitLab instance to register webhooks, post commit statuses on merge requests, and read repository contents. On self-hosted GitLab, the SCU needs **Maintainer** role on the repository at minimum: | GitLab operation | Required role | | --- | --- | | Read `bitrise.yml`, list branches | Reporter | | Register webhook | Maintainer | | Post commit / merge request status | Maintainer | Reporter or Developer is not sufficient. Status reporting will silently fail. See [The service credential user](/bitrise-platform/integrations/the-service-credential-user) for the full SCU configuration flow. ### Connecting through a proxy You can add custom HTTP headers to your self-hosted GitLab instance to be able to connect through a proxy. The header values are stored encrypted. To add a custom HTTP header, go to the **Workspace settings** page and select **Integrations**. Find the **GitLab self-managed** card and you can edit your credentials there. For example, Cloudflare Access customers can set their client ID and client secret: `CF-Access-Client-Id` and `CF-Access-Client-Secret`. ### Adding a new project from a self-hosted GitLab repository 1. Start the process of [adding a new project](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache#adding-a-new-connection-to-the-build-cache). 1. When prompted to select your Git provider, select the **Self-hosted GitLab** option. 1. Click **Connect**. Once connected, proceed as usual: [Adding your first project](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache#adding-a-new-connection-to-the-build-cache). --- ## GitHub app integration :::important[Supported for GitHub Cloud users] The Bitrise GitHub app is supported for all GitHub Cloud users. GitHub Enterprise Server users need to create and install a different GitHub app, as described in our [GH Enterprise integration guide](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise). ::: The best way to connect your Bitrise account to your GitHub repositories is by integrating with [a GitHub app](https://docs.github.com/en/apps/overview). The Bitrise GitHub app has a number of features that make integration easier: - The app eliminates the need for an SSH key, a Personal Access Token, and a service credential user. For access, it generates a temporary access token before every build, significantly increasing security. - It provides granular access to your repositories: no need to grant access to an entire GitHub organization, instead select the specific repositories the app can access. - With the app installed, you automatically receive Bitrise status updates directly on GitHub with the GitHub Checks app. No need for configuring status reports separately. Note that while only one GitHub account can be connected to a Bitrise Workspace, GitHub Checks can still be configured for repositories owned by other GitHub accounts. :::important[HTTPS URL required] The GitHub App requires an HTTPS URL for your repository instead of an SSH one. Normally, you don't have to worry about this: setting up the GitHub App connection changes the URL of your project. If there's an issue, you can change the URL manually: [Changing the repository URL](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-repository-url). ::: ### Event subscriptions When you install the Bitrise GitHub App on a repository or organization, GitHub automatically registers event subscriptions for that installation. These are separate from the repo-level webhooks you can configure manually in GitHub's repository settings. The Bitrise GitHub App subscribes to the following events: - `push`: triggers builds on branch pushes and tag pushes. - `pull_request`: triggers builds when a pull request is opened, updated, or synchronized. - `issue_comment`: enables comment-based build triggers on pull requests. These subscriptions are managed by GitHub at the app installation level. They do not appear as webhooks under **Settings → Webhooks** in your GitHub repository. :::warning[Remove manual webhooks after switching to the GitHub App] If your repository also has manually configured webhooks pointing to `hooks.bitrise.io` — for example, from a previous OAuth-based Bitrise connection — each qualifying event will trigger two builds: one from the GitHub App subscription and one from the manual webhook. After switching to the GitHub App, remove any manual Bitrise webhooks from your repository's **Settings → Webhooks** page on GitHub to avoid duplicate builds. ::: ### Installing the GitHub app integration This guide is intended for GitHub Cloud users, including GitHub Enterprise Cloud users, who wish to install the Bitrise GitHub app and connect their Bitrise Workspace to a GitHub account or organization with the app. For GitHub Enterprise Server users, we have a separate guide: [Integrating GitHub Enterprise with Bitrise](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise) You can connect via the GitHub app integration in two ways: - From the **Workspace settings** page. - When adding a new Bitrise project. :::important[GitHub App installations per Workspace] Note that: - A maximum of ten GitHub app installations can be connected to a Workspace. - A GitHub app installation cannot be connected to multiple Workspaces. - The GitHub Checks functionality of the app is available for repositories owned by other GitHub accounts. ::: #### Connecting a GitHub app from the Workspace settings page A Bitrise GitHub app installation is tied to a Workspace. You can always install and check its connection from the **Workspace settings** page. :::note[SSO on GitHub] If you install the GitHub App integration for a GitHub organization that requires SAML SSO, you need to have an active SAML SSO session on GitHub to be able to connect to the organization's repositories. If your installed GitHub app can't access all repositories it should, you might to need to revoke the app and authorize it again on GitHub while you have an active SAML SSO session. For more information and the detailed procedure, [check GitHub's documentation](https://docs.github.com/en/enterprise-cloud@latest/apps/using-github-apps/saml-and-github-apps). ::: 1. On the Bitrise main page, select your Workspace from the dropdown menu. 1. From the navigation menu on the left, select **Settings**. 1. On the **Workspace settings** page, select **Integrations**. 1. Select **GitHub** and click **Connect**. ![github-account-connection.png](/img/_paligo/uuid-1b49695a-ea36-fe03-f9a1-48a6bfc9a737.png) 1. If you haven't authorized the Bitrise GitHub app before, you will be prompted for authorization at this point. 1. You will be prompted to select the GitHub account or organization you want to connect. If you don't find the one you need in the list, you need to install the App to that account or organization first: click the link below the list of accounts. ![install-the-app.png](/img/_paligo/uuid-cae94617-17e3-33ce-8cf7-99205e85bd22.png) 1. Once you click the link, you will be prompted to select an account or organization. After selecting one, you will be transferred to the **Install & Authorize** page. 1. On the **Install & Authorize** page, select the access type: - **All repositories**: the Bitrise GitHub App will have access to all repositories belonging to the account or organization, including future ones. - **Only select repositories**: Select one or more repositories that Bitrise will be able to access. You can add more later but to do so, you will need to reconfigure your repository access on the GitHub App's page. ![authorizing-app.png](/img/_paligo/uuid-a25560d9-ce2a-4181-2dc6-59cc4318c577.png) 1. When done, click **Install & Authorize**. You will be redirected to the **Workspace settings** page. :::important[Authorization] If you are not authorized on GitHub to install the app, you can still request the installation. Once a GitHub Admin approves the installation, you can come back and select the **App installation** from the list. ::: 1. If you have existing apps with OAuth connection, we recommend [switching them over to the GitHub App connection](/bitrise-platform/repository-access/github-app-integration#switching-from-oauth-connection-to-the-github-app). #### Connecting a GitHub app when adding a new project :::note[SSO on GitHub] If you install the GitHub App integration for a GitHub organization that requires SAML SSO, you need to have an active SAML SSO session on GitHub to be able to connect to the organization's repositories. If your installed GitHub app can't access all repositories it should, you might to need to revoke the app and authorize it again on GitHub while you have an active SAML SSO session. For more information and the detailed procedure, [check GitHub's documentation](https://docs.github.com/en/enterprise-cloud@latest/apps/using-github-apps/saml-and-github-apps). ::: During the process of [adding a new project](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache#adding-a-new-connection-to-the-build-cache) on Bitrise, you have to select how Bitrise can access your repository. This process allows connecting the project via the GitHub app. 1. Start the process of [adding a new project](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache#adding-a-new-connection-to-the-build-cache). 1. At the **Select a repository** section, select **GitHub App (recommended)** from the **Provider** dropdown menu. ![select-repository.png](/img/_paligo/uuid-5fa460a4-aa40-627b-9ccd-d820ef1af5db.png) 1. Click **Connect account**. ![connect-github-app.png](/img/_paligo/uuid-bbcc5c35-f82c-f026-b5a7-92bb3040d6da.png) 1. You will be prompted to select the GitHub account or organization you want to connect. If you don't find the one you need in the list, you need to install the App to that account or organization first: click the link below the list of accounts. ![install-the-app.png](/img/_paligo/uuid-cae94617-17e3-33ce-8cf7-99205e85bd22.png) 1. Once you click the link, you will be prompted to select an account or organization. After selecting one, you will be transferred to the **Install & Authorize** page. 1. On the **Install & Authorize** page, select the access type: - **All repositories**: the Bitrise GitHub App will have access to all repositories belonging to the account or organization, including future ones. - **Only select repositories**: Select one or more repositories that Bitrise will be able to access. You can add more later but to do so, you will need to reconfigure your repository access on the GitHub App's page. ![authorizing-app.png](/img/_paligo/uuid-a25560d9-ce2a-4181-2dc6-59cc4318c577.png) 1. When done, click **Install & Authorize**. You will be redirected to continue adding your new Bitrise project. :::note[Connecting multiple GitHub organizations to a Bitrise workspace] If you wish your builds to access code that is stored in different GitHub organizations/accounts from your main source code, you can connect multiple GitHub orgs to your Bitrise Workspace using the **+ Add GitHub account**button. On the **GitHub** app page of your Workspace, Project Admins, who have installed the Bitrise GitHub app, can find the **+ Add GitHub account** button. This way they can connect up to **10 GitHub accounts/orgs** to their workspace. ![multipleGithuborgs.png](/img/_paligo/uuid-6986251f-485b-cef8-01b9-c6110f4e4e4f.png) ::: ### Extending GitHub app permissions to the builds :::tip[Using the API] This section describes how to configure the feature on the Bitrise website. You can also configure it via the Bitrise API: [GitHub app configuration API](/bitrise-ci/api/github-app-configuration-api). ::: The Bitrise GitHub app generates a short-term, temporary token for each build that is triggered via the app. This token has only one permission by default: `content:read`. This means the build can access the GitHub repository but can't do anything else. You can extend these permissions so that you can perform other operations during a build. For example, this can enable users to push Git tags from their builds, create custom status reports, put a label on a pull request, or push a new version number. :::important[Linked repositories] When extending permissions, you extend permissions to all [additional linked repositories](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app) as well! ::: The exact permissions you can extend depends on your GitHub account: - On GitHub Cloud, the GitHub app has the following permissions: - Read access to issues and metadata - Read and write access to checks, code, commit statuses, and pull requests - [GitHub Enterprise Server](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise) users define their GitHub app permissions when creating the app. To extend the permissions: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. Select **Repository** from the menu. 1. Find the **Extend GitHub App permissions to builds** option and toggle it on. This extends permissions to the default repository and all additional linked repositories, too. ### Additional linked repositories via a GitHub App :::tip[Using the API] This section describes how to configure the feature on the Bitrise website. You can also configure it via the Bitrise API: [GitHub app configuration API](/bitrise-ci/api/github-app-configuration-api). ::: Each Bitrise project has a primary Git repository. This is where your project's code is stored and this repository is cloned when we start a build. By default, a Bitrise project can't access other repositories. However, your project might require other repositories. For example, it might have private submodules that it must access during a build. If you use the GitHub App, you can do this via linking additional repositories. The feature is available on both GitHub Cloud and GitHub Enterprise Server. :::note[Other connection methods] If you are not using the Bitrise GitHub App, you can still configure access to additional repositories: [Apps with submodules or private repo dependencies](/bitrise-platform/repository-access/apps-with-submodules-or-private-repo-dependencies). ::: A linked repository is a repository that a Bitrise project can access using a GitHub App installation but it's not the project's primary repository. When running a build of a project connected via a GitHub App installation, Bitrise generates a temporary token that, by default, can only access the primary repository. Once an additional repository is linked, the tokens generated for the build can access the additional repository. To be able to link a repository, all of the following conditions must be met: - The GitHub App is installed to the account or organization that owns the repository on GitHub. - The app installation is enabled for the repository. - The user attempting to link the repository can access the repository on GitHub. If your GitHub user account doesn't have access to a repository, you can't link it on Bitrise. :::note[GitHub Enterprise Server] If you use a GitHub App to connect to a [GitHub Enterprise Server](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise) instance, the app doesn't check user access. You can link any repository that your GitHub App has access to. ::: #### Linking additional repositories To link additional repositories to a project with an established GitHub App connection: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left, select **Repository**. 1. Under **Authorization**, find the **Additional repositories** card and click **Change**. 1. In the **Link additional repositories** dialog, select the repositories you want to link. ![SCR-20260331-pmhi.png](/img/_paligo/uuid-324a0ec5-3e09-e10f-9e9e-7ae1359ffdc2.png) You can link a maximum of 50 additional repositories. You will see a list of repositories. To see a repository on the list: - On GitHub Cloud, your GitHub user needs to have access to it. If you use [GitHub Enterprise Server](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise), user permissions are not checked. - The GitHub App installation has access to it. :::important[Disabling repositories] If you already have repositories linked, please note that users who otherwise don't have access to those repositories can disable them but cannot add them back! ::: 1. When done, click **Save changes**. #### Linking all repositories automatically GitHub organization owners can switch the **Grant access to all current and future repositories** toggle so that Bitrise builds can have access to every GitHub repository your GitHub App is allowed to access, including any new repositories added in future. To successfully use this functionality: - For security reasons, you have to be logged in as a Bitrise user who is also the GitHub **owner** of your organization. If you aren't the owner, ask the owner to log in to Bitrise and toggle the feature on. - Make sure you configured the GitHub App to have access to necessary repositories. 1. On Bitrise, go to the **Project Settings** page of your project. 1. On the left, select **Repository**. 1. Under **Authorization**, find **Additional repositories** and click **Change**. 1. Toggle the **Grant access to all current and future repositories** switch to the right. ![linkadditionalrepositories.png](/img/_paligo/uuid-bfc425a6-84a8-0672-31bb-d3d7b07b56ce.png) Your project's build will now have access to all current and future GitHub repositories the Bitrise GitHub App has access to. :::note[GitHub email notification about allowing permission] When Bitrise released this feature, Bitrise GitHub App users will have received an email from GitHub on a new permission which is needed to use the Grant access to all current and future repositories toggle. Bitrise GitHub App requests additional permission which is called: read organization membership. Only GitHub organization ownershave the necessary rights to follow the link in the email and to make this functionality available for their teams. This is a standard and legitimate message from GitHub and allowing this permission will not have any detrimental effect on Bitrise builds. You can read more about the new permission Bitrise requires [here](https://docs.github.com/en/rest/orgs/members?apiVersion=2022-11-28#get-organization-membership-for-a-user). ::: ### Using a private Step library via the GitHub App Each Bitrise project has a default Step library: a repository of Steps. If the exact source of a Step is not specified in the configuration, the Bitrise CLI pulls the Step data from the default library. This library can be a private Step library. To access such a library via the GitHub App, you need to add the **[Authenticate host with netrc](https://bitrise.io/integrations/steps/authenticate-host-with-netrc)** Step as the very first Step which will run in your Workflow: ```yaml format_version: "13" default_step_lib_source: https://github.com/my-private-org/my-bitrise-steplib.git project_type: ios workflows: example: steps: - https://github.com/bitrise-io/bitrise-steplib.git::authenticate-host-with-netrc@0: ``` Note that the **[Authenticate host with netrc](https://bitrise.io/integrations/steps/authenticate-host-with-netrc)** Step has [a full source identifier](/bitrise-ci/references/steps-reference/step-reference-id-format) to ensure it is pulled from the official Bitrise Step library, not your private library. Using the Step requires specifying three inputs: the host, the Git username, and the Git password. The Bitrise GitHub App integration uses token-based authentication: each build receives a one time token under the GIT_HTTP_PASSWORD Environment Variable. This Env Var can be used as the password. The username can't be empty because the Step will fail but it is not used so it doesn't matter what you put there. ```yaml format_version: '13' default_step_lib_source: https://github.com/tothszabi/steplib.git project_type: ios workflows: example: steps: - https://github.com/bitrise-io/bitrise-steplib.git::authenticate-host-with-netrc@0: inputs: - host: github.com - username: username - password: "$GIT_HTTP_PASSWORD" - private-script@1: {} ``` ### Running git clone with linked repositories If you attempt to run `git clone` or other git commands for a [linked repository](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app), your build might fail with an authentication error. This is because the authentication credentials are stored in a local `netrc` file. This file is automatically generated by the official **Git Clone** Step. However, if you use your own script to perform `git clone`, or you use any other Git command requiring authentication before the **Git Clone** Step, you need to create the `netrc` file. You have two ways: - You can do it manually. - You can use the **[Authenticate host with netrc](https://bitrise.io/integrations/steps/authenticate-host-with-netrc)** Step. It should be the first Step of your Workflow. :::important[HTTP URLs] Make sure you always use HTTP URLs when cloning private repository dependencies. ::: Using the Step requires specifying three inputs: the host, the Git username, and the Git password. The Bitrise GitHub App integration uses token-based authentication: each build receives a one time token under the GIT_HTTP_PASSWORD Environment Variable. This Env Var can be used as the password. The username can't be empty because the Step will fail but it is not used so it doesn't matter what you put there. ```yaml workflows: example: steps: - authenticate-host-with-netrc@0: inputs: - host: github.com - username: "username" - password: "$GIT_HTTP_PASSWORD" ``` ### Switching from OAuth connection to the GitHub app :::tip[Using the API] This section describes how to configure the feature on the Bitrise website. You can also configure it via the Bitrise API: [GitHub app configuration API](/bitrise-ci/api/github-app-configuration-api). ::: If your Bitrise project has an OAuth connection set up to your GitHub account, you can change it to the Bitrise GitHub app at any time without losing any functionality. We strongly recommend doing the switch: with the Bitrise GitHub app installed, you no longer need the service credential user, an SSH key, or a webhook to run Bitrise builds. :::important[HTTPS URL required] Please note that the GitHub app requires an HTTPS URL for your repository instead of an SSH one. Normally, you don't have to worry about this: setting up the GitHub app connection changes the URL of your project. If there's an issue, you can change the URL manually: [Changing the repository URL](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-repository-url). ::: To switch: 1. Install the Bitrise GitHub App as described in the relevant guide: [Installing the GitHub App integration](/bitrise-platform/repository-access/github-app-integration#installing-the-github-app-integration). 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. ![project-settings-button.png](/img/_paligo/uuid-14defaa4-472c-2d09-84df-145dc3aef4f5.png) 1. On the left navigation menu, select **Repository**. 1. You can see a blue card with information about GitHub App support. To switch, click **Setup GitHub App**. ![SCR-20260331-prho.png](/img/_paligo/uuid-3de8dcba-e678-997e-20f0-3055cd889bb0.png) 1. Make sure you remove any pre-existing manual Webhooks from the **Incoming Webhooks** page of the **Webhooks** tab once the GitHub App is configured. You can get to this page via **Project Settings** → **Integrations** → **Webhooks** tab → **Incoming Webhooks**. If you fail to do this, duplicate builds will get triggered. For more information, see [Event subscriptions](/bitrise-platform/repository-access/github-app-integration#event-subscriptions). 1. Optionally, you can remove the service credential user and any SSH keys or personal access tokens used for OAuth connection. ### Reverting back to OAuth connection If you used an OAuth connection for repository access before switching to the GitHub app, you can revert back to it at any time. :::note The OAuth connection requires an SSH key or a personal access token at the Git provider, depending on the authorization method. When switching to the GitHub app, you don't have to remove these: if you didn't, you can use them when reverting to the OAuth connection. ::: 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. Under **Bitrise CI**, select **Integrations** and then the **Git provider** tab. 1. Find the **Connection type** card and click **Change**. 1. In the dialog, select **OAuth** and click **Change**. --- ## Integrating GitHub Enterprise with Bitrise Bitrise offers an integration for self-hosted GitHub Enterprise Server (GHES) instances. The main benefit of the integration is that self-hosted GHES users can [store the `bitrise.yml` file in their repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository). Storing the file in the repository allows for full version control and maintenance of your configuration file. ### About the GitHub Enterprise Server integration :::important[Enterprise Server users only] This guide is for GitHub Enterprise Server users. For GitHub Cloud users who wish to use the Bitrise GitHub App to connect to Bitrise, we have a separate guide: [GitHub app integration](/bitrise-platform/repository-access/github-app-integration). ::: The feature requires: - A Bitrise [Workspace owner](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration) to configure the integration. - [A GHES organization owner](https://docs.github.com/en/enterprise-server@3.11/organizations/managing-peoples-access-to-your-organization-with-roles/roles-in-an-organization) with sufficient permissions to create a GitHub app on GHES and then install it for selected repositories. - Access to the GHES instance. If the Bitrise website cannot access your repository on GHES, it can't use the `bitrise.yml` file stored there. If you have IP address access control lists for security purposes, you need [to allowlist the Bitrise website](/bitrise-platform/infrastructure/build-machines/configuring-your-network-to-access-our-build-machines#ip-address-ranges-for-bitrise-backend-workers). :::important[Allowlisting the Bitrise background workers] Be aware that the Bitrise background workers that power, among other things, app.bitrise.io and the Bitrise build machines have a different IP address range. Allowlisting the build machines is not sufficient for this feature. If allowlisting is not an option for you, [reach out to Bitrise](https://www.bitrise.io/contact) so we can discuss other options. ::: To set up the integration, you need to: 1. [Create a GitHub app](#creating-the-github-app-for-github-enterprise-server). Creating the app also allows GitHub Enterprise Server users to take advantage of the [Bitrise Checks feature](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/bitrise-checks-on-github): once the app is created, you just need to [enable Checks on Bitrise](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/bitrise-checks-on-github#enabling-github-checks-on-bitrise). 1. [Connect your Bitrise Workspace to GHES via the GitHub app](#connecting-to-the-ghes-instance-via-the-github-app). ### Creating the GitHub App for GitHub Enterprise Server 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left of the **Workspace settings** page, select **Integrations**. 1. Select the **Git provider** tab and scroll to the **GitHub Enterprise Server** section. 1. Copy the webhook URL you can find here. 1. In another browser tab, open GHES and go to your organization's **Settings** page. :::note[Target repository] The organization should be the one that owns the repository or repositories that your project(s) use. You can reuse the GitHub app for other organizations later. ::: 1. On the **Settings** page, find the **Developer** settings section and select **GitHub Apps**. 1. Click **New GitHub App** and fill out the app creation form. The following table contains all the necessary information and fields that aren't specified in the table can be left empty: :::important[Setting a webhook secret] Setting a webhook secret is mandatory for this process and you will need the secret later when connecting your Bitrise Workspace to the GHES instance. ::: | **GitHub App name** | Bitrise | | --- | --- | | **Homepage URL** | https://app.bitrise.io | | **Webhook URL** | The one you copied from your Workspace settings page on Bitrise. The format should be: `https://app.bitrise.io/organization//github_webhooks` | | **Webhook secret** | GitHub marks this as optional but to ensure webhook integrity we require a secret to be set. The webhook secret should be a random string of text with high entropy. Please make a note of the secret as you have to share it with Bitrise later. | | **Permissions** | Set the following permissions: - Repository permissions - Checks read and write - Commit statuses read and write - Contents read only - Metadata read only - Pull requests read only :::note[Upcoming features] Bitrise will use these events and permissions to offer a fully integrated experience with supporting, for example, [GitHub Checks](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/bitrise-checks-on-github) and [selective builds](/bitrise-ci/configure-builds/configuring-build-settings/selective-builds). We will add these capabilities soon. ::: | | **Subscribe to events** | Enable the following events: - Check run - Check suite - Pull request - Push | | **Where can this GitHub App be installed?** | If you want to enable integration for repositories outside of this GHES organization, select **Any account**. | 1. When done, click **Create GitHub App**. After creating the GitHub app, proceed to set up the GitHub Enterprise Server integration on Bitrise. ### Connecting to the GHES instance via the GitHub app After creating a new GitHub app, you need to connect your Bitrise Workspace to the GHES instance via the app: :::important[Webhook secret required] Make sure you have the webhook secret from the [GitHub app creation process](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise#creating-the-github-app-for-github-enterprise-server) available. ::: 1. Open your GitHub app's page: on your GitHub organization's **Settings** page, select **GitHub apps** and click **Edit** next to the app's name. 1. On the left, select **General**. 1. Note down the **App ID** and the **Client ID**: you will need them later. 1. Generate a new client secret: find the **Client secrets** section and click **Generate a new client secret**. Copy the secret: you will need it later! 1. Find the **Private keys** section and click **Generate a private key**. This downloads a `.pem` file which you will need to upload to Bitrise later in this process. 1. On Bitrise, open the **Workspace settings** page and in the **GitHub Enterprise Server** section, click **Connect to Instance**. 1. Fill out the connection form: - The **Instance base URL** should be the root URL of your server. - Add the **App ID** and **Client ID** you noted down earlier. - Add the webhook secret and the client secret you generated earlier. - Upload the `.pem` file. 1. When done, click **Save credentials**. :::note[Instant feedback] You will receive immediate feedback about the connection and actionable error messages in the case of failure. ::: 1. Go back to GHES and open your GitHub app's page again. 1. On the left, select **Install app**. 1. Choose the organization(s) to install the app on. 1. Under **Repository access**, select the repositories you want Bitrise to be able to access, or select all repositories. 1. When done, click **Save**. Bitrise receives a webhook event regarding the installation and automatically enables the corresponding Bitrise projects to use the recently set up GHES integration [which you can check on the app settings page](/bitrise-platform/repository-access/integrating-github-enterprise-with-bitrise#troubleshooting-the-ghes-integration). Once this is done, you can now store your `bitrise.yml` file in a GHES repository: [Storing the bitrise.yml file in your repository](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml#storing-the-bitriseyml-file-in-your-repository). :::tip[Testing the integration] We recommend testing the integration by creating a dummy project and store its `bitrise.yml` file on your GHES repository. You can use [this demo project](https://github.com/bitrise-io/android-demo-app) for testing purposes. ::: ### Troubleshooting the GHES integration If the GHES integration doesn't work, you can: - Check the status of the integration on the Bitrise **Integrations** page. - Checking the webhook configuration and webhook deliveries on GitHub. #### Checking the webhook configuration 1. Open your GHES organization's page, and on the top navigation bar, select **Settings**. 1. On the left, select **Developer settings** and then **GitHub Apps**. 1. Find your GitHub app, and click **Edit** next to its name. 1. On the left, select **Advanced**. 1. Under the **Recent deliveries** section, check your webhook deliveries. If the webhook is configured correctly, you should see a 200 OK response with a green checkmark next to the deliveries. 1. If your webhook deliveries failed: - Check the webhook URL on both Bitrise and on GitHub. - If necessary, re-create the webhook secret on GitHub and paste the new secret to the GHES integration on Bitrise. #### Checking the integration on Bitrise You can test the integration for any of the projects connected to your GHES instance. 1. 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. 1. On the left of the **Settings** page, select **Integrations**. 1. On the **Git provider** tab, find the **Git integration status** section. 1. Next to the GitHub Enterprise Server Instance, click the **Test connection** button to test the connection. ### Additional linked repositories for GitHub Enterprise Server You can link additional repositories to a project that uses GitHub Enterprise Server. Linking a repository means giving the project access to multiple repositories in addition to the [default repository](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch). You can read about configuration details here: [Additional linked repositories](/bitrise-platform/repository-access/github-app-integration#additional-linked-repositories-via-a-github-app). ### Extending GitHub App permissions for Enterprise Server users The Bitrise GitHub App generates a short-term, temporary token for each build that is triggered via the app. This token has only one permission by default: `content:read`. This means the build can access the GitHub repository but can't do anything else. You can grant additional permissions for the build token by extending all the permissions of the GitHub App. For details, check out [Extending GitHub App permissions to the builds](/bitrise-platform/repository-access/github-app-integration#extending-github-app-permissions-to-the-builds). --- ## Repository access with OAuth Bitrise needs access to your code in a Git repository to be able to build. You can provide access on a project-by-project basis but we recommend connecting your Bitrise account to your Git provider accounts (GitHub, GitLab, and Bitbucket). One of the ways to connect your accounts is by setting up an OAuth connection. You can connect all three Git provider accounts using OAuth, by either: - Connecting the account when adding a new Bitrise project. - Connecting the account from your [Account settings](http://app.bitrise.io/me/profile#/edit_profile) page. :::important[One account per Git provider] Please note that you cannot connect two accounts from the same Git provider (for example, two GitHub accounts) to Bitrise. ::: Connecting one Git provider account is not final. You can disconnect an account and connect a different one at any time. ### Connecting a Git provider with OAuth when adding a project 1. Log in to your [bitrise.io](https://www.bitrise.io) account and select **Bitrise CI** on the left. 1. Click **New CI project**. 1. Set the project’s privacy setting. 1. In the **Select repository** section, choose between selecting a remote repository or entering an URL manually. If you opt to enter a git URL manually, add it in the **Git repository (clone) URL** field and click **Next**. 1. Choose the Git service provider of the app’s repository, if you chose to select a remote repository. If no account with that provider has been connected to your Bitrise account, the UI will display the option to connect. 1. Click **Connect provider**. This will take you to the login page of the Git provider. 1. Log in to the Git provider account. 1. You should be prompted to authorize bitrise.io - do it! If successful, you should be redirected to Bitrise, and a pop-up message should inform you that you successfully linked the account. Click **Okay**. ### Connecting a Git provider with OAuth from the Account settings page Connecting a Git provider account with an OAuth application allows Bitrise to: - List the available repositories when [adding a new project](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache#adding-a-new-connection-to-the-build-cache). - [Automatically register webhooks](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks#registering-an-incoming-webhook-automatically). Webhooks allow setting up build triggers and enable the use of [Git Insights](/insights/git-insights). - [Automatically register SSH keys](/bitrise-platform/repository-access/configuring-ssh-keys). 1. Log in to Bitrise, and select **Bitrise CI** from the left navigation menu. 1. In the upper right corner, click the profile image to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. On the left, select **Connected accounts**. 1. On the **Git providers** tab, find the Git provider you want to connect, and click **Connect**. 1. Log in to the Git provider account. 1. You should be prompted to authorize bitrise.io - do it! If successful, you should be redirected to Bitrise, and a pop-up message should inform you that you successfully linked the account. Click **Okay**. ### Disconnecting a Git provider account 1. Log in to Bitrise, and select **Bitrise CI** from the left navigation menu. 1. In the upper right corner, click the profile image to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. On the left, select **Connected accounts**. 1. On the **Git providers** tab, find the Git provider you want to disconnect, and click **Disconnect**. ### Switching from OAuth connection to the GitHub app :::tip[Using the API] This section describes how to configure the feature on the Bitrise website. You can also configure it via the Bitrise API: [GitHub app configuration API](/bitrise-ci/api/github-app-configuration-api). ::: If your Bitrise project has an OAuth connection set up to your GitHub account, you can change it to the Bitrise GitHub app at any time without losing any functionality. We strongly recommend doing the switch: with the Bitrise GitHub app installed, you no longer need the service credential user, an SSH key, or a webhook to run Bitrise builds. :::important[HTTPS URL required] Please note that the GitHub app requires an HTTPS URL for your repository instead of an SSH one. Normally, you don't have to worry about this: setting up the GitHub app connection changes the URL of your project. If there's an issue, you can change the URL manually: [Changing the repository URL](/bitrise-platform/projects/configuring-the-repository-url-and-the-default-branch#changing-the-repository-url). ::: To switch: 1. Install the Bitrise GitHub App as described in the relevant guide: [Installing the GitHub App integration](/bitrise-platform/repository-access/github-app-integration#installing-the-github-app-integration). 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. ![project-settings-button.png](/img/_paligo/uuid-14defaa4-472c-2d09-84df-145dc3aef4f5.png) 1. On the left navigation menu, select **Repository**. 1. You can see a blue card with information about GitHub App support. To switch, click **Setup GitHub App**. ![SCR-20260331-prho.png](/img/_paligo/uuid-3de8dcba-e678-997e-20f0-3055cd889bb0.png) 1. Make sure you remove any pre-existing manual Webhooks from the **Incoming Webhooks** page of the **Webhooks** tab once the GitHub App is configured. You can get to this page via **Project Settings** → **Integrations** → **Webhooks** tab → **Incoming Webhooks**. If you fail to do this, duplicate builds will get triggered. For more information, see [Event subscriptions](/bitrise-platform/repository-access/github-app-integration#event-subscriptions). 1. Optionally, you can remove the service credential user and any SSH keys or personal access tokens used for OAuth connection. --- ## Changing the owners of a Workspace Workspace owners can access and delete all projects linked to the Workspace, can manage the billing details of a Workspace and can add or remove other owners. Every Workspace must have at least one owner. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration** from the menu options. 1. Select the **Owners** tab. ![owners-tab-workspace-settings.png](/img/_paligo/uuid-d0da76d5-0ec1-fd85-9ebd-b8d529c150be.png) 1. Click **+ Add owner** to add a new owner to the Workspace. 1. Enter an email address or add an existing member to the owners group using the radio buttons in the dialogue box. The account in question will become an owner of the Workspace. ![add-owner.png](/img/_paligo/uuid-820b4fbc-df87-77b2-04c1-8f688d9f6433.png) --- ## Roles and permissions in workspaces Roles determine the permissions of the workspace members. There are two main types of roles that can be assigned to workspace members: - **Workspace-level roles**: These roles determine what actions a user can perform within a workspace. Workspace-level roles can be assigned to individual members of a workspace. - **Project-level roles**: These roles determine what actions a user can perform on a project. Project-level roles can be assigned to workspace groups. The roles are different based on the product: Bitrise CI and Release Management have their own set of roles. - **Standalone product access**: Some products aren't tied to projects at all. You grant access to them for the whole workspace, with a single on-or-off setting: [Standalone products](#standalone-products). ### Workspace-level roles There are four main roles in a workspace: - **Owner**: The workspace owner has access to all CI projects and Release Management apps and have full control over them. - **Manager**: The user can access and modify workspace settings such as connected service accounts, can manage members but can't access billing details and can't delete the workspace. Workspace Managers can create new Bitrise projects. Within projects they have created, they can create CI configurations and/or Release Management connected apps. They cannot access or modify CI configurations or connected apps in Bitrise projects that they haven’t been given direct access to via user or group access settings. - **Contributor**: The user can't access workspace settings and can't add new members or manage existing members. - **Viewer**: The user can't add new projects or Release Management apps to the workspace. These roles mainly determine the user's permissions within the workspace. However, in the case of the workspace owners and the workspace managers, they provide additional permissions on the project level, as described above. But project access is mostly determined by project-level roles. ### Project-level roles You can assign roles on different projects to members, workspace groups, and outside contributors. You can do so either when: - Creating a group. - Modifying a group's settings. - Modifying a member's details. Project-level roles are only relevant to a specific project. The exact roles and their permissions depend on the product: both Bitrise CI and Release Management have their own roles and permissions: - [Bitrise CI roles and permissions](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). - [Release Management roles and permissions](/release-management/configuring-connected-apps/release-management-roles-and-permissions). Both individual members and workspace groups can be assigned roles on the workspace's projects. You can set up: - **Admin access**: The user or group can access to both Bitrise CI and Release Management on the selected projects, with the project admin role. - **Bitrise CI access**: The user or group can access Bitrise CI configurations of the selected projects. They can be assigned different roles on different projects. - **Release Management access**: The user or group can access Release Management apps of the selected projects. :::note[New projects and Release Management apps] If a new project is added to a workspace, users won't automatically become members of the project. Similarly, if a new Release Management app is added to an existing project, the user or group won't automatically have access to it just because they have access to other apps of the project. ::: ### Standalone products Standalone products don't have project-level roles. Access to them applies to the entire workspace, so there are no projects to select and no role to choose: you either grant access or you don't. Bitrise has one standalone product: - **Remote Dev Environments**: The user or group can create and manage their own sessions in the workspace, with the **RDE User** role. You grant this access in the **Standalone products** section of the product access settings, when inviting a member, creating a group, or managing access for an existing member or group. Project admin access doesn't include it. For details, see [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). ### Managing roles and permissions in a workspace You can update the roles and permissions assigned to any workspace member or workspace group at any time. #### Updating workspace roles for a member 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. Select the **Members** tab and find the workspace member you need in the list. 1. Click the options menu (⋮) next to their name and click **Manage access**. 1. On the **Overview** tab, find the **Workspace role** card and click **Change**. 1. Select the new role and click **Save changes**. #### Managing product and project access for a member You can, at any time, modify product and project access for individual members of a workspace. You can modify access for all the projects a user has access to, or just to a specific project. **All projects** 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. Select the **Members** tab and find the workspace member you need in the list. 1. Click the options menu (⋮) next to their name and click **Manage access** to open their details page. 1. On the **Overview** tab, click **Manage access**. 1. Click **Change settings** at the correct product type: - **Admin access**: Grants access to all products, managing all aspects of selected projects with the project admin role. - **Bitrise CI**: The user has access to Bitrise CI only, and it can be assigned [Bitrise CI roles](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). - **Release Management**: The user has access to Release Management only, and it can be assigned [Release Management roles](/release-management/configuring-connected-apps/release-management-roles-and-permissions). 1. Set up project access and access roles. The roles will be different based on the product. 1. Under **Standalone products**, turn **Remote Dev Environments** on or off. This one has no projects or roles to set up: see [Standalone products](#standalone-products). 1. When done, click **Confirm changes**. **Specific project** 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. Select the **Members** tab and find the workspace member you need in the list. 1. Click the options menu (⋮) next to their name and select **Manage access**. 1. Select the **Projects** tab and find the project you need in the list. 1. Click the options menu (⋮) next to its name and select **Change project access**. 1. Click **Change settings** at the correct product type: - **Admin access**: Grants access to all products, managing all aspects of selected projects with the project admin role. - **Bitrise CI**: The user has access to Bitrise CI only, and it can be assigned [Bitrise CI roles](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). - **Release Management**: The user has access to Release Management only, and it can be assigned [Release Management roles](/release-management/configuring-connected-apps/release-management-roles-and-permissions). 1. Set up project access and access roles. The roles will be different based on the product. 1. When done, click **Confirm changes**. :::note[Standalone products] **Remote Dev Environments** doesn't show up here. It applies to the whole workspace rather than to a single project, so you can only change it from the **All projects** flow. ::: --- ## Workspace collaboration Your workspace isn't just an environment to manage projects: it also allows seamless collaboration with other Bitrise users. You can invite other users to your workspaces, and of course you can be invited to other workspaces, too. You can manage workspace membership on the **Collaboration** page of the workspace settings. You can add members to a workspace in three ways: - Invite individual members: [Adding members to workspaces](#adding-members-to-workspaces). - Add them to a project as outside contributors. You can view and manage every outside contributor for the workspace, or turn off outside-contributor access entirely, from the **Outside contributors** tab on this page. - Organize them into [workspace groups](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups). Workspace members can have different roles in a workspace. Workspace roles determine the different actions that the members have permissions for. You can configure product access for workspace members: each member can have access to Bitrise CI, Release Management, Remote Dev Environments, or any combination of them. For each project within Bitrise CI and Release Management, you can set up different project-level roles for all workspace members: [Roles and permissions in workspaces](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces). If SAML SSO is enabled and configured for a Bitrise workspace, workspace members can use SAML SSO to log in to their Bitrise account: [Configuring SAML SSO on Bitrise](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise). ### Checking workspace member status You can check out the most important information about workspace members at any point. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Select **Collaboration**. 1. Go to the **Members** tab. On this tab: - You can [add and remove workspace members](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration#adding-members-to-workspaces). - If [SAML SSO](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise) is enabled for a member. - See each member's [workspace role](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces) and [product access](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces#project-level-roles). The **Product access** column lists the products the member can reach: Bitrise CI, Release Management, and Remote Dev Environments. Members without any product access show `(no access)`. You can search for a specific Workspace member or use the filter function to filter members based on their roles. Click the options menu (⋮) next to a member and select **View details** to open their details page. It has three tabs: - **Overview**: their workspace role and a **Product access** table showing the role they hold in each product. - **Projects**: the projects they have access to, and their role on each. - **Groups**: the workspace groups they belong to. ### Adding members to workspaces :::caution[Starter plan restrictions] On Starter plans, collaboration features for workspaces are not available. You have to add members on a project basis: [Adding outside contributor to a project](/bitrise-platform/projects/managing-user-access-to-a-project#adding-an-outside-contributor-to-a-project). ::: You can invite people to a workspace if they have a Bitrise account. Workspace members can be assigned to the projects owned by the workspace. When inviting new members, you can: - Add users in bulk: You can invite as many members as the number of available seats on the workspace. - Add them to all projects owned by the workspace, or just to particular projects. - Assign them [user access roles](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) to manage their permissions on the project. When adding users in bulk, all of them will be assigned the same role. - Add users to [global access groups](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups#global-access-groups): The invited users will have the same role on all projects owned by the workspace. You can't select specific projects when adding users this way. :::note[Invitation limits] To prevent abuse, invitations sent from workspaces on non-paid plans may be rate-limited. If you reach a limit while inviting members, wait a while before trying again. ::: :::note[SAML SSO] Bitrise supports SAML SSO for your workspace. To learn more, check out [SAML SSO in Bitrise](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise). Inviting a new member to a workspace with SAML SSO enforced is a different process: [Adding a new user to a Workspace with enforced SAML SSO](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-saml-sso-on-bitrise#adding-a-new-user-to-a-workspace-with-enforced-saml-sso). ::: You can modify a member's user roles on projects at any time after inviting them. You can also add members to [workspace groups](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups#creating-groups-for-workspaces). To add individuals as a workspace member: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. On the **Members** tab, click **Add members**. 1. On the **Invite members** page, find the **New members** section and add the email addresses of the people you want to invite. :::note[Workspace limits] You can't invite people who are already part of the workspace and the number of invitations can't exceed the available seats of the workspace. ::: 1. When done, click **Continue**. It takes you to the **Configure access to products** page. - **Admin access**: Grants access to all products, managing all aspects of selected projects with the project admin role. - **Bitrise CI**: The user has access to Bitrise CI only, and it can be assigned [Bitrise CI roles](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). - **Release Management**: The user has access to Release Management only, and it can be assigned [Release Management roles](/release-management/configuring-connected-apps/release-management-roles-and-permissions). 1. If you toggle on a specific product instead of admin access, you will be prompted to select the projects for the user and its user roles on the selected projects. - For Bitrise CI, you can select projects and assign a role to each project. You can also select the **All projects** option: in this case, the user will be added to [a global access group](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups#global-access-groups) with the selected role. - For Release Management, you can select: - Specific projects. The group will be able to access all currently existing apps of the project but not all future apps. - Specific Release Management apps: Select the already existing apps you want the group to have access to. 1. Under **Standalone products**, turn on **Remote Dev Environments** if the new members should be able to create remote dev sessions. This grants the **RDE User** role on the whole workspace, so there's nothing else to configure: [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). 1. When finished with setting up roles, click **Done**. 1. Click **Confirm access** to finish the process. The summary on the right lists what each invited user gets, including whether they get RDE access. ### Removing members from Workspaces :::important[Owners and managers only] Only Workspace owners and Workspace managers can remove users from a Workspace. ::: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. Select the **Members** tab. 1. Search for the user you would like to remove. Click the options menu (⋮) next to their name and select **Remove from workspace**. 1. Click **Remove** to remove the selected user from your Workspace. ![remove_member_confirm.png](/img/_paligo/uuid-ecd84027-5433-4ce8-cfbe-bbd61a77c095.png) --- ## Workspace groups Members of a Bitrise workspace can be organized into workspace groups. Groups allow flexible allocation of Workspace members between apps, simplifying the process of managing workspaces that own multiple projects. Workspace members can belong to multiple different groups. Groups can be assigned user roles on any project's team: each member of the group will have the group's role and the access rights that come with that role. :::note[Difference between project collaborators and workspace groups] Collaborators on a project are handled on a project basis, while workspace groups are handled globally within a workspace. A workspace group has no inherent roles on its own. [You can assign groups to projects](/bitrise-platform/projects/managing-user-access-to-a-project#adding-workspace-groups-to-a-project) and choose their [role](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) there, which means the same group can have different roles on different projects. ::: Workspace groups can have four main types of product access: - **Admin access**: Gives access to all aspects of the selected projects with the project admin role. This doesn't necessarily mean access to all projects owned by the workspace! - **Bitrise CI access**: The group can only access the Bitrise CI configuration of a project, with the specific [Bitrise CI roles and permissions](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). - **Release Management access**: The group can only access the Release Management apps of the project, with the specific [Release Management permissions](/release-management/configuring-connected-apps/release-management-roles-and-permissions). - **Remote Dev Environments access**: The group gets the **RDE User** role and every member can create remote dev sessions. This one isn't project-based — it applies to the whole workspace: [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). A group's details page has a **Product access** table listing the role the group holds in each product. On the **Groups** tab you can also filter the list by role — including **RDE User**, to find every group with RDE access. ### Global access groups You can grant a workspace member access to all projects on all products. When you do that, the member is added to a global access group. A global access group is a workspace group, with a few differences compared to regular workspace groups: - It can't be removed from the workspace. - Its roles can't be changed. You can add members to global access groups manually, just like to any other group. You can also rename global access groups at any time. ### Creating groups for Workspaces :::important[Owners and managers only] Only Workspace owners and managers can create groups for a workspace. ::: When you create a new group, you must decide which products it should have access to. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration** from the menu options. 1. Select the **Groups** tab. 1. Click the **Create group** button. This opens the group-creation page. 1. Enter a group name in the **Group name** field. Group names must be unique within the workspace. If you reuse one, you'll see a **Group name already exists** error. 1. Configure access to products: - **Admin access**: Grants access to all products, managing all aspects of selected projects with the project admin role. - **Bitrise CI**: The group has access to Bitrise CI only, and it can be assigned [Bitrise CI roles](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). - **Release Management**: The group has access to Release Management only, and it can be assigned [Release Management roles](/release-management/configuring-connected-apps/release-management-roles-and-permissions). 1. If you toggle on a specific product instead of admin access, you will be prompted to select the projects for the group and its user roles on the selected projects. - For Bitrise CI, you can select projects and assign a role to each project. You can also select the **All projects** option: in this case, the user will be added to a global access group with the selected role. - For Release Management in particular, you can select: - Specific projects. Note that the group will be able to access all currently existing apps pf the project but not all future apps. - Specific Release Management apps: select the already existing apps you want the group to have access to. 1. Under **Standalone products**, turn on **Remote Dev Environments** if the group should be able to create remote dev sessions. There are no projects or roles to set up for this one. 1. When finished with setting up roles, click **Done**. 1. Click **Create group**. ### Adding members to a Workspace group You can add Workspace members to Workspace groups for more convenient management of Workspace members. Groups allow you to assign several members to project teams at the same time. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration** from the menu options. 1. Select the **Groups** tab. 1. Find the group you need and click the 3 dots to the right of the group. Select **View details**. 1. On the group's details page, click **Add members**. 1. In the **Add members to '<group name>' group** dialog, choose how to add members: - Select **Add existing workspace members**, then select one or more members from the **Members** dropdown. Click **Add members** to add them to the group. - Select **Invite new members to the workspace**, then enter one or more email addresses in the **New members** field. Click **Invite members** to send the invitations. ### Adding Workspace groups to a project Assigning a workspace group to a project means that all members of that workspace group will have the same role on the project. Roles are different based on product access: both [Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) and [Release Management](/release-management/configuring-connected-apps/release-management-roles-and-permissions) have their own roles. **An project consisting of workspace groups** Let’s say the workspace called *TestSpace* owns a project called *TestProject*. *TestOrg* has the following groups: - **Group Alpha**: they are assigned to *TestProject* with an **Admin** role. Members of this group can assign other groups to the project or add outside contributors, change project settings, manage roles and Workflows. - **Group Beta**: they are assigned to *TestProject* with a **Developer** role. Members of this group can run builds, view build logs and view builds. - **Group Gamma**: they are assigned to *TestProject* with a **Tester/QA** role. They can only view builds. There are two ways to assign workspace groups to a Bitrise project: - You can assign it from the **Collaboration** menu of the **Workspace settings** page. - You can assign it on the **Project settings** page of the project. #### Assigning a group from the Workspace settings page 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. ![workspace-settings.png](/img/_paligo/uuid-b9660c7d-79af-481d-c05a-17356619dd07.png) 1. On the left, select **Collaboration** then go to the **Groups** tab. 1. Choose the group you wish to assign, and click the options menu (⋮). ![2025-08-07-assign-group-from-workspace.png](/img/_paligo/uuid-42c797d6-13f2-d5b3-c183-c48546d78983.png) 1. Select **View details** and go to the **Projects** tab. 1. Click **Manage access**. 1. Configure product access by enabling one or more toggles and then selecting a role for your project in the dialog. You have the option to grant universal access or to set roles on a product basis: - **Admin access** allows the contributor to manage all aspects of the project, including both the Bitrise CI configuration and the Release Management apps. Note that this gives full access to an outside contributor! - Select a product to assign the group specific roles that only apply to that product. If the project doesn't have a [CI configuration](/bitrise-ci) or a [Release Management app](/release-management), the respective option won't be available. ![2025-08-07-access-in-rm-dialog.png](/img/_paligo/uuid-5b7fd557-dadc-4d73-eaa5-39119cd3b63f.png) :::tip[Role cheatsheets] You can check out the role cheatsheets here: . - [Roles and permissions for Bitrise CI](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) - [Release Management roles and permissions](/release-management/configuring-connected-apps/release-management-roles-and-permissions) ::: 1. Click **Save changes** to finalize changes. #### Assigning a group from the Project settings page 1. Open your project on Bitrise with a user that has the **Admin** [role on the project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci). 1. On the main page of the project, click on the **Project settings** button. ![project-settings-button.png](/img/_paligo/uuid-14defaa4-472c-2d09-84df-145dc3aef4f5.png) 1. On the left, select **Collaboration**. 1. Go to the **Groups** tab. 1. Click on **Add group**. 1. In the dropdown menu, select the group you need then click **Next**. ![2025-08-07-add-group-to-project.png](/img/_paligo/uuid-4023a0e5-a889-7041-05ab-f31969f8e898.png) 1. Configure product access by enabling one or more toggles and then selecting a role in the dialog. You have the option to grant universal access or to set roles on a product basis: - **Admin access** allows the group members to manage all aspects of the project, including both the Bitrise CI configuration and the Release Management apps. - Select a product to assign the group specific roles that only apply to that product. If the project doesn't have a [CI configuration](/bitrise-ci) or a [Release Management app](/release-management), the respective option won't be available. 1. Click **Confirm access**. --- ## Creating Workspaces A Workspace is an environment that allows you to manage your Bitrise apps and the team members working on the apps. You can create multiple Workspaces, and you can be invited to Workspaces by other Bitrise users. You must have access to at least one Workspace to be able to use Bitrise. When you create a new account, you can’t add new apps or run builds. To be able to do so, you need to either create a Workspace, or to be invited to an existing one. When you sign up for Bitrise, you are automatically prompted to create a new Workspace. If you skip creating a Workspace, or you want to create additional Workspaces later, you can do it: 1. Log in to [bitrise.io](https://www.bitrise.io). 1. Hover over the left navigation bar. 1. Open the dropdown menu next to your Workspace name. ![workspace-menu.png](/img/_paligo/uuid-c9c66545-e909-2236-e073-d55e134d6548.png) 1. Select **Create Workspace**. This takes you to the **Create workspace** page. 1. Find the **Workspace name** input field, and add a name. 1. Click **Create**. This creates the Workspace - everything that comes after is optional and can be completed at a later point. However, without a subscription plan - either free or paid - your Workspace will be inactive and won't be able to own apps or run builds. 1. Choose a plan. If you’re interested in the details, or you want to find out more about our other plans, check out our [Pricing page](https://www.bitrise.io/pricing/) for more info. 1. Select a paid subscription plan, and follow the instructions to configure the details of the plan and set up payment methods. Alternatively, select the free plan for now and [add a subscription later](/bitrise-platform/workspaces/workspace-billing-and-invoicing). And that’s it. You can start adding apps and inviting people to your Workspace. --- ## Workspace API token A Workspace API token allows Workspace members to access the [Bitrise API](/bitrise-ci/api/api-overview) without each member having to set up their own [Personal Access Token](/bitrise-platform/accounts/personal-access-tokens). For API authentication, the Workspace token functions the exact same way as the Personal Access Token. A Workspace owner can set up multiple Workspace API tokens, each with different access rights to the apps owned by the Workspace. The access rights are determined by [user roles](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci), just as it is for [Workspace members](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration) or [Workspace groups](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups). We recommend setting up any integrations that require an access token for API access using a Workspace API token instead of individual users' Personal Access Token. ### Creating a Workspace API token 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Security**. 1. Click **Create token**. ![workspace-api-token.svg](/img/_paligo/uuid-cb123ebc-f548-8e87-615f-aab39fefa078.svg) 1. On the **Settings** step, enter a **Name** and select an **Expiration** for the token. 1. Select a **Workspace role** for the token. This determines what the token can do at the workspace level. 1. Click **Next**. 1. On the **Product access** step, set up what the token can access: - Toggle on **Admin access** to let the token manage all aspects of selected projects, with access to all products. - Toggle on **Bitrise CI** to let the token access CI builds. Choose **Apply to: All projects** or **Selected projects**, then select a **Role** — or leave it on **No access**. - Toggle on **Release Management** to let the token access Release Management, with permissions controlled by role at the app level. 1. Click **Create token**. 1. Click **Copy and close** to copy the token and close the dialog box. :::caution[Save the token] Once you closed the dialog box, you won't be able to see the token again! ::: ### Regenerating a Workspace API token If a Workspace API token is lost for any reason, there is no way to view it again. You have the option of regenerating the existing token: this way you don't have to create an entirely new token and configure app access again. The regenerated token will: - Have a new expiration date. - Have access to the exact same apps with the exact same roles as before. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Security**. 1. Find your token and click the options menu (⋮) next to its name. 1. Select **Regenerate**. ![regenerate-token.png](/img/_paligo/uuid-3850ebd0-6ab7-934f-c232-4305ccffe249.png) 1. Select the new expiration date. 1. Click **Regenerate** to get the new token. 1. Click **Copy and close**. Make sure to save the token in a secure way: you won't be able to see it again. --- ## Workspace billing and invoicing You can modify your subscription plan and billing information at any time on the Workspace page. You can set up a credit card as payment method. We'll send you invoices to your email address but you can also download them from the **Workspace settings** page. Please note that direct debit is only available for Workspaces via our [Sales team](https://bitrise.io/contact). ### Changing your billing email By default, a workspace’s invoices will be sent to the email provided when the workspace was created. However, the owner(s) of the workspace can change it at any time. 1. Sign in with an account that is an owner of the workspace. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **General settings** from the menu options. ![billing-email.png](/img/_paligo/uuid-d36425af-6967-473f-d8d7-07fdaed7ebc1.png) 1. Locate the **Billing email** field and click **Edit** under it. 1. Enter the new email address and click **Confirm changes**. ### Downloading Workspace invoices 1. Sign in with an account that is an owner of the Workspace. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Plan & billing** from the menu options. 1. Find the product whose invoices you need and click **Manage** on its card. 1. In the product drawer, click **Manage billing information**. This opens the Chargebee billing portal in a new tab. 1. In the Chargebee portal, find the invoice you need and download it. ### Changing a subscription plan You can change your workspace's subscription plan at any time from the **Workspace settings** page. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left navigation menu, select **Plan & Billing**. 1. Find the product you want to change the plan for and click **Manage** on its card. 1. In the product drawer, click **Change plan**. 1. On the **Select new plan** page, click the button on the plan tier you want (for example, **Change to Teams** or **Change to Pro**). :::note[Enterprise plans] Enterprise plans are not available on a self-serve basis. If you wish to select an Enterprise plan, you can click the **Talk to us** button which takes you to our [contact page](https://bitrise.io/contact). ::: 1. On the **Customize plan** page, set up your subscription plan and then click **Continue to checkout**. 1. Follow the instructions in the checkout dialog. You can change your payment method, billing address, and all other subscription information at this stage. ![checkout.png](/img/_paligo/uuid-85ec7e12-6811-a14d-5388-d5502f87fc22.png) ### Canceling a product subscription In Bitrise, each product has its own independent subscription that you can cancel separately. You can cancel Bitrise CI, Build Cache, Release Management, or any other product without affecting your other subscriptions. You can also cancel an add-on subscription on its own. Canceling an add-on doesn't affect the product's subscription — it stays active. When you cancel a product subscription, you keep access until the end of your current billing period. After that, the product reverts to its free plan where available. 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left navigation menu, select **Plan & Billing**. 1. Find the product you want to cancel and click **Manage** on its card. 1. In the product drawer, click **Cancel subscription**. 1. Select a cancellation reason and click **Cancel subscription**. Your subscription remains active until the end of the current billing period. A banner on the **Plan & Billing** page confirms the scheduled cancellation date. :::note To cancel all product subscriptions, repeat these steps for each product individually. ::: --- ## Workspace FAQ **What is a workspace on Bitrise?** Workspaces are used to seamlessly manage bigger teams and members inside a company. It is a place to gather all the people working on each of your company’s projects and delegate them through creating different groups. **How do I add a project to a workspace?** [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project) **How do I migrate/transfer my existing projects to a workspace?** After you’ve created a workspace, you can transfer any of your projects to it at any time: [Changing the owner of a project](/bitrise-platform/projects/changing-the-owner-of-a-project). **What are owners inside a workspace?** Workspaces can have more than one owner. owners can manage billing, delete projects and change the billing email, create, delete and assign groups to projects. Managers can also create, delete, and assign groups to projects. **What can members of a workspace do?** Workspace members have access to different projects and different products, depending on their roles and permissions: [Roles and permissions in workspaces](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces) **What are groups good for?** By creating [groups](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups), you can assign multiple workspace members to each project at once, making it faster and easier to setup new projects on Bitrise. It also make it faster to reassign, remove and change role of multiple members. Groups can be assigned to a project, the group’s role can be set, and by removing the group from the project, you can revoke the access of every member of that group from the project. **Who are the Outside contributors?** Outside contributors are invited to work on a project owned by the workspace. They aren't members of the workspace and they only have access to the project they are invited to. **Can I have multiple workspaces?** One user can have as many workspaces as they like, but each workspace has to have an active subscription to be able to run CI builds or create Release Management apps. --- ## Workspace Slack integration You can configure a Slack integration for your workspace that can send notification messages to selected Slack channels. You can use this integration to send messages of: - Build events in Bitrise CI, with the **[Send a Slack message](https://github.com/bitrise-io/steps-slack-message)** Step. - Release events in Release Management. - Alerts in Insights. The integration is an OAuth application with an incoming Slack webhook. You can configure the integration for multiple channels: if, for example, you want Release Management events posted to a different channel than CI notifications, you can do that. The integration can view basic information about public channels in your Slack workspace and post to both public and private channels without being a member of the channel. If you are logged in to Slack, you can use the below button to connect the Bitrise Slack app to your Slack workspace: [Add to Slack](https://app.bitrise.io/workspace/integrations/slack/oauth) Read the [Bitrise privacy policy](https://go.bitrise.io/privacy-policy) before connecting the Slack app and check out our [Pricing page](https://bitrise.io/pricing) to learn about the Bitrise plans available for your workspace. You can also configure the Slack integration from the **Workspace settings** page: ### Configuring the Slack integration To set up the Slack integration for a given channel: 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. Select **Integrations** and then select the Slack card. 1. Click **Add configuration**. 1. In the dialog, view the permissions of the integration and select a channel. You can select private and public channels, as well as direct messages with Slack users. 1. Click **Allow**. ### Renaming the configuration By default, the integration gets an automatically generated name. You can rename it at any time to create an easily identifiable configuration. 1. Open the **Workspace settings** page. 1. Select **Integrations** and then the Slack card. 1. Find your configuration and click the options menu (⋮) next to its name. 1. Select **Rename**. ![rename-int.png](/img/_paligo/uuid-a5864e82-1efc-0191-b37c-a162cfcb8f42.png) 1. Type a new name and click **Save changes**. ### Getting the integration ID The integration ID identifies the Slack integration: it allows you to use it with the [**Send a Slack message**](https://github.com/bitrise-io/steps-slack-message) Step. To get it: 1. Open the **Workspace settings** page. 1. Select **Integrations** and then the Slack card. 1. Find your configuration and click the options menu (⋮) next to its name. 1. Select **Copy integration ID**. ![integrations-id.png](/img/_paligo/uuid-3b1378b0-3006-c0d1-a710-7c4a51821841.png) --- ## Workspaces overview A workspace is an environment that allows you to manage your Bitrise projects and the team members working on the projects. You can create multiple workspaces, and you can be invited to workspaces by other Bitrise users. To be able to add projects and run builds, you either need to be part of a workspace, or you have to be an outside contributor on an project's team. You also need a workspace to have [an active subscription plan](https://www.bitrise.io/pricing) on Bitrise. Each of your workspaces can have a different subscription plan which determines how many credits your workspace's projects can use. --- ## GitHub integration Authenticate your sessions to GitHub as you with the [Bitrise GitHub App](/bitrise-platform/repository-access/github-app-integration) integration. In every new session, `git clone`, `git push`, and the GitHub CLI (`gh`) work over HTTPS out of the box without needing to paste personal access tokens or manage SSH keys. ### Overview When you enable the integration, Bitrise plants a short-lived GitHub access token on each new session machine, issued through your GitHub account connection on Bitrise (the Bitrise GitHub App): - Tokens are valid for at most eight hours and refresh automatically for the whole lifetime of the session, including restores. - No long-lived credential is ever stored on the machine. - Commits you author in a session are attributed to your GitHub account, using your GitHub noreply email address so your real email address is never exposed. ### Enabling the integration 1. Open Bitrise. 1. 1. Log in to Bitrise and click the profile image in the upper right corner to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. Select **Connected accounts**, then connect **GitHub** through the Bitrise GitHub App. :::info[Workspace-level GitHub App connections don't count] This integration checks your personal GitHub account connection, not a GitHub App installed at the Workspace level. Even if your organization's admin already connected the Bitrise GitHub App for CI, you still need to connect your own account on the **Connected accounts** page. ::: 1. In the [Bitrise RDE UI](/bitrise-rde/rde-options/bitrise-rde-ui), select **Saved Inputs** on the left, under **User settings**. 1. On the **GitHub** card, check that your account shows as connected, then enable the toggle. ![The GitHub card on the Saved Inputs page, connected and ready to enable](/img/rde/2026-07-31-rde-github-integration-card.png) New sessions you create from this point get automatic GitHub access. Sessions created before you enabled the integration are not changed. ### Repositories you can access Sessions act as you through the Bitrise GitHub App, so a session can access the repositories that meet both conditions: - You have access to the repository on GitHub. - The Bitrise GitHub App is installed on the repository. :::info[Repository not found] If a clone fails with "repository not found" for a repository you can open in the browser, the Bitrise GitHub App isn't installed on that repository or organization. Ask an organization admin to install the app there. ::: To check which repositories the app is installed on: 1. On GitHub, open the [installed GitHub Apps](https://github.com/settings/installations) page for your account, or your organization's, if the app is installed at the organization level. 1. Find **Bitrise** in the list and select **Configure**. 1. Under **Repository access**, review the repositories the installation is scoped to. ### Disabling the integration Disabling the integration stops credential issuance immediately: new sessions no longer receive credentials, running sessions immediately stop being able to refresh theirs, and the most recently issued token expires within eight hours. 1. In the [Bitrise RDE UI](/bitrise-rde/rde-options/bitrise-rde-ui), select **Saved Inputs** on the left, under **User settings**. 1. On the **GitHub** card, turn off the toggle. --- ## Managing RDE access Access to Remote Dev Environments is granted per workspace member. Being a member of a workspace that has RDE isn't enough on its own: until someone grants you access, the **Remote Dev Environments** section doesn't open for you. :::caution[Remote Dev Environments is in beta] Remote Dev Environments is a beta product. The features, APIs, and clients described here can change, and breaking changes can happen without prior notice. Don't rely on RDE for production-critical workflows yet. ::: ### RDE access overview RDE is a **standalone product**. Unlike Bitrise CI and Release Management, its access isn't tied to projects: it's a single on-or-off setting that applies to the whole workspace. There's nothing to configure per project, and no role to choose. - Granting access assigns the **RDE User** role on the workspace. That's the only RDE role. - Admin access to projects doesn't include RDE. It has to be granted separately. - Workspace owners always have access. Everyone with the RDE User role can create and manage their own sessions, templates, and saved inputs. :::important[Owners and managers only] Only workspace owners and workspace managers can grant or revoke RDE access. For the full picture of workspace roles, see [Roles and permissions in workspaces](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/roles-and-permissions-in-workspaces). ::: You can grant access in three places, all on the **Collaboration** page of the workspace settings: - To an existing member: [Granting access to a member](#granting-access-to-a-member). - To a whole [workspace group](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-groups): [Granting access to a group](#granting-access-to-a-group). - To someone you're inviting: [Adding members to workspaces](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration#adding-members-to-workspaces). If your workspace provisions users through an identity provider, you can assign the role automatically: [Managing RDE access with SCIM](#managing-rde-access-with-scim). ### Granting access to a member 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. On the **Members** tab, find the member and click the options menu (⋮) next to their name, then select **View details**. 1. On the **Overview** tab, click **Manage access**. 1. Under **Standalone products**, turn on **Remote Dev Environments**. 1. Click **Save changes**. The member gets the **RDE User** role and can open the **Remote Dev Environments** section right away. :::note[All projects only] The **Standalone products** section shows up when you manage access across all projects. It isn't part of the per-project **Change access** flow, because RDE access isn't project-specific. ::: ### Granting access to a group Every member of the group inherits the access, including people you add to the group later. **Existing group** 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. Select the **Groups** tab and find the group you need. 1. Open the group's details and click **Manage access**. 1. Under **Standalone products**, turn on **Remote Dev Environments**. 1. Click **Save changes**. **New group** 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. Select the **Groups** tab and click **Create group**. 1. Enter a group name in the **Group name** field. 1. Under **Standalone products**, turn on **Remote Dev Environments**. 1. Click **Create group**. ### Checking who has access The workspace settings show RDE access in a few places: | Location | What you'll see | |---|---| | **Workspace settings** > **Collaboration** > **Members** tab | **Remote Dev Environments** listed in each member's **Product access** column. Members without any product access show `(no access)`. | | **Workspace settings** > **Collaboration** > **Members** tab > options menu (⋮) > **View details** > **Overview** tab | A **Product access** table with a **Remote Dev Environments** row and the **RDE User** tag. | | **Workspace settings** > **Collaboration** > **Groups** tab | The **RDE User** role on each group. Filter the list by that role to see every group with access. | ### Revoking access Revoking access doesn't delete the person's sessions. Running sessions keep running until they auto-terminate, and terminated sessions keep their persistent disk until someone deletes them or the stack they were created from is removed. To reclaim the storage, delete the sessions explicitly. :::note[Access from a group] If a member still has RDE access after you revoke it directly, check their **Groups** tab: a group they belong to may grant it. Remove them from that group, or turn off RDE for the group. ::: **Member** 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. On the **Members** tab, find the member and click the options menu (⋮) next to their name, then select **View details**. 1. On the **Overview** tab, click **Manage access**. 1. Under **Standalone products**, turn off **Remote Dev Environments**. 1. Click **Save changes**. **Group** 1. 1. Log in to Bitrise and hover over the left navigation bar. 1. Make sure you have the right workspace selected in the **Workspace** menu. 1. Select **Settings**. 1. On the left, select **Collaboration**. 1. Select the **Groups** tab and find the group you need. 1. Open the group's details and click **Manage access**. 1. Under **Standalone products**, turn off **Remote Dev Environments**. 1. Click **Save changes**. ### Managing RDE access with SCIM If your workspace uses SCIM provisioning, your identity provider can assign the RDE User role with the standard `roles` attribute. The value is `rde:rde_admin`: ```json { "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"], "userName": "user@example.com", "roles": [ { "value": "workspace:workspace_contributor" }, { "value": "rde:rde_admin" } ] } ``` Sending a `roles` array without an `rde:` entry removes the user's RDE access. For the request formats each identity provider uses, see [Configuring SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/configuring-scim#managing-workspace-and-product-roles-via-scim). --- ## Remote Dev Environments API The Remote Dev Environments REST API lets you manage sessions, templates, and saved inputs programmatically, and report on what the workspace's active sessions consume. It's the same API that the CLI, the web UI, and the MCP server use. :::caution[Remote Dev Environments is in beta] Remote Dev Environments is a beta product. The features, APIs, and clients described here can change, and breaking changes can happen without prior notice. Don't rely on RDE for production-critical workflows yet. ::: :::warning[Experimental API] The RDE API is experimental. Although it's versioned, endpoints and payloads can change in backwards-incompatible ways without notice. Pin your integrations to a known-good behavior and expect to update them. ::: ### Base URL The API is served at: ```text https://api.bitrise.io/rde ``` ### Authentication Authenticate with a Bitrise [personal access token](https://app.bitrise.io/me/account/security), sent in the `Authorization` header: ```text Authorization: token YOUR_BITRISE_PAT ``` ### Workspace usage report The usage endpoint returns a point-in-time snapshot of the workspace's active sessions: session counts and vCPU and memory totals split by OS, workspace-wide and per user. It reports what the sessions consume right now — it's not a historical or billing-period report. ```text GET /v1/workspaces/{workspace_id}/usage ``` Unlike the other endpoints, this one requires billing visibility: workspace owners and members with a billing-managing custom role can call it. Other members get a `403` response. ### Reference For the full list of endpoints, request and response schemas, and examples, see the interactive API reference: [Remote Dev Environments API reference](/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api) --- ## Saved inputs A saved input is a reusable value or credential that you store once and map into sessions as needed. Saved inputs are scoped to your user account rather than a single workspace, and secret values are encrypted at rest. :::note[Looking for GitHub access?] The **GitHub** card on the same screen isn't a saved input: it toggles the [GitHub integration](/bitrise-rde/configuration/github-integration), which gives your sessions automatic git and GitHub CLI authentication — no token to store. ::: ### Common saved inputs Some saved inputs have a dedicated purpose: - **SSH public key**: registered as `SSH_PUBLIC_KEY`, this lets you connect to your sessions over SSH without a password. See [Connecting to a session](/bitrise-rde/rde-options/connecting-to-a-session#ssh). - **Claude Code credential**: a `CLAUDE_CODE_OAUTH_TOKEN` or `ANTHROPIC_API_KEY` value so sessions start with Claude Code already authenticated. - **Custom values**: any key-value pair your environment needs, such as an API token or a registry login. Mark it as secret to encrypt it. #### Configuring passwordless SSH access To connect to your sessions over SSH without a password, add your SSH public key: 1. Select **Saved Inputs** on the left, under **User settings**. 1. Under **Passwordless SSH access**, click **+ Add public key**. ![Add SSH public key dialog](/img/rde/2026-06-29-rde-saved-inputs-add-ssh-key.png) 1. Paste your public key (for example, the contents of `~/.ssh/id_ed25519.pub`) into the `SSH_PUBLIC_KEY` field. 1. Click **Save**. Bitrise adds the key to the `authorized_keys` of every new session, so you can connect with `ssh` directly. #### Configuring Claude Code credentials To start Claude Code automatically in new sessions, add a Claude Code credential: **Subscription token** Use this option to bill usage against your Claude Pro or Max plan. 1. Under **Claude Code**, open the **Subscription token** tab. 1. Click **+ Add subscription token**. ![Add Claude subscription token dialog](/img/rde/2026-06-29-rde-saved-inputs-add-subscription-token.png) 1. In your terminal, run `claude login` then `claude setup-token`. Copy the generated token (it starts with `sk-ant-oat01-`). 1. Paste the token into the `CLAUDE_CODE_OAUTH_TOKEN` field. 1. Click **Save**. **API key** Use this option for pay-per-token billing with an Anthropic API key. 1. Under **Claude Code**, open the **API key** tab. 1. Click **+ Add API key**. ![Add Anthropic API key dialog](/img/rde/2026-06-29-rde-saved-inputs-api-key.png) 1. Paste your Anthropic API key (starts with `sk-ant-`) into the `ANTHROPIC_API_KEY` field. 1. Click **Save**. Once saved, new sessions that include a Claude Code credential in their template will start with Claude Code already authenticated. ### Using saved inputs in a session When you create a session, a [template](/bitrise-rde/configuration/templates) input can pull its value from a saved input. You can select the saved input explicitly, or let Bitrise map saved inputs to session inputs that share the same key. Because the session references the saved input by ID, the actual value — including secrets — is resolved on the server and never exposed in the UI or in your session configuration. ### Managing saved inputs Create, edit, and delete saved inputs from the [Bitrise RDE UI](/bitrise-rde/rde-options/bitrise-rde-ui), or from the CLI with `bitrise-cli rde saved-input`. --- ## Templates A template is a reusable Remote Dev Environment configuration. Define the machine and its setup once, then create consistent sessions from it without repeating the same choices each time. ### Template overview A template can include: - A stack, a machine type, and a working directory that terminals start in. - A warmup script and a startup script for installing tools and preparing the environment. - Template variables and session inputs for the values your environment needs. - Workspace links: shortcut buttons that open a specific folder in your IDE. ### Warmup and startup scripts Both scripts are Bash and run as the session user, but at different times: - The warmup script runs once, when the session is first created. Use it for slow, one-time setup such as installing dependencies. - The startup script runs every time the session starts, including after a restore. Keep it idempotent, since it runs more than once. ### Variables and inputs Templates carry two kinds of values, both of which can be exposed to the session as environment variables: - Template variables are baked into the template with a fixed value. Mark a variable as secret to encrypt it at rest. - Session inputs are filled in when a session is created. You can mark an input as required and give it a default value. A session input can also pull its value from a [saved input](/bitrise-rde/configuration/saved-inputs), so secrets are resolved on the server and never shown in the UI. ### Workspace links Workspace links are buttons on the session that open a given folder path in your IDE. They're handy for jumping straight into the right directory in a multi-folder project. ### Managing templates Create, edit, clone, and delete templates from the [Bitrise RDE UI](/bitrise-rde/rde-options/bitrise-rde-ui), or from the CLI with `bitrise-cli rde template`. When you create a session, its template configuration is captured as a snapshot. Editing or deleting a template afterwards doesn't change or break sessions that were already created from it. --- ## Key concepts Remote Dev Environments share the same building blocks across every client — the CLI, the web UI, the MCP server, and the API. Understanding these concepts helps you move between them. ### Sessions A session is a single Remote Dev Environment instance: one cloud machine that you connect to and work on. You create a session either from a [template](#templates) or directly by choosing a [stack and a machine type](#stacks-and-machine-types). Each session belongs to the workspace it was created in and is owned by the user who created it. You can connect to it in several ways — see [Connecting to a session](/bitrise-rde/rde-options/connecting-to-a-session). ### Session lifecycle A session moves through a few states during its life: - **Running**: the machine is provisioned and ready to connect to. When you create or restore a session, it becomes running after a short startup. - **Terminated**: the machine is stopped, but the session and its persistent disk are kept. Terminating is reversible. - **Deleted**: the session is permanently removed. You can only delete a session that's already terminated. Terminating a session preserves its **persistent disk**, so when you restore it your files and changes are still there. There is no time limit on how long a terminated session is kept - it stays until you delete it, or until the stack it was created from is removed from Bitrise. A session's disk stores only the changes you have made on top of the stack image it was created from, so the session can only be started while that stack image is still available. Stacks are removed on a published schedule, with at least four weeks' notice - see [Stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). When a stack is removed, sessions created from it are permanently erased and cannot be restored. Create a new session from a current stack, and commit or export anything you want to keep, before then. To avoid leaving machines running, every session has an **auto-terminate** timer: - The default is 5 days of inactivity. - You can set it to anything up to 30 days, or turn it off so the session never auto-terminates. - Sessions in free-trial workspaces are capped at 8 hours and can't change this. ### Stacks and machine types When you create a session you choose two things: - A **stack**: the operating system image and the tools preinstalled on it, such as a specific Xcode version on macOS. These are the same stacks used by Bitrise CI. - A **machine type**: the size of the machine, defined by its CPU and RAM. macOS uses Apple silicon machine types; Linux machine types range from small shared instances to large dedicated ones. A template can set these for you, or you can pick them directly when creating a session. The available stacks and machine types depend on your workspace. **Your session stays tied to the stack you choose.** The stack isn't only a starting point - a session keeps a permanent dependency on the stack image it was created from. Your session's disk stores only the changes you make on top of that image, so the session can be started only while that image is still available on Bitrise. You cannot move an existing session to a different stack; to move to a newer stack, create a new session from it. Because stacks are eventually removed on a published schedule, this also determines how long a session can be kept - see [Session lifecycle](#session-lifecycle). ### Templates A template is a reusable session configuration. Instead of choosing a stack, machine type, and setup steps every time, you define them once in a template and create sessions from it. A template can include: - A stack, a machine type, and a working directory. - A **warmup script** that runs once when the session is first created, and a **startup script** that runs on every start. - **Template variables** and **session inputs**: values the session needs, which can be exposed as environment variables and marked as secret. - **Workspace links**: shortcut buttons that open a specific folder in your IDE. For details, see [Templates](/bitrise-rde/configuration/templates). ### Saved inputs A saved input is a reusable value or credential — such as an SSH public key, an API token, or a Claude Code credential — that you store once and map into sessions as needed. Saved inputs are scoped to your user account, not to a single workspace, and secret values are encrypted at rest. For details, see [Saved inputs](/bitrise-rde/configuration/saved-inputs). --- ## Quickstart The fastest way to try Remote Dev Environments is the Bitrise RDE CLI. In three commands you install the CLI, sign in, and drop into [Claude Code](https://www.anthropic.com/claude-code) running on a cloud machine, working on a clone of your repository. :::caution[Remote Dev Environments is in beta] Remote Dev Environments is a beta product. The features, APIs, and clients described here can change, and breaking changes can happen without prior notice. Don't rely on RDE for production-critical workflows yet. ::: ### Before you start You need: - A local Git repository with the branch you want to work on already pushed to its remote. - A Claude Code subscription or an Anthropic API key, so the agent can run in your session. ### Granting RDE access A workspace owner or manager needs to turn on Remote Dev Environments for you before you can start a session. They do this from the **Collaboration** page in the workspace settings. For the full walkthrough, see [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). ### Start a Claude Code session Run these commands in your terminal. 1. Install the Bitrise CLI. ```bash curl -fsSL https://app.bitrise.io/cli/install.sh | bash ``` 1. Sign in to your Bitrise account. This opens your browser to authenticate. ```bash bitrise-cli auth login ``` 1. From your repository folder, start a session with Claude Code. ```bash bitrise-cli rde claude ``` :::note If you belong to more than one workspace, the CLI asks you to pick one. To skip the prompt, set a default with `bitrise-cli config set default_workspace_id `, or use the `--workspace` flag. ::: 1. Pick a stack and a machine type. 1. Authenticate Claude Code if prompted. If no credential is saved for you yet, the CLI picks up your local Claude Code credential, or opens the browser so you can sign in with your subscription or API key. The credential is saved, so future sessions start with Claude Code already authenticated. :::tip You can also save or update the credential in the [Bitrise RDE UI](/bitrise-rde/rde-options/bitrise-rde-ui#authentication). ::: The CLI remembers your choices for the current repository. It creates a session, clones your current branch into it, and starts Claude Code in the cloud machine. You land directly in the agent, ready to work. :::important[Only pushed commits are cloned] `bitrise-cli rde claude` clones the pushed state of your current branch. Local commits and uncommitted changes that you haven't pushed are not transferred to the session. ::: :::tip[Give the session GitHub access] Enable the [GitHub integration](/bitrise-rde/configuration/github-integration) so the agent can pull, push, and open pull requests as you — git and the GitHub CLI authenticate automatically in every new session. ::: ### Let the agent reach your machine While you work in Claude Code on the cloud machine, the CLI keeps a secure connection open so the agent can run a few actions on your **local** computer. Just ask Claude Code in plain language: - **Open a VNC viewer**: the agent opens a remote desktop viewer on your machine, pointed at the session's macOS desktop, so you can watch a simulator or a GUI app. The VNC password stays local and is never sent to the session. - **Download files**: the agent pulls a file or folder from the session down to your machine and tells you where it landed. - **Upload files**: the agent pushes a local file or folder, such as a signing certificate, into the session. For example, after the agent builds your app you can say *"open VNC so I can see the simulator"* or *"download the build output to my Downloads folder"*, and it happens on your machine. :::note[VNC is macOS only] Opening a VNC viewer works for macOS sessions, which have a graphical desktop. Linux sessions don't have a desktop, so the agent can still transfer files but can't open VNC. ::: ### Resume your session later If your connection drops, the CLI reconnects automatically while Claude Code keeps running in the session. Press Ctrl-C during a reconnect to detach and leave the machine running. When you exit Claude Code, the session is automatically terminated to free the machine, but it's preserved so you can come back to it. From the same repository folder, resume your most recent session and conversation: ```bash bitrise-cli rde claude --continue ``` To choose from your earlier sessions for the repository instead, use `bitrise-cli rde claude --resume`. ### Next steps - Do more from the terminal: [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli). - Understand what you just created: [Key concepts](/bitrise-rde/getting-started/key-concepts). - Use a browser or a different IDE: [Ways to use RDE](/bitrise-rde/getting-started/remote-dev-environments-overview#ways-to-use-rde). --- ## Remote Dev Environments FAQ ### Getting started **What is a Remote Dev Environment?** An on-demand cloud machine - macOS or Linux - running on the same infrastructure, stacks, and caches as Bitrise CI. You create a session in seconds, connect from your terminal, IDE, or an AI coding agent, and terminate it when you're done. The persistent disk is kept, so you can restore the session later and pick up where you left off. **How do I get access?** There are two ways to get RDE. - **Self-serve:** sign up on the [Remote Dev Environments page](https://bitrise.io/platform/remote-dev-environments). - **Enterprise:** RDE is enabled on your workspace through Bitrise sales. Contact Bitrise. Either way, you then need the **RDE User** role on the workspace: membership alone isn't enough. A workspace owner or manager grants it from **Settings** → **Collaboration**, per member or per group. If your workspace uses SCIM, assign the `rde:rde_admin` role from your identity provider. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). **What's the fastest way to try it?** Three commands: install the Bitrise CLI, run `bitrise-cli auth login`, then `bitrise-cli rde claude` from your repository folder. That creates a session, clones your current branch, and drops you into Claude Code on the cloud machine. See [Quickstart](/bitrise-rde/getting-started/quickstart). **Which machines can I get?** macOS on Apple silicon (M2 Pro, M4, M4 Pro) and Linux from 2 to 48 vCPUs, on shared or dedicated clusters. The exact stacks and machine types available depend on your workspace - check the in-product list when creating a session. For what each way of buying RDE includes, see [RDE pricing](https://bitrise.io/pricing#rde) for self-serve, or the [Bitrise pricing calculator](https://pricing-calculator.tools.bitrise.dev/calc) for Enterprise. ### Sessions, storage, and lifetime **What are the session states?** - **Running**: provisioned and connectable. - **Terminated**: the machine is stopped, and the session and its persistent disk are kept; fully reversible. - **Deleted**: permanently removed. You can only delete a session that's already terminated. **Will my session shut down on its own?** Yes, in two ways. Every session has an auto-terminate timer, defaulting to five days of inactivity. You can set it to anything up to 30 days, or turn it off so the session never auto-terminates. Sessions in free-trial workspaces are capped at eight hours and can't change this. Separately from that timer, Bitrise stops long-running machines for infrastructure maintenance from time to time. Those sessions are drained (shut down) and can be restarted afterwards, and turning the auto-terminate timer off doesn't exempt a session from it. In both cases, terminating is not deleting: your disk is preserved. **How long is my session kept after I terminate it?** Indefinitely, as long as you don't delete it and the stack it was created from is still available on Bitrise. There is no inactivity-based deletion of terminated sessions. **Can my session be deleted without me deleting it?** Yes, if the stack your session was created from is removed. Your session's disk holds only your changes on top of that stack image, so it can't be started once the image is gone. Stack removals follow the published [stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy), with at least four weeks' notice. Upcoming removals are listed on the [upcoming stack deprecations](https://stacks.bitrise.io/announcements/upcoming-stack-deprecations/) page, and you can [subscribe to RSS updates](https://stacks.bitrise.io/tips/get-notified/) to follow them. **What happens to my work if that happens?** It's permanently erased and can't be recovered. Commit your work to your repository, or export it, before the stack removal date. You can create a new session from a current stack at any time. **Can I move an existing session to a newer stack?** No. A session stays on the stack it was created from for its whole life. To move to a newer stack, create a new session from it and clone your repository again. **Is my session disk backed up?** No. Session disks are working storage, and not backed up. They aren't covered by a service-level commitment. Treat anything that exists only on a session disk as unsaved work. Push your branches. **What's actually on the persistent disk?** Only the changes made since the session was created - your clone, build outputs, local configuration - stored as a difference against the stack image. That's what makes restore fast, and why the session depends on that image continuing to exist. **Does session storage cost extra?** Session storage isn't billed separately today. Enterprise agreements define a storage allowance and how storage beyond it is handled. If you're on one, check your Order Form. **What happens to sessions when someone leaves the workspace?** Revoking a member's RDE access doesn't delete their sessions. Running sessions continue until they auto-terminate; terminated sessions keep their disk until someone deletes them. To reclaim the storage, delete the sessions explicitly. **Do sessions survive maintenance?** Long-running machines may be stopped for infrastructure maintenance. These sessions are drained (shut down) and can be restarted afterwards. **How long does a restore take?** Usually between roughly 20 seconds and a few minutes, depending on image size. ### Connecting **How do I connect to a session?** Four ways: - The browser-based web terminal on the session detail page. - SSH, using the address and one-time password shown there or from `bitrise-cli rde session view`. - VS Code, through **Open in VS Code** with the Remote-SSH extension. - VNC for a graphical desktop on macOS sessions. Linux sessions have no desktop, so VNC isn't available. See [Connecting to a session](/bitrise-rde/rde-options/connecting-to-a-session). **Can I connect without copying a password every time?** Yes. Register your SSH public key as a [saved input](/bitrise-rde/configuration/saved-inputs) and Bitrise adds it to the session's authorized keys. macOS sessions sign in as the `vagrant` user, Linux sessions as the `ubuntu` user. **Can I get an interactive shell from the CLI?** `bitrise-cli rde session exec` runs a single command and streams the output back: it isn't an interactive shell. For an interactive session, use SSH or the web terminal. **My remote command times out. Can I raise the limit?** Yes. `session exec` stops the remote command after 10 minutes by default. Use `--timeout 30m` for long builds, or `--timeout 0` to disable the cap. **How do I move files in and out?** Use `bitrise-cli rde session upload` and `bitrise-cli rde session download`. If you're working through an AI agent started by `bitrise-cli rde claude`, ask it in plain language. It can transfer files and open a VNC viewer on your local machine. A session is a normal machine you have SSH access to, so the tools you already use work too: - Copy single files or folders with `scp`, using the session's SSH address from the session detail page or `bitrise-cli rde session view`. - Keep a folder in sync with `rsync` over SSH. You can start it from your laptop or from inside the session, in either direction. - Pull straight from the internet inside the session with `curl`, `wget`, or `git clone`. For large dependencies and artifacts this is usually much faster than uploading from your laptop, because the session sits on Bitrise infrastructure. - Push results out from inside the session to wherever you already store them, such as your own object storage bucket or an artifact server. - Skip transferring altogether and edit in place with [VS Code Remote - SSH](/bitrise-rde/rde-options/connecting-to-a-session#vs-code-remote---ssh), which reads and writes files on the session directly. Register your SSH public key as a [saved input](/bitrise-rde/configuration/saved-inputs) first. Passwordless access is what makes scripted and repeated transfers practical, instead of copying a one-time password every time. **The macOS desktop locked over VNC. How do I get back in?** Use the VNC password shown on the session detail page in the RDE UI. ### Git and credentials **How do I clone private repositories?** Enable the [GitHub integration](/bitrise-rde/configuration/github-integration). Bitrise plants a short-lived GitHub token on each new session, issued through your personal GitHub App connection, so `git clone`, `git push`, and the `gh` CLI work over HTTPS without personal access tokens or SSH keys. Tokens are valid for at most eight hours and refresh automatically for the lifetime of the session, including across restores. No long-lived credential is stored on the machine. **I enabled it, but a clone fails with "repository not found."** The Bitrise GitHub App isn't installed on that repository or organization. Note that a workspace-level GitHub App connection doesn't count: this integration uses your **personal** connection under **Account settings** → **Connected accounts**. **Are commits attributed to me?** Yes, to your GitHub account, using your GitHub noreply address so your real email address is never exposed. **How do I store other credentials?** As [saved inputs](/bitrise-rde/configuration/saved-inputs): API tokens, SSH keys, agent credentials. They're scoped to your user account rather than a single workspace, and secret values are encrypted at rest. ### AI coding agents **Which agents can I run?** Claude Code is first-class: `bitrise-cli rde claude` creates a session, clones your branch, and starts the agent. Other agents can be installed from a [template](/bitrise-rde/configuration/templates) warmup script. Any assistant that supports the Model Context Protocol can drive sessions through the [RDE MCP server](/bitrise-rde/rde-options/bitrise-rde-mcp-server). **Do I need my own AI subscription?** Yes. Agents run on your own subscription or API key. On first use the CLI picks up your local Claude Code credential, or opens a browser so you can sign in. The credential is saved, so later sessions start already authenticated. **Can the agent reach my local machine?** Yes, over a secure connection the CLI keeps open while you work. The agent can open a VNC viewer pointed at the session's desktop and upload or download files. The VNC password stays local and is never sent to the session. **What if my connection drops?** The CLI reconnects automatically and the agent keeps running in the session. `bitrise-cli rde claude --continue` resumes your most recent session and conversation for that repository; `--resume` lets you pick from earlier ones. ### Capabilities and limits **Can I run Docker?** - Linux: yes, full Docker support. - macOS: no. Apple's virtualization doesn't expose nested virtualization, so Docker, OrbStack, and Android emulators can't run inside a macOS session. Use a Linux session for container work. **Does using RDE consume my CI build credits?** No. RDE is billed separately and doesn't draw down your build minutes or credits. **Can I reach a private network or VPN?** Yes, through custom scripts in your [template](/bitrise-rde/configuration/templates), the same way CI machines do. There's no dedicated Step or one-click setup yet. **Can several people share one session?** Not today. Each session is owned by the user who created it. **Is there an API?** Yes, the full session, template, and saved-input lifecycle is available. See [Remote Dev Environments API](/bitrise-rde/configuration/rde-api). ### Pricing **How is RDE priced?** RDE is billed separately from Bitrise CI and doesn't consume your build credits. There are two ways to buy it: - **Self-serve**: pricing is public. See [RDE pricing](https://bitrise.io/pricing#rde) and sign up from there. - **Enterprise**: pricing is based on committed capacity and goes through Bitrise sales. Model it with the [Bitrise pricing calculator](https://pricing-calculator.tools.bitrise.dev/calc), then contact Bitrise for a quote. --- ## Remote Dev Environments overview A Remote Dev Environment (RDE) is an on-demand cloud machine — macOS or Linux — that runs on the same infrastructure, stacks, and caches as Bitrise CI. You spin up a session in seconds, connect to it from your terminal, IDE, or an AI coding agent, and archive it when you're done. The persistent disk is kept, so you can restore the session and pick up where you left off, for as long as the stack it was created from is available. :::caution[Remote Dev Environments is in beta] Remote Dev Environments is a beta product. The features, APIs, and clients described here can change, and breaking changes can happen without prior notice. Don't rely on RDE for production-critical workflows yet. ::: ### Why use RDE A Remote Dev Environment gives you a powerful, pre-configured machine in the cloud without provisioning your own hardware. It's a good fit when you want to: - Develop on a much more powerful machine than your laptop, with your toolchain already installed and cached. - Run AI coding agents like Claude Code in a sandbox that can build and test your app, on your own API keys. - Reproduce a CI failure in an environment that matches the one your builds run in. - Spin up parallel, disposable environments for short-lived tasks and tear them down afterwards. - Push branches and open pull requests straight from the session: with the [GitHub integration](/bitrise-rde/configuration/github-integration), git and the GitHub CLI authenticate as you. Because RDE uses the same machines and stacks as Bitrise CI, the environment your code is written in matches the environment your code is tested in. ### Supported platforms RDE runs on production-grade Bitrise infrastructure in US and EU data centers: - **macOS**: Apple silicon machines (M2 Pro, M4, and M4 Pro) for iOS, macOS, and cross-platform work. macOS sessions also expose a graphical desktop over VNC. - **Linux**: machines from 2 to 48 vCPUs, on dedicated and shared clusters, with full Docker support. You choose the machine when you create a session, either directly or through a template. For the exact stacks and machine types available to you, check the in-product list when [creating a session](/bitrise-rde/rde-options/bitrise-rde-ui). ### Ways to use RDE You can create and connect to sessions through several clients. Pick the one that fits how you work — they all share the same sessions, templates, and saved inputs. - [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli): manage sessions from your terminal and start an AI coding agent in a session with a single command. This is the fastest way to get started. - [Bitrise RDE UI](/bitrise-rde/rde-options/bitrise-rde-ui): create and manage sessions, templates, and saved inputs from the browser, and connect with a built-in web terminal. - [MCP server](/bitrise-rde/rde-options/bitrise-rde-mcp-server): let any AI assistant that supports the Model Context Protocol create and drive sessions on your behalf. - [Bitrise VS Code plugin](/bitrise-rde/rde-options/bitrise-vscode-plugin): open a repository in a new session and edit it from VS Code. This client is coming soon. If you're not sure where to start, follow the [Quickstart](/bitrise-rde/getting-started/quickstart). ### What you need To use Remote Dev Environments, you need: - A Bitrise workspace with RDE access. Remote Dev Environments is in beta. If your workspace doesn't have access yet, contact Bitrise. - The **RDE User** role on that workspace. Members don't get it automatically — a workspace owner or manager grants it: [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). - A way to connect, depending on the client you choose: the Bitrise CLI, a supported AI assistant, or a browser. --- ## Remote Dev Environments --- ## Bitrise RDE CLI The Bitrise RDE CLI lets you manage Remote Dev Environments from your terminal: create and connect to sessions, run commands in them, transfer files, and start AI coding agents. The CLI is open source, and all RDE commands live under `bitrise-cli rde`. If you just want to get started fast, follow the [Quickstart](/bitrise-rde/getting-started/quickstart). This page is the broader reference for what the CLI can do. ### Installing the CLI Install the latest version with the install script: ```bash curl -fsSL https://app.bitrise.io/cli/install.sh | bash ``` This installs the `bitrise-cli` binary to `~/.local/bin`. Make sure that directory is on your `PATH`. You can also download a build from the [GitHub releases](https://github.com/bitrise-io/bitrise-cli/releases) or install from source with `go install github.com/bitrise-io/bitrise-cli@latest`. ### Signing in Sign in to your Bitrise account. This opens your browser to authenticate: ```bash bitrise-cli auth login ``` Check your status with `bitrise-cli auth status`, and sign out with `bitrise-cli auth logout`. For non-interactive use, such as CI, set the `BITRISE_TOKEN` environment variable to a personal access token, or pipe a token into `bitrise-cli auth login --with-token`. #### Choosing a workspace RDE commands run against a workspace. If you belong to exactly one, the CLI selects it automatically. If you belong to more than one, the CLI asks you to pick one. To skip the prompt, save a default: ```bash bitrise-cli config set default_workspace_id WORKSPACE_ID ``` For a single command, the `--workspace` flag takes precedence, followed by the `BITRISE_WORKSPACE_ID` environment variable, then the saved default. ### Managing sessions The `bitrise-cli rde session` commands cover the full session lifecycle. Commands that take a `SESSION_ID` also accept the session's name, as long as the name is unique. | Command | What it does | | --- | --- | | `bitrise-cli rde session create NAME` | Create a session from a `--template`, or without one by passing `--stack` and `--machine-type`. Add `--wait` to block until the session is running. | | `bitrise-cli rde session list` | List your sessions and their status. | | `bitrise-cli rde session view SESSION_ID` | Show a session's details, including connection credentials. | | `bitrise-cli rde session update SESSION_ID` | Rename a session, change its description, or adjust its auto-terminate timer. | | `bitrise-cli rde session exec SESSION_ID -- COMMAND` | Run a command in the session over SSH. See [Running commands in a session](#running-commands-in-a-session). | | `bitrise-cli rde session upload SESSION_ID LOCAL_PATH REMOTE_FOLDER` | Upload a file or folder into the session. | | `bitrise-cli rde session download SESSION_ID REMOTE_PATH LOCAL_PATH` | Download a file or folder from the session. | | `bitrise-cli rde session vnc SESSION_ID` | Print the session's VNC connection details, or tunnel them to a local port with `--forward` (macOS only). | | `bitrise-cli rde session open-vnc SESSION_ID` | Open the session's desktop in your default VNC viewer (macOS only). | | `bitrise-cli rde session logs SESSION_ID --stage startup` | Print the session's warmup or startup script logs. Add `--follow` to stream them live. | | `bitrise-cli rde session notifications SESSION_ID` | List events the session emitted, such as agent stops and permission prompts. | | `bitrise-cli rde session diff SESSION_ID` | Show how the session's template changed since the session was created. | | `bitrise-cli rde session terminate SESSION_ID` | Stop the machine but keep the session for later. | | `bitrise-cli rde session restore SESSION_ID` | Restart a terminated session from its persistent disk. Add `--wait` to block until it's running. | | `bitrise-cli rde session delete SESSION_ID` | Permanently delete a terminated session. | | `bitrise-cli rde session delete-terminated` | Permanently delete all terminated sessions in the workspace. | ### Running commands in a session `bitrise-cli rde session exec` runs a single command in a session and streams its output back, without opening an interactive shell. It's the main building block for scripting sessions and for letting AI agents drive them: ```bash bitrise-cli rde session exec SESSION_ID -- npm test ``` The command runs in a login shell, so the session's `PATH`, Homebrew packages, and language version managers are all available. If a local SSH agent is running, the CLI forwards it into the session, so Git over SSH inside the session uses your local keys. Everything after `--` is passed as a program with literal arguments. To use pipes, `&&`, or redirection, add `--shell` and quote the command: ```bash bitrise-cli rde session exec SESSION_ID --shell -- 'cd my-app && xcodebuild | xcpretty' ``` The most useful flags: - `--timeout`: the remote command is stopped after 10 minutes by default. Raise the cap for long builds (`--timeout 30m`) or disable it with `--timeout 0`. - `--env`: forward a local environment variable to the remote command (`--env NPM_TOKEN`), or set a literal value (`--env CI=1`). Forwarded values are never printed locally, but they are visible in the session's process list while the command runs. - `--output json`: emit a single JSON object with the exit code, stdout, and stderr — easy to parse from a script or an agent. To share a list of forwarded environment variables with your team, add them to `.bitrise/rde.yml` in your repository: ```yaml exec: env: - API_BASE_URL - NPM_TOKEN=abc123 ``` The `exec` command reads the file from the working directory or any parent folder and forwards the listed variables on every run. `--env` overrides a same-named entry, and `--no-env-file` skips the file entirely. ### Running AI coding agents The `bitrise-cli rde claude` command creates a session, clones your current repository branch into it, and drops you into Claude Code running on the cloud machine. While the agent works, the CLI keeps a secure connection open so it can open a VNC viewer or transfer files to and from your local machine. This is the recommended way to start. For the full walkthrough, see the [Quickstart](/bitrise-rde/getting-started/quickstart). Some behaviors worth knowing: - The CLI asks you to pick a stack and a machine type, and remembers your choice for the repository. Pass `--stack` and `--machine-type` to skip the prompts, for example in scripts. - If no Claude Code credential is saved for your workspace yet, the CLI picks up your local one, or opens the browser so you can create one, and saves it for future sessions. You can also manage the credential in the [Bitrise RDE UI](/bitrise-rde/rde-options/bitrise-rde-ui#authentication). - If the connection drops, the CLI reconnects automatically while Claude Code keeps running in the session. Press Ctrl-C during a reconnect to detach and leave the machine running. - When you exit Claude Code, the session is terminated automatically, but preserved so you can restore it later. To return to a session, use `bitrise-cli rde claude --continue` for the most recent one, or `bitrise-cli rde claude --resume` to pick from a list. Resuming reconnects to a running session, or restores a terminated one and continues the same Claude Code conversation. ### Templates, saved inputs, and machine options The CLI also manages the configuration objects behind your sessions: - `bitrise-cli rde template`: list, create, view, update, and delete [templates](/bitrise-rde/configuration/templates). - `bitrise-cli rde saved-input`: list, create, view, update, and delete [saved inputs](/bitrise-rde/configuration/saved-inputs). - `bitrise-cli rde stack list`: list the stacks available in your workspace. - `bitrise-cli rde machine-type list --stack STACK_ID`: list the machine types compatible with a given stack. ### Workspace usage Workspace owners and members who manage billing can check what the workspace's active sessions consume: ```bash bitrise-cli rde usage ``` The report is a point-in-time snapshot: active session counts and vCPU and memory totals split by OS, plus a per-user breakdown. Add `--output json` for a machine-readable version to use in scripts and automations. ### Full command reference Every command has detailed built-in help, written so that both people and AI agents can discover features from it. The help is updated together with the features themselves, so it's the most current reference: ```bash bitrise-cli rde --help bitrise-cli rde session exec --help ``` The generated reference for every command, flag, and argument lives in the open-source repository: [bitrise-io/bitrise-cli](https://github.com/bitrise-io/bitrise-cli/tree/main/docs/cli). --- ## MCP server for AI agents The Bitrise Dev Environments MCP server lets any AI assistant that supports the [Model Context Protocol](https://modelcontextprotocol.io) — such as Claude Code, Claude Desktop, Cursor, or VS Code — create and drive Remote Dev Environment sessions for you. The server is open source. ### Connection options There are two ways to connect to the MCP server: - **Hosted**: connect your assistant to `https://mcp-rde.bitrise.io` and sign in with your browser the first time. There's nothing to install, and it's the recommended option. - **Local**: run the server as a binary on your machine using a personal access token. This exposes the full tool set, including uploading and downloading files between the session and your computer. ### Adding the server to your AI assistant Set up the hosted server in the client you use: **Claude Code** ```bash claude mcp add --transport http bitrise-dev-environments https://mcp-rde.bitrise.io ``` Run `/mcp` and authenticate in your browser. **Cursor** Add the server to your `mcp.json`: ```json { "mcpServers": { "bitrise-dev-environments": { "url": "https://mcp-rde.bitrise.io" } } } ``` **VS Code** Add the server to your MCP configuration: ```json { "servers": { "bitrise-dev-environments": { "type": "http", "url": "https://mcp-rde.bitrise.io" } } } ``` ### Assistant capabilities Once connected, you can ask your assistant in plain language to: - Create, list, restore, terminate, and delete sessions. - Run shell commands in a session over SSH. - Take screenshots of, and control, the macOS desktop. - Open SSH or VNC remote access. - Report the workspace's active session and resource usage (workspace owners and billing managers only). - Upload and download files (local server only). For example: *"Spin up a macOS Xcode session, clone my repo, and run the unit tests."* ### Authentication * The hosted server uses browser-based sign-in, so there's no token to manage. * The local server authenticates with a Bitrise [personal access token](https://app.bitrise.io/me/account/security) set as the `BITRISE_TOKEN` environment variable. If you belong to more than one workspace, set `BITRISE_WORKSPACE_ID`. ### Learn more For the local setup, the full list of tools, and per-client install guides, see the open-source repository: [bitrise-io/bitrise-mcp-dev-environments](https://github.com/bitrise-io/bitrise-mcp-dev-environments). --- ## Bitrise RDE UI The Bitrise RDE UI is the web interface for Remote Dev Environments. It's the visual way to create and manage sessions, templates, and saved inputs, and it includes a built-in terminal so you can work in a session without leaving the browser. Open the **Remote Dev Environments** section of the Bitrise app to get started. If you don't see it, you don't have the **RDE User** role yet: ask a workspace owner or manager to grant it. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). ### Authentication You can configure your Claude Code credentials and passwordless SSH access on the **Saved inputs** page. Saved inputs are reusable credentials and values you store once and map into sessions. See [Saved inputs](/bitrise-rde/configuration/saved-inputs) for details. ### Creating a session 1. In the Remote Dev Environments section, click **New session**. 1. Set a session title, and optionally a description. The session title must be unique. 1. Optionally, enter an AI prompt to start Claude Code automatically when the session boots. This requires saved Claude Code credentials. 1. Choose when the session should auto-terminate. 1. Choose a template, or select **No template** and pick a stack and a machine type directly. 1. Fill in any required inputs. You can type a value or select an existing saved input. 1. Click **Create**. The session starts within a short while. When it's running, open it to connect. {/* TODO: screenshot of the New session form (capture at 1728×875 per the Style Guide) */} ### Managing sessions The **Sessions** list shows every session in the workspace, grouped by status, with search. From a session you can: - Restore a terminated session, or terminate a running one. - Permanently delete a terminated session. - Edit its name and description, and change its auto-terminate setting. ### Connecting to a session The session detail page is your connection hub. From it you can: - Open the **built-in web terminal**, with support for multiple tabs. - Copy the **SSH** and **VNC** credentials to connect from your own tools. - Use **Open in VS Code** to connect with the VS Code Remote - SSH extension. - Use **workspace-link buttons** to open a specific folder in your IDE. For details on each method, see [Connecting to a session](/bitrise-rde/rde-options/connecting-to-a-session). ### Templates You can create and manage reusable session configurations from the UI: see [Templates](/bitrise-rde/configuration/templates). ### Workspace usage The **Usage** page shows what the workspace's active sessions consume right now: session counts, vCPU and memory totals split by OS, and a per-user breakdown. Only workspace owners and members who can manage billing see the page. The same report is available programmatically: see [Workspace usage report](/bitrise-rde/configuration/rde-api#workspace-usage-report). --- ## Bitrise VS Code plugin The Bitrise VS Code plugin brings Remote Dev Environments into your editor. Instead of connecting to an existing session, you start from a local repository, and the plugin creates the session, clones your repository into it, and connects VS Code — so you edit, run terminals, and debug as if the code were on your own machine. ### Before you start You need: - A Bitrise workspace with RDE access. - VS Code. The plugin depends on the [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) extension, which it installs automatically. - For private repositories, a local SSH key so the session can clone your repository. ### Installing the plugin Install **Bitrise** from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=bitrise.bitrise), or search for `Bitrise` in the Extensions view in VS Code. After it installs, a **Bitrise** icon appears in the activity bar. ### Signing in 1. Open the **Bitrise** view from the activity bar. 1. Click **Sign in to Bitrise**. This opens your browser to authenticate. 1. Select the workspace to use. Your sessions appear once you select a workspace with RDE access. ### Opening a repository in a new session Use **Open Repo in New Session** — the **+** in the Sessions view — to create a session from a local repository. The plugin walks you through: 1. A name for the session. 1. The local repository to open. 1. The branch to work on. 1. The stack for the machine. 1. The machine type. The plugin then creates the session, clones your repository into it, and opens a remote VS Code window connected to the session. :::important[Only pushed commits are cloned] The plugin clones the pushed state of the branch you select. Local commits and uncommitted changes that you haven't pushed are not transferred to the session. ::: ### Managing sessions The **Sessions** view lists the sessions in your workspace. From it you can: - Open a running session in a remote window, or restore and open a terminated one. - Stop a running session. - Open a session in the [Bitrise RDE UI](/bitrise-rde/rde-options/bitrise-rde-ui). - Search your sessions. ### Quick configuration The **Configuration** view helps you set up your environment once, so new sessions are ready to use: - **Passwordless SSH**: registers your SSH public key as a [saved input](/bitrise-rde/configuration/saved-inputs) so you connect without a password. - **Claude Code**: saves a Claude Code credential so new sessions start with Claude Code already authenticated. - **SSH agent forwarding**: lets a session use your local Git keys to push and pull. --- ## Connecting to a session Once a session is running, you can connect to it in several ways. Which methods are available depends on the operating system: macOS sessions add a graphical desktop over VNC, while Linux sessions are terminal and IDE only. ### Web terminal The [Bitrise RDE UI](/bitrise-rde/rde-options/bitrise-rde-ui) includes a browser-based terminal on the session detail page. It connects straight to the machine, supports multiple tabs, and needs no local setup — it's the quickest way to run a command in a session. ### SSH Each session has an SSH address and a one-time password, shown on the session detail page and available from the CLI with `bitrise-cli rde session view`. Use them with any SSH client. For passwordless access, register your SSH public key as a [saved input](/bitrise-rde/configuration/saved-inputs). Bitrise adds it to the session's authorized keys, so you can connect without copying a password each time. macOS sessions sign in as the `vagrant` user and Linux sessions as the `ubuntu` user. To run a single command without opening an interactive shell, use [`bitrise-cli rde session exec`](/bitrise-rde/rde-options/bitrise-rde-cli#running-commands-in-a-session). ### VNC macOS sessions expose a graphical desktop over VNC, which is useful for watching a simulator or a GUI app. The session detail page shows the VNC address and credentials, and builds a `vnc://` link that opens your VNC viewer. From the CLI, run `bitrise-cli rde session open-vnc SESSION_ID` to open the viewer directly, or `bitrise-cli rde session vnc SESSION_ID` to print the connection details. If there's no direct network route to the session, `bitrise-cli rde session vnc SESSION_ID --forward 5901` tunnels the VNC endpoint to a local port over SSH. Linux sessions don't have a desktop, so VNC isn't available for them. ### VS Code Remote - SSH To edit code in a session from VS Code, use **Open in VS Code** on the session detail page. It opens VS Code with the [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) extension connected to the session. If the session's template defines workspace links, you can open a specific folder directly. The dedicated [Bitrise VS Code plugin](/bitrise-rde/rde-options/bitrise-vscode-plugin) can also create and manage sessions for you. ### Transferring files You can move files between your machine and a session at any time: - With the CLI, use `bitrise-cli rde session upload` and `bitrise-cli rde session download`. - With an AI coding agent started by `bitrise-cli rde claude`, just ask the agent to upload or download a file — see the [Quickstart](/bitrise-rde/getting-started/quickstart#let-the-agent-reach-your-machine). --- ## Building a Slack-native coding agent This recipe describes an architecture for a Slack-native coding agent: assign it a ticket or @mention it in a thread, and it reads the requirements, posts a plan, spins up a disposable dev machine, writes and tests the code, opens a pull request, reacts to review comments and CI results as they arrive, and cleans up after itself once the pull request merges. The core idea is a separation of concerns: a small, locked-down orchestrator lives in Slack and never touches code directly. It delegates all actual coding to disposable Remote Dev Environments (RDEs). An open source reference implementation of this architecture, **bitclaw**, is available at [github.com/bitrise-io/bitclaw-public](https://github.com/bitrise-io/bitclaw-public). For details, see [Reference implementation](#reference-implementation) below. ### What the agent does Typical requests sent to the agent in Slack: - Clean up a feature flag that's already fully rolled out. - Push a stalled pull request until CI turns green. - Upgrade a dependency, using a previous pull request as a reference for the pattern. - Investigate a support ticket. - Add more context to an error message surfaced in a monitoring tool. Assigning a ticket to the agent's user is enough to start work. It posts a short acknowledgment in a shared channel, then updates the thread only at milestones: plan, dev session created, code pushed, pull request opened, CI result, review feedback addressed, merged, cleanup done. It doesn't narrate every intermediate step. Both the pull request and the ticket are anchored to the thread that owns them, so review comments, CI results, and ticket transitions flow back into the session as they happen. The agent reacts to these events on its own: it addresses reviewer feedback, answers follow-up questions on the ticket, and once the merge lands, tears down its dev environment and transitions the ticket. The same loop scales to larger, longer-running work — a multi-file refactor that spans several days and multiple rounds of merge conflicts, for example — without requiring more from a human than periodic review. ### Why build a custom orchestrator An agent like this touches everything sensitive at once: source code, credentials, the ticket tracker, and — on public repositories — the open internet. A generic, off-the-shelf agent can't encode the things that make an agent trustworthy for a specific team: which authors it may listen to, which actions need a human's approval, what "done" means in your workflow. Owning the orchestrator keeps all of that as code you control: which tools the agent holds, trust rules written as executable checks rather than system-prompt instructions, and a workflow tuned to how your team actually works. The orchestrator itself doesn't need to be large. It can be a single small service, and — since it only relays, plans, and calls tools rather than executing code — it's a reasonable target to bootstrap using a coding agent in the same delegate-review-merge loop it will later run for others. ### Core principle: the orchestrator can't code The design has one load-bearing rule: **the orchestrator is not a coder.** - One Slack thread is one session, backed by one persistent conversation, so context isn't lost between messages, webhooks, and follow-ups that arrive days later. - Every capability is a narrowly scoped tool: post to Slack, read and manage pull requests, read the ticket tracker, query observability tooling for logs and metrics, and create and drive RDE sessions. - Pull requests and tickets are anchored to the thread that owns them, so a review comment, a CI result, or a ticket transition arrives as a message in the right conversation. The agent reacts to events instead of polling for them. - The orchestrator has no shell and no file access. It can't run code, and it can't read source code through the ticket tracker or source control APIs: deny those tools in code, not in the prompt. ``` Ticket assignment ────┐ Slack @mention ───────┼──► one Slack thread = one session (the orchestrator) Webhooks (PR, CI) ────┘ │ ▲ │ creates and drives │ review, CI, and ticket ▼ │ events route back RDE session ───── git push ──► pull request (coding agent + full toolchain) ``` ### Where Remote Dev Environments fit Everything a coding agent needs — cloning repositories, installing packages, running build tools and test suites, executing whatever a `Makefile` says — is exactly what shouldn't run on the machine holding the orchestrator's credentials. Give every task its own disposable machine instead: - **One template, one tool call.** Create every coding machine from a single pinned template: the stack, the machine type, and a warmup script that installs the coding agent, sets up a git-only SSH identity, and starts the agent in a persistent terminal session. Pass credentials through saved inputs and session inputs: encrypted, never baked into an image. - **A brief, not a babysitter.** Create each session with a self-contained task brief: the repository, the ticket, the acceptance criteria, the branch rules — plus one behavioral instruction: never block on input; pick the most defensible default, document the assumption in the commit message and pull request description, and continue. Pull request review is where a wrong assumption gets corrected. - **Isolation as the security model.** Give the coding agent a push-scoped SSH key and no API access to the ticket tracker or source control platform: git is its only interface to the outside world. Even if injected text in a codebase manipulates it, the blast radius is a pushed branch that still has to survive human review. The orchestrator's credentials never touch the machine, and the machine is deleted when the work is done. - **A dev environment that matches CI.** Run RDE sessions on the same infrastructure and stacks as your CI, so "the tests pass in the session" and "the tests pass in CI" are the same claim. When CI fails, relay the failing check into the session so the coding agent can reproduce it in a matching environment. - **One machine per task.** Running several tickets in parallel means several isolated environments with no contention. - **A standard tool interface.** Creating, driving, and deleting sessions are ordinary tool calls on the [RDE MCP server](/bitrise-rde/rde-options/bitrise-rde-mcp-server). Any AI assistant that speaks the Model Context Protocol can drive sessions the same way, so there's no bespoke integration to build. ### Best practices A few rules worth treating as non-negotiable when running an agent like this against real repositories: - **Put guardrails in code, not prompts.** A system prompt steers behavior; it doesn't enforce it. Which tools exist, whose text the agent may read, and what needs approval should be hard checks that a prompt injection can't talk its way past. - **Treat every near-miss as a guardrail gap.** If the agent ever merges its own pull request the moment it sees an approval, require an explicit human instruction to merge from then on. On public repositories, redact untrusted authors' text before it reaches the model, and gate every write visible to the outside world behind an approve/reject step. - **Keep humans on the two decisions that matter.** Merging, and anything the outside world can see. Planning, coding, testing, and replying to reviewers work better without a human in the loop. - **Make "stop" always work.** Handle a stop command outside the normal message queue so it interrupts a running turn instead of waiting behind it. - **Fail closed.** When the agent can't confirm an author is trusted, a repository is private, or a check succeeded, assume the unsafe answer and hold. - **Delegate the thinking, not just the typing.** Don't have the orchestrator read source code, even to plan. The coding agent, sitting in front of the full working tree inside the RDE, should plan its own work. The moment a task requires understanding code, it belongs in the RDE. ### Reference implementation **bitclaw** is an open source reference implementation of this architecture: [github.com/bitrise-io/bitclaw-public](https://github.com/bitrise-io/bitclaw-public). It's MIT-licensed and intended to be studied and adapted rather than run as-is in production: SQLite instead of a managed database, polling instead of a push channel, plain logs. Its README documents each guardrail together with the failure mode that motivated it. Setup is tiered, so you can see it respond in minutes and grow it into a coding agent from there: | Tier | You configure | The agent can | |---|---|---| | 1. Chat | A Slack app and an Anthropic API key | Answer when @mentioned in Slack | | 2. Code | A Bitrise token, workspace, and an RDE template | Clone repositories, write code, push branches | | 3. Ship | A GitHub token, a trusted org, and a webhook | Open pull requests, react to reviews and CI, merge on your go-ahead | Tier 1 is a single `docker run` with three environment variables: ```bash docker run -it --rm \ -v bitclaw-data:/data -v bitclaw-claude:/home/app/.claude \ -p 8080:8080 \ -e SLACK_BOT_TOKEN=xoxb-your-bot-token \ -e SLACK_APP_TOKEN=xapp-your-app-token \ -e ANTHROPIC_API_KEY=sk-ant-your-api-key \ bitriseio/bitclaw-public:latest ``` Tier 2 is the reason the repository exists: its `docs/rde-template.md` guide walks through building the coding-agent template — a warmup script and a handful of saved inputs — after which the bot delegates real coding work to RDE sessions. :::caution[Do your own threat modeling] bitclaw's guardrails were built against real incidents, but they're a reference, not a guarantee. Review the security model and adapt it to your own trust boundaries before pointing an autonomous agent at your repositories. ::: ### Next steps - [Quickstart](/bitrise-rde/getting-started/quickstart): create your first RDE session in three commands. - [Key concepts](/bitrise-rde/getting-started/key-concepts): sessions, templates, saved inputs, and the session lifecycle. - [Templates](/bitrise-rde/configuration/templates): define the reusable environment your coding agent runs in. - [Saved inputs](/bitrise-rde/configuration/saved-inputs): store the credentials your sessions need, once. - [MCP server for AI agents](/bitrise-rde/rde-options/bitrise-rde-mcp-server): the tool surface any agent can use to drive RDE. --- ## Docs changelog This page tracks documentation updates: new guides, updated procedures, and changes reflecting new or updated Bitrise features. Subscribe to RSS ### 2026 September #### Track Remote Dev Environments usage across API, CLI, MCP, and UI {#2026-09-01-track-remote-dev-environments-usage-across-api-cli-mcp-and-ui} You can now check RDE workspace usage through the REST API, the `rde usage` CLI command, the MCP server, or the UI. See [Remote Dev Environments API](/bitrise-rde/configuration/rde-api). ### 2026 August #### CodePush delta updates {#2026-08-31-codepush-delta-updates} Learn what delta updates are, why they matter, and which version Bitrise currently supports. See [Delta updates](/release-management/codepush/delta-updates). #### Enable Build Cache writes for React Native on non-Bitrise CI {#2026-08-26-enable-build-cache-writes-for-react-native-on-non-bitrise-ci} Docs now show how to pass `--cache-push` so a non-Bitrise CI provider can write to the Build Cache, not just read from it. See [Configuring the Build Cache for React Native in non-Bitrise CI environments](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-non-bitrise-ci-environments). #### GitHub stacked pull requests {#2026-08-25-github-stacked-pull-requests} Trigger conditions and `$BITRISEIO_GIT_BRANCH_DEST` now explain how Bitrise handles GitHub stacked pull requests, matching against the stack's base branch. See [About build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/about-build-triggers). #### Remote Dev Environments FAQ, and a corrected session retention model {#2026-08-24-remote-dev-environments-faq-and-a-corrected-session-retention-model} New [Remote Dev Environments FAQ](/bitrise-rde/getting-started/rde-faq) answers the most common questions about sessions, storage, connecting, credentials, AI coding agents, and limits. The session retention documentation was also corrected. Terminated sessions are not cleaned up after a fixed period: a session's persistent disk is kept until you delete it, or until the stack it was created from is removed under the [stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). [Key concepts](/bitrise-rde/getting-started/key-concepts) now also explains that a session stays permanently tied to the stack it was created from and can't be moved to a different one. #### Manage Remote Dev Environments access from Collaboration {#2026-08-14-manage-remote-dev-environments-access-from-collaboration} RDE is now a standalone product in workspace collaboration: grant or revoke the **RDE User** role for members and groups from the **Collaboration** page, or assign it through SCIM with `rde:rde_admin`. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). #### Utility builds beta for Pro plans {#2026-08-06-utility-builds-beta-for-pro-plans} Short Linux builds that run on the Linux Small machine type don't count against your build quota during the beta. See [Utility builds](/bitrise-ci/run-and-analyze-builds/utility-builds). #### Edit modular YAML in the Workflow Editor {#2026-08-05-edit-modular-yaml-in-the-workflow-editor} The Workflow Editor now loads every module of a configuration split with the `include` keyword, shows the merged result, and pushes your changes back to your repository in one step. See [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). ### 2026 July #### Linux tooling steps scoped to the Docker-based image {#2026-07-30-linux-tooling-steps-scoped-to-the-docker-based-image} The tooling-access steps for Build Hub Linux machines apply only to the deprecated Docker-based image. If you use `linux-bitvirt-2026`, you can skip them. See [Configuring Build Hub for GitHub Actions](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#enabling-linux-machines-to-access-tooling). #### Select Bazel RBE worker pools by name {#2026-07-30-select-bazel-rbe-worker-pools-by-name} Remote Build Execution for Bazel now routes builds with a single `Pool=` execution property, instead of separate architecture and OS properties. #### CodePush SDK setup steps rewritten {#2026-07-30-codepush-sdk-setup-steps-rewritten} The React Native and Expo setup guides now match the current CodePush SDK, with the Expo instructions first. See [Configuring your mobile app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). #### Bitrise CI API reference corrections {#2026-07-24-bitrise-ci-api-reference-corrections} The API documentation now covers the pipeline outgoing-webhook event type, the full set of app role groups, optional Android keystore parameters, and the correct build notification defaults. #### Configuration YAML reference gains missing limits {#2026-07-24-configuration-yaml-reference-gains-missing-limits} The reference now documents the `status_report_name` and `parallel` limits, trigger priority, and the values `should_always_run` actually accepts. #### Workspace invitations can be rate-limited {#2026-07-24-workspace-invitations-can-be-rate-limited} Invitations sent from Workspaces on non-paid plans may be rate-limited. See [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). #### Developing a new step guide rewritten {#2026-07-20-developing-a-new-step-guide-rewritten} The walkthrough for building your own Step has been rewritten, with inaccurate statements corrected and background material trimmed. #### RDE CLI docs refreshed to match current commands {#2026-07-14-rde-cli-docs-refreshed-to-match-current-commands} The RDE CLI reference now covers stack-based session creation, running commands in a session with `session exec`, VNC tunneling, workspace selection, and the reconnect behavior of `rde claude`. See [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli). #### Building a Slack-native coding agent {#2026-07-10-building-a-slack-native-coding-agent} A new recipe walks through a reference architecture for a Slack-native coding agent: a locked-down orchestrator that delegates coding work to disposable Remote Dev Environments, plus an open source reference implementation you can try. See [Building a Slack-native coding agent](/bitrise-rde/recipes/building-a-slack-native-coding-agent-recipe). #### Bitrise Desktop App for macOS {#2026-07-09-bitrise-for-mac-menu-bar-app-guide} A new guide covers the Bitrise Desktop App for macOS: installing it, signing in, selecting a workspace and project, configuring filters and notifications, and troubleshooting. See [Bitrise Desktop App for macOS](/bitrise-ci/run-and-analyze-builds/bitrise-desktop-app-for-macos). #### Product subscriptions can now be canceled independently {#2026-07-07-product-subscriptions-can-now-be-canceled-independently} Each product (Bitrise CI, Build Cache, Release Management, and so on) has its own independently cancellable subscription, and add-ons can be canceled on their own too. The docs now walk through the updated **Plan & Billing** cancellation flow. See [Workspace billing and invoicing](/bitrise-platform/workspaces/workspace-billing-and-invoicing). #### Bitrise MCP server drops self-registration tools {#2026-07-02-bitrise-mcp-server-drops-self-registration-tools} The `register` and `verify_registration` tools, along with the `registration` API group, are no longer part of the Bitrise MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools). ### 2026 June #### RDE API reference now available in-site {#2026-06-29-rde-api-reference-now-available-in-site} The Remote Dev Environments REST API reference is now part of docs.bitrise.io as a native interactive explorer, covering 42 endpoints across user, workspace, sessions, templates, and saved inputs. See [RDE API reference](/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api). #### Remote Dev Environments docs now available {#2026-06-29-remote-dev-environments-docs-now-available} Documentation for Bitrise Remote Dev Environments (RDE) is now available, covering key concepts, a quickstart, configuration options (templates, saved inputs), and the available interfaces: CLI, MCP server, UI, and VS Code plugin. See [Remote Dev Environments](/bitrise-rde). #### Agent onboarding guide updated with OAuth flow {#2026-06-26-agent-onboarding-guide-updated-with-oauth-flow} The [onboarding guide for AI agents](/bitrise-platform/ai/onboarding-for-agents) now covers the full OAuth sign-in flow in detail: how your agent triggers browser authorization, creating an account during sign-in, email confirmation for password-based accounts, and troubleshooting steps for common issues. #### Entra ID SCIM provisioning guide {#2026-06-23-entra-id-scim-provisioning-guide} You can now set up automatic user and group provisioning for your Bitrise workspace using Microsoft Entra ID SCIM. The guide covers generating SCIM credentials, configuring Entra ID, attribute mapping, group and deprovisioning behavior, and migrating existing workspace members. See [Entra ID SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-entra-id-scim-for-bitrise). #### Bitrise CI API reference is now interactive {#2026-06-22-bitrise-ci-api-reference-is-now-interactive} The Bitrise CI API reference is now available as a full interactive explorer at `/en/bitrise-api`, replacing the previous SwaggerUI embed. Endpoints are grouped by tag with a sidebar, and you can try requests directly from the docs. See [Bitrise CI API reference](/bitrise-api). #### CodePush CLI docs expanded with full reference {#2026-06-19-codepush-cli-docs-expanded-with-full-reference} The CodePush CLI documentation has been expanded and restructured. A new reference page covers all commands, global flags, environment variables, and exit codes. The [Using the CodePush CLI](/release-management/codepush/codepush-cli/using-the-codepush-cli) page now includes workflow examples, JSON output, and Bitrise CI integration details. The code signing page adds a directory naming warning and a React Native >= 0.61 Android setup note. See [CodePush CLI](/release-management/codepush/codepush-cli/about-the-codepush-cli). #### AI agent onboarding tip added to sign-up page {#2026-06-18-ai-agent-onboarding-tip-added-to-sign-up-page} The [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) page now includes a tip pointing AI agents and coding assistants to the [dedicated onboarding runbook](/bitrise-platform/ai/onboarding-for-agents), which covers how to create a Bitrise account and connect everything directly from an agent session without a website visit. #### GitHub App integration: event subscriptions clarified {#2026-06-17-github-app-integration-event-subscriptions-clarified} The [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) page now has an Event subscriptions section explaining that the Bitrise GitHub App subscribes to `push`, `pull_request`, and `issue_comment` events via GitHub's app installation mechanism, not through repo-level webhooks. The section also warns that any existing manual webhooks pointing to `hooks.bitrise.io` must be removed after switching to the GitHub App to avoid duplicate builds. #### Bitrise MCP: new registration tools and API group {#2026-06-15-bitrise-mcp-new-registration-tools-and-api-group} The Bitrise MCP server now includes a `registration` API group with two unauthenticated tools — `register` and `verify_registration` — that let an AI agent onboard a brand-new Bitrise user without a token. The agent sends a one-time password to the user's email via `register`, then calls `verify_registration` with the OTP to receive a personal access token. These tools are most useful with the remote (HTTP) MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools) for the full reference. #### Bitrise MCP: install guides added for six tools {#2026-06-15-bitrise-mcp-install-guides-added-for-six-tools} Step-by-step install guides for the Bitrise MCP server are now available for VS Code, Cursor, Claude, Windsurf, Kiro, Gemini CLI, and other Copilot-compatible IDEs. Each guide covers how to configure the MCP server and authenticate with your Bitrise token. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) to get started. #### Workflow Editor can now push bitrise.yml directly to the repository {#2026-06-11-workflow-editor-can-now-push-bitrise-yml-directly-to-the-repository} The Workflow Editor now supports pushing changes to a repository-stored `bitrise.yml` directly from the editor — either to the current branch or a new branch — without manually copying and committing. See [Storing an app's configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml) for the updated flow. #### Build Hub: Gradle dependency mirroring explained {#2026-06-10-build-hub-gradle-dependency-mirroring-explained} The Build Hub documentation now includes an explanation of how Gradle dependency mirroring works, giving you a clearer picture of caching behaviour for Gradle projects running on Build Hub. #### Configuration YAML docs updated for YAML/Visual mode switcher {#2026-06-09-configuration-yaml-docs-updated-for-yaml-visual-mode-switcher} References throughout the docs have been updated to reflect the new toggle between YAML and Visual editing modes in the Workflow Editor. Where instructions previously referred to the left navigation menu, they now point to the **YAML** toggle at the top of the editor. #### New guide: Maven Central repository manager {#2026-06-08-new-guide-maven-central-repository-manager} A new guide covering the Maven Central repository manager is now available under [Build Cache getting started](/bitrise-build-cache/getting-started-with-the-build-cache/maven-central-repository-manager). It explains how Bitrise's proxy cache works for Maven dependencies, covers special cases like dependency verification and custom Docker images, and documents the opt-out process. #### Bitrise MCP server: OAuth is now the primary authentication method {#2026-06-08-bitrise-mcp-server-oauth-is-now-the-primary-authentication-method} The Bitrise MCP server now uses OAuth as the primary authentication method. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) for the updated setup steps. ### 2026 May #### Build distribution: custom access links for installable artifacts {#2026-05-29-build-distribution-custom-access-links-for-installable-artifacts} In Release Management, you can now create shareable install links. See [Custom access links](/release-management/build-distribution/distributing-builds-to-testers#custom-access-link) for details. #### Modular YAML: increased file and nesting limits for GitHub users {#2026-05-28-modular-yaml-increased-file-and-nesting-limits-for-github-users} The modular YAML configuration guide has been updated to reflect the new, higher file count and nesting limits for GitHub users. See [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration) for the updated limits. #### Python projects now supported {#2026-05-20-python-projects-now-supported} Bitrise now detects Python projects automatically and offers default workflows. The [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) and [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guides have been updated to include Python. ### 2026 April #### Next.js and Flutter Web project types documented {#2026-04-20-next-js-and-flutter-web-project-types-documented} The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide and [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) page now cover Next.js (as an extension of Node.js) and Flutter Web project types. ### 2026 March #### M4 machine type added to build machine docs {#2026-03-30-m4-machine-type-added-to-build-machine-docs} The [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types) page now lists the M4 machine type alongside the existing M4 Pro, M2 Pro, and M1 options, with region availability for each. #### Ruby projects now supported {#2026-03-25-ruby-projects-now-supported} Bitrise now detects Ruby projects automatically and offers default workflows. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to include Ruby. #### Pro Trial: credit card required to access the full trial {#2026-03-24-pro-trial-credit-card-required-to-access-the-full-trial} New users now need to provide a valid credit card (which won't be charged) to access the full Pro Trial. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to explain this. #### New page: build artifact retention policy {#2026-03-20-new-page-build-artifact-retention-policy} A dedicated [Build artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy) page is now available, covering default retention periods by artifact type, extended retention options for enterprise customers, and the edge case around transferred projects. #### Xcode compilation cache: new flag to disable caching without disabling analytics {#2026-03-10-xcode-compilation-cache-new-flag-to-disable-caching-without-disabling-analytics} The [Xcode compilation cache FAQ](/bitrise-build-cache/build-cache-for-xcode/xcode-compilation-cache-faq) now documents the `--no-bitrise-build-cache` flag, which lets you disable caching temporarily while keeping analytics and build history intact. ### 2026 February #### Build Cache: clear cache button replaces Settings dropdown {#2026-02-20-build-cache-clear-cache-button-replaces-settings-dropdown} The [Clearing the Build Cache](/bitrise-build-cache/getting-started-with-the-build-cache/clearing-the-build-cache) guide has been updated to reflect the current UI: the Settings dropdown was replaced by a **Clear Cache** button. The guide includes a new screenshot and a note that clearing the cache requires Workspace owner permissions. #### New guide: Endpoint Detection and Response (EDR) on Bitrise {#2026-02-20-new-guide-endpoint-detection-and-response-edr-on-bitrise} A new page under Integrations explains how Bitrise uses Endpoint Detection and Response (EDR) as part of its corporate security program, and clarifies that EDR agents are not deployed on Bitrise-hosted CI runners. #### OIDC for AWS guide updated {#2026-02-13-oidc-for-aws-guide-updated} The [OIDC for AWS](/bitrise-platform/integrations/oidc-authentication/oidc-for-aws) guide has been updated with additional clarifications on configuration and usage. #### New guide: GitHub App migration API {#2026-02-03-new-guide-github-app-migration-api} A new guide explains how to use the Bitrise API to bulk-migrate projects from OAuth-based GitHub connections to the GitHub App integration, including caveats about reverting the migration. See [Adding and managing apps](/bitrise-ci/api/adding-and-managing-apps) for details. ### 2026 January #### Tool setup: new tool versions added {#2026-01-27-tool-setup-new-tool-versions-added} The [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions) guide has been updated with newly supported tool versions in the tool setup feature. #### Build artifact retention policy documented {#2026-01-19-build-artifact-retention-policy-documented} The [Build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) page now includes a section on the artifact retention policy, covering default retention periods by artifact type and options for Enterprise customers. The policy takes effect on March 31, 2026. #### Pipeline rebuild: dynamic parallel workflows explained {#2026-01-12-pipeline-rebuild-dynamic-parallel-workflows-explained} The guide on rebuilding failed pipelines now includes an explanation of how dynamic parallel Workflows affect rebuild options — specifically, when you can rebuild individual Workflows versus all unsuccessful ones. See [Rebuilding a failed build](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline) for details. --- ## Docs changelog(Bitrise-build-cache) This page tracks documentation updates: new guides, updated procedures, and changes reflecting new or updated Bitrise features. Subscribe to RSS ### 2026 September #### Track Remote Dev Environments usage across API, CLI, MCP, and UI {#2026-09-01-track-remote-dev-environments-usage-across-api-cli-mcp-and-ui} You can now check RDE workspace usage through the REST API, the `rde usage` CLI command, the MCP server, or the UI. See [Remote Dev Environments API](/bitrise-rde/configuration/rde-api). ### 2026 August #### CodePush delta updates {#2026-08-31-codepush-delta-updates} Learn what delta updates are, why they matter, and which version Bitrise currently supports. See [Delta updates](/release-management/codepush/delta-updates). #### Enable Build Cache writes for React Native on non-Bitrise CI {#2026-08-26-enable-build-cache-writes-for-react-native-on-non-bitrise-ci} Docs now show how to pass `--cache-push` so a non-Bitrise CI provider can write to the Build Cache, not just read from it. See [Configuring the Build Cache for React Native in non-Bitrise CI environments](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-non-bitrise-ci-environments). #### GitHub stacked pull requests {#2026-08-25-github-stacked-pull-requests} Trigger conditions and `$BITRISEIO_GIT_BRANCH_DEST` now explain how Bitrise handles GitHub stacked pull requests, matching against the stack's base branch. See [About build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/about-build-triggers). #### Remote Dev Environments FAQ, and a corrected session retention model {#2026-08-24-remote-dev-environments-faq-and-a-corrected-session-retention-model} New [Remote Dev Environments FAQ](/bitrise-rde/getting-started/rde-faq) answers the most common questions about sessions, storage, connecting, credentials, AI coding agents, and limits. The session retention documentation was also corrected. Terminated sessions are not cleaned up after a fixed period: a session's persistent disk is kept until you delete it, or until the stack it was created from is removed under the [stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). [Key concepts](/bitrise-rde/getting-started/key-concepts) now also explains that a session stays permanently tied to the stack it was created from and can't be moved to a different one. #### Manage Remote Dev Environments access from Collaboration {#2026-08-14-manage-remote-dev-environments-access-from-collaboration} RDE is now a standalone product in workspace collaboration: grant or revoke the **RDE User** role for members and groups from the **Collaboration** page, or assign it through SCIM with `rde:rde_admin`. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). #### Utility builds beta for Pro plans {#2026-08-06-utility-builds-beta-for-pro-plans} Short Linux builds that run on the Linux Small machine type don't count against your build quota during the beta. See [Utility builds](/bitrise-ci/run-and-analyze-builds/utility-builds). #### Edit modular YAML in the Workflow Editor {#2026-08-05-edit-modular-yaml-in-the-workflow-editor} The Workflow Editor now loads every module of a configuration split with the `include` keyword, shows the merged result, and pushes your changes back to your repository in one step. See [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). ### 2026 July #### Linux tooling steps scoped to the Docker-based image {#2026-07-30-linux-tooling-steps-scoped-to-the-docker-based-image} The tooling-access steps for Build Hub Linux machines apply only to the deprecated Docker-based image. If you use `linux-bitvirt-2026`, you can skip them. See [Configuring Build Hub for GitHub Actions](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#enabling-linux-machines-to-access-tooling). #### Select Bazel RBE worker pools by name {#2026-07-30-select-bazel-rbe-worker-pools-by-name} Remote Build Execution for Bazel now routes builds with a single `Pool=` execution property, instead of separate architecture and OS properties. #### CodePush SDK setup steps rewritten {#2026-07-30-codepush-sdk-setup-steps-rewritten} The React Native and Expo setup guides now match the current CodePush SDK, with the Expo instructions first. See [Configuring your mobile app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). #### Bitrise CI API reference corrections {#2026-07-24-bitrise-ci-api-reference-corrections} The API documentation now covers the pipeline outgoing-webhook event type, the full set of app role groups, optional Android keystore parameters, and the correct build notification defaults. #### Configuration YAML reference gains missing limits {#2026-07-24-configuration-yaml-reference-gains-missing-limits} The reference now documents the `status_report_name` and `parallel` limits, trigger priority, and the values `should_always_run` actually accepts. #### Workspace invitations can be rate-limited {#2026-07-24-workspace-invitations-can-be-rate-limited} Invitations sent from Workspaces on non-paid plans may be rate-limited. See [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). #### Developing a new step guide rewritten {#2026-07-20-developing-a-new-step-guide-rewritten} The walkthrough for building your own Step has been rewritten, with inaccurate statements corrected and background material trimmed. #### RDE CLI docs refreshed to match current commands {#2026-07-14-rde-cli-docs-refreshed-to-match-current-commands} The RDE CLI reference now covers stack-based session creation, running commands in a session with `session exec`, VNC tunneling, workspace selection, and the reconnect behavior of `rde claude`. See [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli). #### Building a Slack-native coding agent {#2026-07-10-building-a-slack-native-coding-agent} A new recipe walks through a reference architecture for a Slack-native coding agent: a locked-down orchestrator that delegates coding work to disposable Remote Dev Environments, plus an open source reference implementation you can try. See [Building a Slack-native coding agent](/bitrise-rde/recipes/building-a-slack-native-coding-agent-recipe). #### Bitrise Desktop App for macOS {#2026-07-09-bitrise-for-mac-menu-bar-app-guide} A new guide covers the Bitrise Desktop App for macOS: installing it, signing in, selecting a workspace and project, configuring filters and notifications, and troubleshooting. See [Bitrise Desktop App for macOS](/bitrise-ci/run-and-analyze-builds/bitrise-desktop-app-for-macos). #### Product subscriptions can now be canceled independently {#2026-07-07-product-subscriptions-can-now-be-canceled-independently} Each product (Bitrise CI, Build Cache, Release Management, and so on) has its own independently cancellable subscription, and add-ons can be canceled on their own too. The docs now walk through the updated **Plan & Billing** cancellation flow. See [Workspace billing and invoicing](/bitrise-platform/workspaces/workspace-billing-and-invoicing). #### Bitrise MCP server drops self-registration tools {#2026-07-02-bitrise-mcp-server-drops-self-registration-tools} The `register` and `verify_registration` tools, along with the `registration` API group, are no longer part of the Bitrise MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools). ### 2026 June #### RDE API reference now available in-site {#2026-06-29-rde-api-reference-now-available-in-site} The Remote Dev Environments REST API reference is now part of docs.bitrise.io as a native interactive explorer, covering 42 endpoints across user, workspace, sessions, templates, and saved inputs. See [RDE API reference](/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api). #### Remote Dev Environments docs now available {#2026-06-29-remote-dev-environments-docs-now-available} Documentation for Bitrise Remote Dev Environments (RDE) is now available, covering key concepts, a quickstart, configuration options (templates, saved inputs), and the available interfaces: CLI, MCP server, UI, and VS Code plugin. See [Remote Dev Environments](/bitrise-rde). #### Agent onboarding guide updated with OAuth flow {#2026-06-26-agent-onboarding-guide-updated-with-oauth-flow} The [onboarding guide for AI agents](/bitrise-platform/ai/onboarding-for-agents) now covers the full OAuth sign-in flow in detail: how your agent triggers browser authorization, creating an account during sign-in, email confirmation for password-based accounts, and troubleshooting steps for common issues. #### Entra ID SCIM provisioning guide {#2026-06-23-entra-id-scim-provisioning-guide} You can now set up automatic user and group provisioning for your Bitrise workspace using Microsoft Entra ID SCIM. The guide covers generating SCIM credentials, configuring Entra ID, attribute mapping, group and deprovisioning behavior, and migrating existing workspace members. See [Entra ID SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-entra-id-scim-for-bitrise). #### Bitrise CI API reference is now interactive {#2026-06-22-bitrise-ci-api-reference-is-now-interactive} The Bitrise CI API reference is now available as a full interactive explorer at `/en/bitrise-api`, replacing the previous SwaggerUI embed. Endpoints are grouped by tag with a sidebar, and you can try requests directly from the docs. See [Bitrise CI API reference](/bitrise-api). #### CodePush CLI docs expanded with full reference {#2026-06-19-codepush-cli-docs-expanded-with-full-reference} The CodePush CLI documentation has been expanded and restructured. A new reference page covers all commands, global flags, environment variables, and exit codes. The [Using the CodePush CLI](/release-management/codepush/codepush-cli/using-the-codepush-cli) page now includes workflow examples, JSON output, and Bitrise CI integration details. The code signing page adds a directory naming warning and a React Native >= 0.61 Android setup note. See [CodePush CLI](/release-management/codepush/codepush-cli/about-the-codepush-cli). #### AI agent onboarding tip added to sign-up page {#2026-06-18-ai-agent-onboarding-tip-added-to-sign-up-page} The [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) page now includes a tip pointing AI agents and coding assistants to the [dedicated onboarding runbook](/bitrise-platform/ai/onboarding-for-agents), which covers how to create a Bitrise account and connect everything directly from an agent session without a website visit. #### GitHub App integration: event subscriptions clarified {#2026-06-17-github-app-integration-event-subscriptions-clarified} The [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) page now has an Event subscriptions section explaining that the Bitrise GitHub App subscribes to `push`, `pull_request`, and `issue_comment` events via GitHub's app installation mechanism, not through repo-level webhooks. The section also warns that any existing manual webhooks pointing to `hooks.bitrise.io` must be removed after switching to the GitHub App to avoid duplicate builds. #### Bitrise MCP: new registration tools and API group {#2026-06-15-bitrise-mcp-new-registration-tools-and-api-group} The Bitrise MCP server now includes a `registration` API group with two unauthenticated tools — `register` and `verify_registration` — that let an AI agent onboard a brand-new Bitrise user without a token. The agent sends a one-time password to the user's email via `register`, then calls `verify_registration` with the OTP to receive a personal access token. These tools are most useful with the remote (HTTP) MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools) for the full reference. #### Bitrise MCP: install guides added for six tools {#2026-06-15-bitrise-mcp-install-guides-added-for-six-tools} Step-by-step install guides for the Bitrise MCP server are now available for VS Code, Cursor, Claude, Windsurf, Kiro, Gemini CLI, and other Copilot-compatible IDEs. Each guide covers how to configure the MCP server and authenticate with your Bitrise token. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) to get started. #### Workflow Editor can now push bitrise.yml directly to the repository {#2026-06-11-workflow-editor-can-now-push-bitrise-yml-directly-to-the-repository} The Workflow Editor now supports pushing changes to a repository-stored `bitrise.yml` directly from the editor — either to the current branch or a new branch — without manually copying and committing. See [Storing an app's configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml) for the updated flow. #### Build Hub: Gradle dependency mirroring explained {#2026-06-10-build-hub-gradle-dependency-mirroring-explained} The Build Hub documentation now includes an explanation of how Gradle dependency mirroring works, giving you a clearer picture of caching behaviour for Gradle projects running on Build Hub. #### Configuration YAML docs updated for YAML/Visual mode switcher {#2026-06-09-configuration-yaml-docs-updated-for-yaml-visual-mode-switcher} References throughout the docs have been updated to reflect the new toggle between YAML and Visual editing modes in the Workflow Editor. Where instructions previously referred to the left navigation menu, they now point to the **YAML** toggle at the top of the editor. #### New guide: Maven Central repository manager {#2026-06-08-new-guide-maven-central-repository-manager} A new guide covering the Maven Central repository manager is now available under [Build Cache getting started](/bitrise-build-cache/getting-started-with-the-build-cache/maven-central-repository-manager). It explains how Bitrise's proxy cache works for Maven dependencies, covers special cases like dependency verification and custom Docker images, and documents the opt-out process. #### Bitrise MCP server: OAuth is now the primary authentication method {#2026-06-08-bitrise-mcp-server-oauth-is-now-the-primary-authentication-method} The Bitrise MCP server now uses OAuth as the primary authentication method. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) for the updated setup steps. ### 2026 May #### Build distribution: custom access links for installable artifacts {#2026-05-29-build-distribution-custom-access-links-for-installable-artifacts} In Release Management, you can now create shareable install links. See [Custom access links](/release-management/build-distribution/distributing-builds-to-testers#custom-access-link) for details. #### Modular YAML: increased file and nesting limits for GitHub users {#2026-05-28-modular-yaml-increased-file-and-nesting-limits-for-github-users} The modular YAML configuration guide has been updated to reflect the new, higher file count and nesting limits for GitHub users. See [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration) for the updated limits. #### Python projects now supported {#2026-05-20-python-projects-now-supported} Bitrise now detects Python projects automatically and offers default workflows. The [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) and [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guides have been updated to include Python. ### 2026 April #### Next.js and Flutter Web project types documented {#2026-04-20-next-js-and-flutter-web-project-types-documented} The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide and [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) page now cover Next.js (as an extension of Node.js) and Flutter Web project types. ### 2026 March #### M4 machine type added to build machine docs {#2026-03-30-m4-machine-type-added-to-build-machine-docs} The [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types) page now lists the M4 machine type alongside the existing M4 Pro, M2 Pro, and M1 options, with region availability for each. #### Ruby projects now supported {#2026-03-25-ruby-projects-now-supported} Bitrise now detects Ruby projects automatically and offers default workflows. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to include Ruby. #### Pro Trial: credit card required to access the full trial {#2026-03-24-pro-trial-credit-card-required-to-access-the-full-trial} New users now need to provide a valid credit card (which won't be charged) to access the full Pro Trial. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to explain this. #### New page: build artifact retention policy {#2026-03-20-new-page-build-artifact-retention-policy} A dedicated [Build artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy) page is now available, covering default retention periods by artifact type, extended retention options for enterprise customers, and the edge case around transferred projects. #### Xcode compilation cache: new flag to disable caching without disabling analytics {#2026-03-10-xcode-compilation-cache-new-flag-to-disable-caching-without-disabling-analytics} The [Xcode compilation cache FAQ](/bitrise-build-cache/build-cache-for-xcode/xcode-compilation-cache-faq) now documents the `--no-bitrise-build-cache` flag, which lets you disable caching temporarily while keeping analytics and build history intact. ### 2026 February #### Build Cache: clear cache button replaces Settings dropdown {#2026-02-20-build-cache-clear-cache-button-replaces-settings-dropdown} The [Clearing the Build Cache](/bitrise-build-cache/getting-started-with-the-build-cache/clearing-the-build-cache) guide has been updated to reflect the current UI: the Settings dropdown was replaced by a **Clear Cache** button. The guide includes a new screenshot and a note that clearing the cache requires Workspace owner permissions. #### New guide: Endpoint Detection and Response (EDR) on Bitrise {#2026-02-20-new-guide-endpoint-detection-and-response-edr-on-bitrise} A new page under Integrations explains how Bitrise uses Endpoint Detection and Response (EDR) as part of its corporate security program, and clarifies that EDR agents are not deployed on Bitrise-hosted CI runners. #### OIDC for AWS guide updated {#2026-02-13-oidc-for-aws-guide-updated} The [OIDC for AWS](/bitrise-platform/integrations/oidc-authentication/oidc-for-aws) guide has been updated with additional clarifications on configuration and usage. #### New guide: GitHub App migration API {#2026-02-03-new-guide-github-app-migration-api} A new guide explains how to use the Bitrise API to bulk-migrate projects from OAuth-based GitHub connections to the GitHub App integration, including caveats about reverting the migration. See [Adding and managing apps](/bitrise-ci/api/adding-and-managing-apps) for details. ### 2026 January #### Tool setup: new tool versions added {#2026-01-27-tool-setup-new-tool-versions-added} The [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions) guide has been updated with newly supported tool versions in the tool setup feature. #### Build artifact retention policy documented {#2026-01-19-build-artifact-retention-policy-documented} The [Build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) page now includes a section on the artifact retention policy, covering default retention periods by artifact type and options for Enterprise customers. The policy takes effect on March 31, 2026. #### Pipeline rebuild: dynamic parallel workflows explained {#2026-01-12-pipeline-rebuild-dynamic-parallel-workflows-explained} The guide on rebuilding failed pipelines now includes an explanation of how dynamic parallel Workflows affect rebuild options — specifically, when you can rebuild individual Workflows versus all unsuccessful ones. See [Rebuilding a failed build](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline) for details. --- ## Docs changelog(Bitrise-build-hub) This page tracks documentation updates: new guides, updated procedures, and changes reflecting new or updated Bitrise features. Subscribe to RSS ### 2026 September #### Track Remote Dev Environments usage across API, CLI, MCP, and UI {#2026-09-01-track-remote-dev-environments-usage-across-api-cli-mcp-and-ui} You can now check RDE workspace usage through the REST API, the `rde usage` CLI command, the MCP server, or the UI. See [Remote Dev Environments API](/bitrise-rde/configuration/rde-api). ### 2026 August #### CodePush delta updates {#2026-08-31-codepush-delta-updates} Learn what delta updates are, why they matter, and which version Bitrise currently supports. See [Delta updates](/release-management/codepush/delta-updates). #### Enable Build Cache writes for React Native on non-Bitrise CI {#2026-08-26-enable-build-cache-writes-for-react-native-on-non-bitrise-ci} Docs now show how to pass `--cache-push` so a non-Bitrise CI provider can write to the Build Cache, not just read from it. See [Configuring the Build Cache for React Native in non-Bitrise CI environments](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-non-bitrise-ci-environments). #### GitHub stacked pull requests {#2026-08-25-github-stacked-pull-requests} Trigger conditions and `$BITRISEIO_GIT_BRANCH_DEST` now explain how Bitrise handles GitHub stacked pull requests, matching against the stack's base branch. See [About build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/about-build-triggers). #### Remote Dev Environments FAQ, and a corrected session retention model {#2026-08-24-remote-dev-environments-faq-and-a-corrected-session-retention-model} New [Remote Dev Environments FAQ](/bitrise-rde/getting-started/rde-faq) answers the most common questions about sessions, storage, connecting, credentials, AI coding agents, and limits. The session retention documentation was also corrected. Terminated sessions are not cleaned up after a fixed period: a session's persistent disk is kept until you delete it, or until the stack it was created from is removed under the [stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). [Key concepts](/bitrise-rde/getting-started/key-concepts) now also explains that a session stays permanently tied to the stack it was created from and can't be moved to a different one. #### Manage Remote Dev Environments access from Collaboration {#2026-08-14-manage-remote-dev-environments-access-from-collaboration} RDE is now a standalone product in workspace collaboration: grant or revoke the **RDE User** role for members and groups from the **Collaboration** page, or assign it through SCIM with `rde:rde_admin`. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). #### Utility builds beta for Pro plans {#2026-08-06-utility-builds-beta-for-pro-plans} Short Linux builds that run on the Linux Small machine type don't count against your build quota during the beta. See [Utility builds](/bitrise-ci/run-and-analyze-builds/utility-builds). #### Edit modular YAML in the Workflow Editor {#2026-08-05-edit-modular-yaml-in-the-workflow-editor} The Workflow Editor now loads every module of a configuration split with the `include` keyword, shows the merged result, and pushes your changes back to your repository in one step. See [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). ### 2026 July #### Linux tooling steps scoped to the Docker-based image {#2026-07-30-linux-tooling-steps-scoped-to-the-docker-based-image} The tooling-access steps for Build Hub Linux machines apply only to the deprecated Docker-based image. If you use `linux-bitvirt-2026`, you can skip them. See [Configuring Build Hub for GitHub Actions](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#enabling-linux-machines-to-access-tooling). #### Select Bazel RBE worker pools by name {#2026-07-30-select-bazel-rbe-worker-pools-by-name} Remote Build Execution for Bazel now routes builds with a single `Pool=` execution property, instead of separate architecture and OS properties. #### CodePush SDK setup steps rewritten {#2026-07-30-codepush-sdk-setup-steps-rewritten} The React Native and Expo setup guides now match the current CodePush SDK, with the Expo instructions first. See [Configuring your mobile app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). #### Bitrise CI API reference corrections {#2026-07-24-bitrise-ci-api-reference-corrections} The API documentation now covers the pipeline outgoing-webhook event type, the full set of app role groups, optional Android keystore parameters, and the correct build notification defaults. #### Configuration YAML reference gains missing limits {#2026-07-24-configuration-yaml-reference-gains-missing-limits} The reference now documents the `status_report_name` and `parallel` limits, trigger priority, and the values `should_always_run` actually accepts. #### Workspace invitations can be rate-limited {#2026-07-24-workspace-invitations-can-be-rate-limited} Invitations sent from Workspaces on non-paid plans may be rate-limited. See [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). #### Developing a new step guide rewritten {#2026-07-20-developing-a-new-step-guide-rewritten} The walkthrough for building your own Step has been rewritten, with inaccurate statements corrected and background material trimmed. #### RDE CLI docs refreshed to match current commands {#2026-07-14-rde-cli-docs-refreshed-to-match-current-commands} The RDE CLI reference now covers stack-based session creation, running commands in a session with `session exec`, VNC tunneling, workspace selection, and the reconnect behavior of `rde claude`. See [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli). #### Building a Slack-native coding agent {#2026-07-10-building-a-slack-native-coding-agent} A new recipe walks through a reference architecture for a Slack-native coding agent: a locked-down orchestrator that delegates coding work to disposable Remote Dev Environments, plus an open source reference implementation you can try. See [Building a Slack-native coding agent](/bitrise-rde/recipes/building-a-slack-native-coding-agent-recipe). #### Bitrise Desktop App for macOS {#2026-07-09-bitrise-for-mac-menu-bar-app-guide} A new guide covers the Bitrise Desktop App for macOS: installing it, signing in, selecting a workspace and project, configuring filters and notifications, and troubleshooting. See [Bitrise Desktop App for macOS](/bitrise-ci/run-and-analyze-builds/bitrise-desktop-app-for-macos). #### Product subscriptions can now be canceled independently {#2026-07-07-product-subscriptions-can-now-be-canceled-independently} Each product (Bitrise CI, Build Cache, Release Management, and so on) has its own independently cancellable subscription, and add-ons can be canceled on their own too. The docs now walk through the updated **Plan & Billing** cancellation flow. See [Workspace billing and invoicing](/bitrise-platform/workspaces/workspace-billing-and-invoicing). #### Bitrise MCP server drops self-registration tools {#2026-07-02-bitrise-mcp-server-drops-self-registration-tools} The `register` and `verify_registration` tools, along with the `registration` API group, are no longer part of the Bitrise MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools). ### 2026 June #### RDE API reference now available in-site {#2026-06-29-rde-api-reference-now-available-in-site} The Remote Dev Environments REST API reference is now part of docs.bitrise.io as a native interactive explorer, covering 42 endpoints across user, workspace, sessions, templates, and saved inputs. See [RDE API reference](/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api). #### Remote Dev Environments docs now available {#2026-06-29-remote-dev-environments-docs-now-available} Documentation for Bitrise Remote Dev Environments (RDE) is now available, covering key concepts, a quickstart, configuration options (templates, saved inputs), and the available interfaces: CLI, MCP server, UI, and VS Code plugin. See [Remote Dev Environments](/bitrise-rde). #### Agent onboarding guide updated with OAuth flow {#2026-06-26-agent-onboarding-guide-updated-with-oauth-flow} The [onboarding guide for AI agents](/bitrise-platform/ai/onboarding-for-agents) now covers the full OAuth sign-in flow in detail: how your agent triggers browser authorization, creating an account during sign-in, email confirmation for password-based accounts, and troubleshooting steps for common issues. #### Entra ID SCIM provisioning guide {#2026-06-23-entra-id-scim-provisioning-guide} You can now set up automatic user and group provisioning for your Bitrise workspace using Microsoft Entra ID SCIM. The guide covers generating SCIM credentials, configuring Entra ID, attribute mapping, group and deprovisioning behavior, and migrating existing workspace members. See [Entra ID SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-entra-id-scim-for-bitrise). #### Bitrise CI API reference is now interactive {#2026-06-22-bitrise-ci-api-reference-is-now-interactive} The Bitrise CI API reference is now available as a full interactive explorer at `/en/bitrise-api`, replacing the previous SwaggerUI embed. Endpoints are grouped by tag with a sidebar, and you can try requests directly from the docs. See [Bitrise CI API reference](/bitrise-api). #### CodePush CLI docs expanded with full reference {#2026-06-19-codepush-cli-docs-expanded-with-full-reference} The CodePush CLI documentation has been expanded and restructured. A new reference page covers all commands, global flags, environment variables, and exit codes. The [Using the CodePush CLI](/release-management/codepush/codepush-cli/using-the-codepush-cli) page now includes workflow examples, JSON output, and Bitrise CI integration details. The code signing page adds a directory naming warning and a React Native >= 0.61 Android setup note. See [CodePush CLI](/release-management/codepush/codepush-cli/about-the-codepush-cli). #### AI agent onboarding tip added to sign-up page {#2026-06-18-ai-agent-onboarding-tip-added-to-sign-up-page} The [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) page now includes a tip pointing AI agents and coding assistants to the [dedicated onboarding runbook](/bitrise-platform/ai/onboarding-for-agents), which covers how to create a Bitrise account and connect everything directly from an agent session without a website visit. #### GitHub App integration: event subscriptions clarified {#2026-06-17-github-app-integration-event-subscriptions-clarified} The [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) page now has an Event subscriptions section explaining that the Bitrise GitHub App subscribes to `push`, `pull_request`, and `issue_comment` events via GitHub's app installation mechanism, not through repo-level webhooks. The section also warns that any existing manual webhooks pointing to `hooks.bitrise.io` must be removed after switching to the GitHub App to avoid duplicate builds. #### Bitrise MCP: new registration tools and API group {#2026-06-15-bitrise-mcp-new-registration-tools-and-api-group} The Bitrise MCP server now includes a `registration` API group with two unauthenticated tools — `register` and `verify_registration` — that let an AI agent onboard a brand-new Bitrise user without a token. The agent sends a one-time password to the user's email via `register`, then calls `verify_registration` with the OTP to receive a personal access token. These tools are most useful with the remote (HTTP) MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools) for the full reference. #### Bitrise MCP: install guides added for six tools {#2026-06-15-bitrise-mcp-install-guides-added-for-six-tools} Step-by-step install guides for the Bitrise MCP server are now available for VS Code, Cursor, Claude, Windsurf, Kiro, Gemini CLI, and other Copilot-compatible IDEs. Each guide covers how to configure the MCP server and authenticate with your Bitrise token. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) to get started. #### Workflow Editor can now push bitrise.yml directly to the repository {#2026-06-11-workflow-editor-can-now-push-bitrise-yml-directly-to-the-repository} The Workflow Editor now supports pushing changes to a repository-stored `bitrise.yml` directly from the editor — either to the current branch or a new branch — without manually copying and committing. See [Storing an app's configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml) for the updated flow. #### Build Hub: Gradle dependency mirroring explained {#2026-06-10-build-hub-gradle-dependency-mirroring-explained} The Build Hub documentation now includes an explanation of how Gradle dependency mirroring works, giving you a clearer picture of caching behaviour for Gradle projects running on Build Hub. #### Configuration YAML docs updated for YAML/Visual mode switcher {#2026-06-09-configuration-yaml-docs-updated-for-yaml-visual-mode-switcher} References throughout the docs have been updated to reflect the new toggle between YAML and Visual editing modes in the Workflow Editor. Where instructions previously referred to the left navigation menu, they now point to the **YAML** toggle at the top of the editor. #### New guide: Maven Central repository manager {#2026-06-08-new-guide-maven-central-repository-manager} A new guide covering the Maven Central repository manager is now available under [Build Cache getting started](/bitrise-build-cache/getting-started-with-the-build-cache/maven-central-repository-manager). It explains how Bitrise's proxy cache works for Maven dependencies, covers special cases like dependency verification and custom Docker images, and documents the opt-out process. #### Bitrise MCP server: OAuth is now the primary authentication method {#2026-06-08-bitrise-mcp-server-oauth-is-now-the-primary-authentication-method} The Bitrise MCP server now uses OAuth as the primary authentication method. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) for the updated setup steps. ### 2026 May #### Build distribution: custom access links for installable artifacts {#2026-05-29-build-distribution-custom-access-links-for-installable-artifacts} In Release Management, you can now create shareable install links. See [Custom access links](/release-management/build-distribution/distributing-builds-to-testers#custom-access-link) for details. #### Modular YAML: increased file and nesting limits for GitHub users {#2026-05-28-modular-yaml-increased-file-and-nesting-limits-for-github-users} The modular YAML configuration guide has been updated to reflect the new, higher file count and nesting limits for GitHub users. See [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration) for the updated limits. #### Python projects now supported {#2026-05-20-python-projects-now-supported} Bitrise now detects Python projects automatically and offers default workflows. The [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) and [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guides have been updated to include Python. ### 2026 April #### Next.js and Flutter Web project types documented {#2026-04-20-next-js-and-flutter-web-project-types-documented} The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide and [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) page now cover Next.js (as an extension of Node.js) and Flutter Web project types. ### 2026 March #### M4 machine type added to build machine docs {#2026-03-30-m4-machine-type-added-to-build-machine-docs} The [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types) page now lists the M4 machine type alongside the existing M4 Pro, M2 Pro, and M1 options, with region availability for each. #### Ruby projects now supported {#2026-03-25-ruby-projects-now-supported} Bitrise now detects Ruby projects automatically and offers default workflows. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to include Ruby. #### Pro Trial: credit card required to access the full trial {#2026-03-24-pro-trial-credit-card-required-to-access-the-full-trial} New users now need to provide a valid credit card (which won't be charged) to access the full Pro Trial. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to explain this. #### New page: build artifact retention policy {#2026-03-20-new-page-build-artifact-retention-policy} A dedicated [Build artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy) page is now available, covering default retention periods by artifact type, extended retention options for enterprise customers, and the edge case around transferred projects. #### Xcode compilation cache: new flag to disable caching without disabling analytics {#2026-03-10-xcode-compilation-cache-new-flag-to-disable-caching-without-disabling-analytics} The [Xcode compilation cache FAQ](/bitrise-build-cache/build-cache-for-xcode/xcode-compilation-cache-faq) now documents the `--no-bitrise-build-cache` flag, which lets you disable caching temporarily while keeping analytics and build history intact. ### 2026 February #### Build Cache: clear cache button replaces Settings dropdown {#2026-02-20-build-cache-clear-cache-button-replaces-settings-dropdown} The [Clearing the Build Cache](/bitrise-build-cache/getting-started-with-the-build-cache/clearing-the-build-cache) guide has been updated to reflect the current UI: the Settings dropdown was replaced by a **Clear Cache** button. The guide includes a new screenshot and a note that clearing the cache requires Workspace owner permissions. #### New guide: Endpoint Detection and Response (EDR) on Bitrise {#2026-02-20-new-guide-endpoint-detection-and-response-edr-on-bitrise} A new page under Integrations explains how Bitrise uses Endpoint Detection and Response (EDR) as part of its corporate security program, and clarifies that EDR agents are not deployed on Bitrise-hosted CI runners. #### OIDC for AWS guide updated {#2026-02-13-oidc-for-aws-guide-updated} The [OIDC for AWS](/bitrise-platform/integrations/oidc-authentication/oidc-for-aws) guide has been updated with additional clarifications on configuration and usage. #### New guide: GitHub App migration API {#2026-02-03-new-guide-github-app-migration-api} A new guide explains how to use the Bitrise API to bulk-migrate projects from OAuth-based GitHub connections to the GitHub App integration, including caveats about reverting the migration. See [Adding and managing apps](/bitrise-ci/api/adding-and-managing-apps) for details. ### 2026 January #### Tool setup: new tool versions added {#2026-01-27-tool-setup-new-tool-versions-added} The [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions) guide has been updated with newly supported tool versions in the tool setup feature. #### Build artifact retention policy documented {#2026-01-19-build-artifact-retention-policy-documented} The [Build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) page now includes a section on the artifact retention policy, covering default retention periods by artifact type and options for Enterprise customers. The policy takes effect on March 31, 2026. #### Pipeline rebuild: dynamic parallel workflows explained {#2026-01-12-pipeline-rebuild-dynamic-parallel-workflows-explained} The guide on rebuilding failed pipelines now includes an explanation of how dynamic parallel Workflows affect rebuild options — specifically, when you can rebuild individual Workflows versus all unsuccessful ones. See [Rebuilding a failed build](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline) for details. --- ## Docs changelog(Bitrise-ci) This page tracks documentation updates: new guides, updated procedures, and changes reflecting new or updated Bitrise features. Subscribe to RSS ### 2026 September #### Track Remote Dev Environments usage across API, CLI, MCP, and UI {#2026-09-01-track-remote-dev-environments-usage-across-api-cli-mcp-and-ui} You can now check RDE workspace usage through the REST API, the `rde usage` CLI command, the MCP server, or the UI. See [Remote Dev Environments API](/bitrise-rde/configuration/rde-api). ### 2026 August #### CodePush delta updates {#2026-08-31-codepush-delta-updates} Learn what delta updates are, why they matter, and which version Bitrise currently supports. See [Delta updates](/release-management/codepush/delta-updates). #### Enable Build Cache writes for React Native on non-Bitrise CI {#2026-08-26-enable-build-cache-writes-for-react-native-on-non-bitrise-ci} Docs now show how to pass `--cache-push` so a non-Bitrise CI provider can write to the Build Cache, not just read from it. See [Configuring the Build Cache for React Native in non-Bitrise CI environments](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-non-bitrise-ci-environments). #### GitHub stacked pull requests {#2026-08-25-github-stacked-pull-requests} Trigger conditions and `$BITRISEIO_GIT_BRANCH_DEST` now explain how Bitrise handles GitHub stacked pull requests, matching against the stack's base branch. See [About build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/about-build-triggers). #### Remote Dev Environments FAQ, and a corrected session retention model {#2026-08-24-remote-dev-environments-faq-and-a-corrected-session-retention-model} New [Remote Dev Environments FAQ](/bitrise-rde/getting-started/rde-faq) answers the most common questions about sessions, storage, connecting, credentials, AI coding agents, and limits. The session retention documentation was also corrected. Terminated sessions are not cleaned up after a fixed period: a session's persistent disk is kept until you delete it, or until the stack it was created from is removed under the [stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). [Key concepts](/bitrise-rde/getting-started/key-concepts) now also explains that a session stays permanently tied to the stack it was created from and can't be moved to a different one. #### Manage Remote Dev Environments access from Collaboration {#2026-08-14-manage-remote-dev-environments-access-from-collaboration} RDE is now a standalone product in workspace collaboration: grant or revoke the **RDE User** role for members and groups from the **Collaboration** page, or assign it through SCIM with `rde:rde_admin`. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). #### Utility builds beta for Pro plans {#2026-08-06-utility-builds-beta-for-pro-plans} Short Linux builds that run on the Linux Small machine type don't count against your build quota during the beta. See [Utility builds](/bitrise-ci/run-and-analyze-builds/utility-builds). #### Edit modular YAML in the Workflow Editor {#2026-08-05-edit-modular-yaml-in-the-workflow-editor} The Workflow Editor now loads every module of a configuration split with the `include` keyword, shows the merged result, and pushes your changes back to your repository in one step. See [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). ### 2026 July #### Linux tooling steps scoped to the Docker-based image {#2026-07-30-linux-tooling-steps-scoped-to-the-docker-based-image} The tooling-access steps for Build Hub Linux machines apply only to the deprecated Docker-based image. If you use `linux-bitvirt-2026`, you can skip them. See [Configuring Build Hub for GitHub Actions](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#enabling-linux-machines-to-access-tooling). #### Select Bazel RBE worker pools by name {#2026-07-30-select-bazel-rbe-worker-pools-by-name} Remote Build Execution for Bazel now routes builds with a single `Pool=` execution property, instead of separate architecture and OS properties. #### CodePush SDK setup steps rewritten {#2026-07-30-codepush-sdk-setup-steps-rewritten} The React Native and Expo setup guides now match the current CodePush SDK, with the Expo instructions first. See [Configuring your mobile app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). #### Bitrise CI API reference corrections {#2026-07-24-bitrise-ci-api-reference-corrections} The API documentation now covers the pipeline outgoing-webhook event type, the full set of app role groups, optional Android keystore parameters, and the correct build notification defaults. #### Configuration YAML reference gains missing limits {#2026-07-24-configuration-yaml-reference-gains-missing-limits} The reference now documents the `status_report_name` and `parallel` limits, trigger priority, and the values `should_always_run` actually accepts. #### Workspace invitations can be rate-limited {#2026-07-24-workspace-invitations-can-be-rate-limited} Invitations sent from Workspaces on non-paid plans may be rate-limited. See [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). #### Developing a new step guide rewritten {#2026-07-20-developing-a-new-step-guide-rewritten} The walkthrough for building your own Step has been rewritten, with inaccurate statements corrected and background material trimmed. #### RDE CLI docs refreshed to match current commands {#2026-07-14-rde-cli-docs-refreshed-to-match-current-commands} The RDE CLI reference now covers stack-based session creation, running commands in a session with `session exec`, VNC tunneling, workspace selection, and the reconnect behavior of `rde claude`. See [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli). #### Building a Slack-native coding agent {#2026-07-10-building-a-slack-native-coding-agent} A new recipe walks through a reference architecture for a Slack-native coding agent: a locked-down orchestrator that delegates coding work to disposable Remote Dev Environments, plus an open source reference implementation you can try. See [Building a Slack-native coding agent](/bitrise-rde/recipes/building-a-slack-native-coding-agent-recipe). #### Bitrise Desktop App for macOS {#2026-07-09-bitrise-for-mac-menu-bar-app-guide} A new guide covers the Bitrise Desktop App for macOS: installing it, signing in, selecting a workspace and project, configuring filters and notifications, and troubleshooting. See [Bitrise Desktop App for macOS](/bitrise-ci/run-and-analyze-builds/bitrise-desktop-app-for-macos). #### Product subscriptions can now be canceled independently {#2026-07-07-product-subscriptions-can-now-be-canceled-independently} Each product (Bitrise CI, Build Cache, Release Management, and so on) has its own independently cancellable subscription, and add-ons can be canceled on their own too. The docs now walk through the updated **Plan & Billing** cancellation flow. See [Workspace billing and invoicing](/bitrise-platform/workspaces/workspace-billing-and-invoicing). #### Bitrise MCP server drops self-registration tools {#2026-07-02-bitrise-mcp-server-drops-self-registration-tools} The `register` and `verify_registration` tools, along with the `registration` API group, are no longer part of the Bitrise MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools). ### 2026 June #### RDE API reference now available in-site {#2026-06-29-rde-api-reference-now-available-in-site} The Remote Dev Environments REST API reference is now part of docs.bitrise.io as a native interactive explorer, covering 42 endpoints across user, workspace, sessions, templates, and saved inputs. See [RDE API reference](/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api). #### Remote Dev Environments docs now available {#2026-06-29-remote-dev-environments-docs-now-available} Documentation for Bitrise Remote Dev Environments (RDE) is now available, covering key concepts, a quickstart, configuration options (templates, saved inputs), and the available interfaces: CLI, MCP server, UI, and VS Code plugin. See [Remote Dev Environments](/bitrise-rde). #### Agent onboarding guide updated with OAuth flow {#2026-06-26-agent-onboarding-guide-updated-with-oauth-flow} The [onboarding guide for AI agents](/bitrise-platform/ai/onboarding-for-agents) now covers the full OAuth sign-in flow in detail: how your agent triggers browser authorization, creating an account during sign-in, email confirmation for password-based accounts, and troubleshooting steps for common issues. #### Entra ID SCIM provisioning guide {#2026-06-23-entra-id-scim-provisioning-guide} You can now set up automatic user and group provisioning for your Bitrise workspace using Microsoft Entra ID SCIM. The guide covers generating SCIM credentials, configuring Entra ID, attribute mapping, group and deprovisioning behavior, and migrating existing workspace members. See [Entra ID SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-entra-id-scim-for-bitrise). #### Bitrise CI API reference is now interactive {#2026-06-22-bitrise-ci-api-reference-is-now-interactive} The Bitrise CI API reference is now available as a full interactive explorer at `/en/bitrise-api`, replacing the previous SwaggerUI embed. Endpoints are grouped by tag with a sidebar, and you can try requests directly from the docs. See [Bitrise CI API reference](/bitrise-api). #### CodePush CLI docs expanded with full reference {#2026-06-19-codepush-cli-docs-expanded-with-full-reference} The CodePush CLI documentation has been expanded and restructured. A new reference page covers all commands, global flags, environment variables, and exit codes. The [Using the CodePush CLI](/release-management/codepush/codepush-cli/using-the-codepush-cli) page now includes workflow examples, JSON output, and Bitrise CI integration details. The code signing page adds a directory naming warning and a React Native >= 0.61 Android setup note. See [CodePush CLI](/release-management/codepush/codepush-cli/about-the-codepush-cli). #### AI agent onboarding tip added to sign-up page {#2026-06-18-ai-agent-onboarding-tip-added-to-sign-up-page} The [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) page now includes a tip pointing AI agents and coding assistants to the [dedicated onboarding runbook](/bitrise-platform/ai/onboarding-for-agents), which covers how to create a Bitrise account and connect everything directly from an agent session without a website visit. #### GitHub App integration: event subscriptions clarified {#2026-06-17-github-app-integration-event-subscriptions-clarified} The [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) page now has an Event subscriptions section explaining that the Bitrise GitHub App subscribes to `push`, `pull_request`, and `issue_comment` events via GitHub's app installation mechanism, not through repo-level webhooks. The section also warns that any existing manual webhooks pointing to `hooks.bitrise.io` must be removed after switching to the GitHub App to avoid duplicate builds. #### Bitrise MCP: new registration tools and API group {#2026-06-15-bitrise-mcp-new-registration-tools-and-api-group} The Bitrise MCP server now includes a `registration` API group with two unauthenticated tools — `register` and `verify_registration` — that let an AI agent onboard a brand-new Bitrise user without a token. The agent sends a one-time password to the user's email via `register`, then calls `verify_registration` with the OTP to receive a personal access token. These tools are most useful with the remote (HTTP) MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools) for the full reference. #### Bitrise MCP: install guides added for six tools {#2026-06-15-bitrise-mcp-install-guides-added-for-six-tools} Step-by-step install guides for the Bitrise MCP server are now available for VS Code, Cursor, Claude, Windsurf, Kiro, Gemini CLI, and other Copilot-compatible IDEs. Each guide covers how to configure the MCP server and authenticate with your Bitrise token. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) to get started. #### Workflow Editor can now push bitrise.yml directly to the repository {#2026-06-11-workflow-editor-can-now-push-bitrise-yml-directly-to-the-repository} The Workflow Editor now supports pushing changes to a repository-stored `bitrise.yml` directly from the editor — either to the current branch or a new branch — without manually copying and committing. See [Storing an app's configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml) for the updated flow. #### Build Hub: Gradle dependency mirroring explained {#2026-06-10-build-hub-gradle-dependency-mirroring-explained} The Build Hub documentation now includes an explanation of how Gradle dependency mirroring works, giving you a clearer picture of caching behaviour for Gradle projects running on Build Hub. #### Configuration YAML docs updated for YAML/Visual mode switcher {#2026-06-09-configuration-yaml-docs-updated-for-yaml-visual-mode-switcher} References throughout the docs have been updated to reflect the new toggle between YAML and Visual editing modes in the Workflow Editor. Where instructions previously referred to the left navigation menu, they now point to the **YAML** toggle at the top of the editor. #### New guide: Maven Central repository manager {#2026-06-08-new-guide-maven-central-repository-manager} A new guide covering the Maven Central repository manager is now available under [Build Cache getting started](/bitrise-build-cache/getting-started-with-the-build-cache/maven-central-repository-manager). It explains how Bitrise's proxy cache works for Maven dependencies, covers special cases like dependency verification and custom Docker images, and documents the opt-out process. #### Bitrise MCP server: OAuth is now the primary authentication method {#2026-06-08-bitrise-mcp-server-oauth-is-now-the-primary-authentication-method} The Bitrise MCP server now uses OAuth as the primary authentication method. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) for the updated setup steps. ### 2026 May #### Build distribution: custom access links for installable artifacts {#2026-05-29-build-distribution-custom-access-links-for-installable-artifacts} In Release Management, you can now create shareable install links. See [Custom access links](/release-management/build-distribution/distributing-builds-to-testers#custom-access-link) for details. #### Modular YAML: increased file and nesting limits for GitHub users {#2026-05-28-modular-yaml-increased-file-and-nesting-limits-for-github-users} The modular YAML configuration guide has been updated to reflect the new, higher file count and nesting limits for GitHub users. See [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration) for the updated limits. #### Python projects now supported {#2026-05-20-python-projects-now-supported} Bitrise now detects Python projects automatically and offers default workflows. The [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) and [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guides have been updated to include Python. ### 2026 April #### Next.js and Flutter Web project types documented {#2026-04-20-next-js-and-flutter-web-project-types-documented} The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide and [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) page now cover Next.js (as an extension of Node.js) and Flutter Web project types. ### 2026 March #### M4 machine type added to build machine docs {#2026-03-30-m4-machine-type-added-to-build-machine-docs} The [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types) page now lists the M4 machine type alongside the existing M4 Pro, M2 Pro, and M1 options, with region availability for each. #### Ruby projects now supported {#2026-03-25-ruby-projects-now-supported} Bitrise now detects Ruby projects automatically and offers default workflows. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to include Ruby. #### Pro Trial: credit card required to access the full trial {#2026-03-24-pro-trial-credit-card-required-to-access-the-full-trial} New users now need to provide a valid credit card (which won't be charged) to access the full Pro Trial. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to explain this. #### New page: build artifact retention policy {#2026-03-20-new-page-build-artifact-retention-policy} A dedicated [Build artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy) page is now available, covering default retention periods by artifact type, extended retention options for enterprise customers, and the edge case around transferred projects. #### Xcode compilation cache: new flag to disable caching without disabling analytics {#2026-03-10-xcode-compilation-cache-new-flag-to-disable-caching-without-disabling-analytics} The [Xcode compilation cache FAQ](/bitrise-build-cache/build-cache-for-xcode/xcode-compilation-cache-faq) now documents the `--no-bitrise-build-cache` flag, which lets you disable caching temporarily while keeping analytics and build history intact. ### 2026 February #### Build Cache: clear cache button replaces Settings dropdown {#2026-02-20-build-cache-clear-cache-button-replaces-settings-dropdown} The [Clearing the Build Cache](/bitrise-build-cache/getting-started-with-the-build-cache/clearing-the-build-cache) guide has been updated to reflect the current UI: the Settings dropdown was replaced by a **Clear Cache** button. The guide includes a new screenshot and a note that clearing the cache requires Workspace owner permissions. #### New guide: Endpoint Detection and Response (EDR) on Bitrise {#2026-02-20-new-guide-endpoint-detection-and-response-edr-on-bitrise} A new page under Integrations explains how Bitrise uses Endpoint Detection and Response (EDR) as part of its corporate security program, and clarifies that EDR agents are not deployed on Bitrise-hosted CI runners. #### OIDC for AWS guide updated {#2026-02-13-oidc-for-aws-guide-updated} The [OIDC for AWS](/bitrise-platform/integrations/oidc-authentication/oidc-for-aws) guide has been updated with additional clarifications on configuration and usage. #### New guide: GitHub App migration API {#2026-02-03-new-guide-github-app-migration-api} A new guide explains how to use the Bitrise API to bulk-migrate projects from OAuth-based GitHub connections to the GitHub App integration, including caveats about reverting the migration. See [Adding and managing apps](/bitrise-ci/api/adding-and-managing-apps) for details. ### 2026 January #### Tool setup: new tool versions added {#2026-01-27-tool-setup-new-tool-versions-added} The [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions) guide has been updated with newly supported tool versions in the tool setup feature. #### Build artifact retention policy documented {#2026-01-19-build-artifact-retention-policy-documented} The [Build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) page now includes a section on the artifact retention policy, covering default retention periods by artifact type and options for Enterprise customers. The policy takes effect on March 31, 2026. #### Pipeline rebuild: dynamic parallel workflows explained {#2026-01-12-pipeline-rebuild-dynamic-parallel-workflows-explained} The guide on rebuilding failed pipelines now includes an explanation of how dynamic parallel Workflows affect rebuild options — specifically, when you can rebuild individual Workflows versus all unsuccessful ones. See [Rebuilding a failed build](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline) for details. --- ## Docs changelog(Bitrise-platform) This page tracks documentation updates: new guides, updated procedures, and changes reflecting new or updated Bitrise features. Subscribe to RSS ### 2026 September #### Track Remote Dev Environments usage across API, CLI, MCP, and UI {#2026-09-01-track-remote-dev-environments-usage-across-api-cli-mcp-and-ui} You can now check RDE workspace usage through the REST API, the `rde usage` CLI command, the MCP server, or the UI. See [Remote Dev Environments API](/bitrise-rde/configuration/rde-api). ### 2026 August #### CodePush delta updates {#2026-08-31-codepush-delta-updates} Learn what delta updates are, why they matter, and which version Bitrise currently supports. See [Delta updates](/release-management/codepush/delta-updates). #### Enable Build Cache writes for React Native on non-Bitrise CI {#2026-08-26-enable-build-cache-writes-for-react-native-on-non-bitrise-ci} Docs now show how to pass `--cache-push` so a non-Bitrise CI provider can write to the Build Cache, not just read from it. See [Configuring the Build Cache for React Native in non-Bitrise CI environments](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-non-bitrise-ci-environments). #### GitHub stacked pull requests {#2026-08-25-github-stacked-pull-requests} Trigger conditions and `$BITRISEIO_GIT_BRANCH_DEST` now explain how Bitrise handles GitHub stacked pull requests, matching against the stack's base branch. See [About build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/about-build-triggers). #### Remote Dev Environments FAQ, and a corrected session retention model {#2026-08-24-remote-dev-environments-faq-and-a-corrected-session-retention-model} New [Remote Dev Environments FAQ](/bitrise-rde/getting-started/rde-faq) answers the most common questions about sessions, storage, connecting, credentials, AI coding agents, and limits. The session retention documentation was also corrected. Terminated sessions are not cleaned up after a fixed period: a session's persistent disk is kept until you delete it, or until the stack it was created from is removed under the [stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). [Key concepts](/bitrise-rde/getting-started/key-concepts) now also explains that a session stays permanently tied to the stack it was created from and can't be moved to a different one. #### Manage Remote Dev Environments access from Collaboration {#2026-08-14-manage-remote-dev-environments-access-from-collaboration} RDE is now a standalone product in workspace collaboration: grant or revoke the **RDE User** role for members and groups from the **Collaboration** page, or assign it through SCIM with `rde:rde_admin`. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). #### Utility builds beta for Pro plans {#2026-08-06-utility-builds-beta-for-pro-plans} Short Linux builds that run on the Linux Small machine type don't count against your build quota during the beta. See [Utility builds](/bitrise-ci/run-and-analyze-builds/utility-builds). #### Edit modular YAML in the Workflow Editor {#2026-08-05-edit-modular-yaml-in-the-workflow-editor} The Workflow Editor now loads every module of a configuration split with the `include` keyword, shows the merged result, and pushes your changes back to your repository in one step. See [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). ### 2026 July #### Linux tooling steps scoped to the Docker-based image {#2026-07-30-linux-tooling-steps-scoped-to-the-docker-based-image} The tooling-access steps for Build Hub Linux machines apply only to the deprecated Docker-based image. If you use `linux-bitvirt-2026`, you can skip them. See [Configuring Build Hub for GitHub Actions](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#enabling-linux-machines-to-access-tooling). #### Select Bazel RBE worker pools by name {#2026-07-30-select-bazel-rbe-worker-pools-by-name} Remote Build Execution for Bazel now routes builds with a single `Pool=` execution property, instead of separate architecture and OS properties. #### CodePush SDK setup steps rewritten {#2026-07-30-codepush-sdk-setup-steps-rewritten} The React Native and Expo setup guides now match the current CodePush SDK, with the Expo instructions first. See [Configuring your mobile app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). #### Bitrise CI API reference corrections {#2026-07-24-bitrise-ci-api-reference-corrections} The API documentation now covers the pipeline outgoing-webhook event type, the full set of app role groups, optional Android keystore parameters, and the correct build notification defaults. #### Configuration YAML reference gains missing limits {#2026-07-24-configuration-yaml-reference-gains-missing-limits} The reference now documents the `status_report_name` and `parallel` limits, trigger priority, and the values `should_always_run` actually accepts. #### Workspace invitations can be rate-limited {#2026-07-24-workspace-invitations-can-be-rate-limited} Invitations sent from Workspaces on non-paid plans may be rate-limited. See [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). #### Developing a new step guide rewritten {#2026-07-20-developing-a-new-step-guide-rewritten} The walkthrough for building your own Step has been rewritten, with inaccurate statements corrected and background material trimmed. #### RDE CLI docs refreshed to match current commands {#2026-07-14-rde-cli-docs-refreshed-to-match-current-commands} The RDE CLI reference now covers stack-based session creation, running commands in a session with `session exec`, VNC tunneling, workspace selection, and the reconnect behavior of `rde claude`. See [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli). #### Building a Slack-native coding agent {#2026-07-10-building-a-slack-native-coding-agent} A new recipe walks through a reference architecture for a Slack-native coding agent: a locked-down orchestrator that delegates coding work to disposable Remote Dev Environments, plus an open source reference implementation you can try. See [Building a Slack-native coding agent](/bitrise-rde/recipes/building-a-slack-native-coding-agent-recipe). #### Bitrise Desktop App for macOS {#2026-07-09-bitrise-for-mac-menu-bar-app-guide} A new guide covers the Bitrise Desktop App for macOS: installing it, signing in, selecting a workspace and project, configuring filters and notifications, and troubleshooting. See [Bitrise Desktop App for macOS](/bitrise-ci/run-and-analyze-builds/bitrise-desktop-app-for-macos). #### Product subscriptions can now be canceled independently {#2026-07-07-product-subscriptions-can-now-be-canceled-independently} Each product (Bitrise CI, Build Cache, Release Management, and so on) has its own independently cancellable subscription, and add-ons can be canceled on their own too. The docs now walk through the updated **Plan & Billing** cancellation flow. See [Workspace billing and invoicing](/bitrise-platform/workspaces/workspace-billing-and-invoicing). #### Bitrise MCP server drops self-registration tools {#2026-07-02-bitrise-mcp-server-drops-self-registration-tools} The `register` and `verify_registration` tools, along with the `registration` API group, are no longer part of the Bitrise MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools). ### 2026 June #### RDE API reference now available in-site {#2026-06-29-rde-api-reference-now-available-in-site} The Remote Dev Environments REST API reference is now part of docs.bitrise.io as a native interactive explorer, covering 42 endpoints across user, workspace, sessions, templates, and saved inputs. See [RDE API reference](/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api). #### Remote Dev Environments docs now available {#2026-06-29-remote-dev-environments-docs-now-available} Documentation for Bitrise Remote Dev Environments (RDE) is now available, covering key concepts, a quickstart, configuration options (templates, saved inputs), and the available interfaces: CLI, MCP server, UI, and VS Code plugin. See [Remote Dev Environments](/bitrise-rde). #### Agent onboarding guide updated with OAuth flow {#2026-06-26-agent-onboarding-guide-updated-with-oauth-flow} The [onboarding guide for AI agents](/bitrise-platform/ai/onboarding-for-agents) now covers the full OAuth sign-in flow in detail: how your agent triggers browser authorization, creating an account during sign-in, email confirmation for password-based accounts, and troubleshooting steps for common issues. #### Entra ID SCIM provisioning guide {#2026-06-23-entra-id-scim-provisioning-guide} You can now set up automatic user and group provisioning for your Bitrise workspace using Microsoft Entra ID SCIM. The guide covers generating SCIM credentials, configuring Entra ID, attribute mapping, group and deprovisioning behavior, and migrating existing workspace members. See [Entra ID SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-entra-id-scim-for-bitrise). #### Bitrise CI API reference is now interactive {#2026-06-22-bitrise-ci-api-reference-is-now-interactive} The Bitrise CI API reference is now available as a full interactive explorer at `/en/bitrise-api`, replacing the previous SwaggerUI embed. Endpoints are grouped by tag with a sidebar, and you can try requests directly from the docs. See [Bitrise CI API reference](/bitrise-api). #### CodePush CLI docs expanded with full reference {#2026-06-19-codepush-cli-docs-expanded-with-full-reference} The CodePush CLI documentation has been expanded and restructured. A new reference page covers all commands, global flags, environment variables, and exit codes. The [Using the CodePush CLI](/release-management/codepush/codepush-cli/using-the-codepush-cli) page now includes workflow examples, JSON output, and Bitrise CI integration details. The code signing page adds a directory naming warning and a React Native >= 0.61 Android setup note. See [CodePush CLI](/release-management/codepush/codepush-cli/about-the-codepush-cli). #### AI agent onboarding tip added to sign-up page {#2026-06-18-ai-agent-onboarding-tip-added-to-sign-up-page} The [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) page now includes a tip pointing AI agents and coding assistants to the [dedicated onboarding runbook](/bitrise-platform/ai/onboarding-for-agents), which covers how to create a Bitrise account and connect everything directly from an agent session without a website visit. #### GitHub App integration: event subscriptions clarified {#2026-06-17-github-app-integration-event-subscriptions-clarified} The [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) page now has an Event subscriptions section explaining that the Bitrise GitHub App subscribes to `push`, `pull_request`, and `issue_comment` events via GitHub's app installation mechanism, not through repo-level webhooks. The section also warns that any existing manual webhooks pointing to `hooks.bitrise.io` must be removed after switching to the GitHub App to avoid duplicate builds. #### Bitrise MCP: new registration tools and API group {#2026-06-15-bitrise-mcp-new-registration-tools-and-api-group} The Bitrise MCP server now includes a `registration` API group with two unauthenticated tools — `register` and `verify_registration` — that let an AI agent onboard a brand-new Bitrise user without a token. The agent sends a one-time password to the user's email via `register`, then calls `verify_registration` with the OTP to receive a personal access token. These tools are most useful with the remote (HTTP) MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools) for the full reference. #### Bitrise MCP: install guides added for six tools {#2026-06-15-bitrise-mcp-install-guides-added-for-six-tools} Step-by-step install guides for the Bitrise MCP server are now available for VS Code, Cursor, Claude, Windsurf, Kiro, Gemini CLI, and other Copilot-compatible IDEs. Each guide covers how to configure the MCP server and authenticate with your Bitrise token. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) to get started. #### Workflow Editor can now push bitrise.yml directly to the repository {#2026-06-11-workflow-editor-can-now-push-bitrise-yml-directly-to-the-repository} The Workflow Editor now supports pushing changes to a repository-stored `bitrise.yml` directly from the editor — either to the current branch or a new branch — without manually copying and committing. See [Storing an app's configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml) for the updated flow. #### Build Hub: Gradle dependency mirroring explained {#2026-06-10-build-hub-gradle-dependency-mirroring-explained} The Build Hub documentation now includes an explanation of how Gradle dependency mirroring works, giving you a clearer picture of caching behaviour for Gradle projects running on Build Hub. #### Configuration YAML docs updated for YAML/Visual mode switcher {#2026-06-09-configuration-yaml-docs-updated-for-yaml-visual-mode-switcher} References throughout the docs have been updated to reflect the new toggle between YAML and Visual editing modes in the Workflow Editor. Where instructions previously referred to the left navigation menu, they now point to the **YAML** toggle at the top of the editor. #### New guide: Maven Central repository manager {#2026-06-08-new-guide-maven-central-repository-manager} A new guide covering the Maven Central repository manager is now available under [Build Cache getting started](/bitrise-build-cache/getting-started-with-the-build-cache/maven-central-repository-manager). It explains how Bitrise's proxy cache works for Maven dependencies, covers special cases like dependency verification and custom Docker images, and documents the opt-out process. #### Bitrise MCP server: OAuth is now the primary authentication method {#2026-06-08-bitrise-mcp-server-oauth-is-now-the-primary-authentication-method} The Bitrise MCP server now uses OAuth as the primary authentication method. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) for the updated setup steps. ### 2026 May #### Build distribution: custom access links for installable artifacts {#2026-05-29-build-distribution-custom-access-links-for-installable-artifacts} In Release Management, you can now create shareable install links. See [Custom access links](/release-management/build-distribution/distributing-builds-to-testers#custom-access-link) for details. #### Modular YAML: increased file and nesting limits for GitHub users {#2026-05-28-modular-yaml-increased-file-and-nesting-limits-for-github-users} The modular YAML configuration guide has been updated to reflect the new, higher file count and nesting limits for GitHub users. See [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration) for the updated limits. #### Python projects now supported {#2026-05-20-python-projects-now-supported} Bitrise now detects Python projects automatically and offers default workflows. The [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) and [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guides have been updated to include Python. ### 2026 April #### Next.js and Flutter Web project types documented {#2026-04-20-next-js-and-flutter-web-project-types-documented} The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide and [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) page now cover Next.js (as an extension of Node.js) and Flutter Web project types. ### 2026 March #### M4 machine type added to build machine docs {#2026-03-30-m4-machine-type-added-to-build-machine-docs} The [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types) page now lists the M4 machine type alongside the existing M4 Pro, M2 Pro, and M1 options, with region availability for each. #### Ruby projects now supported {#2026-03-25-ruby-projects-now-supported} Bitrise now detects Ruby projects automatically and offers default workflows. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to include Ruby. #### Pro Trial: credit card required to access the full trial {#2026-03-24-pro-trial-credit-card-required-to-access-the-full-trial} New users now need to provide a valid credit card (which won't be charged) to access the full Pro Trial. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to explain this. #### New page: build artifact retention policy {#2026-03-20-new-page-build-artifact-retention-policy} A dedicated [Build artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy) page is now available, covering default retention periods by artifact type, extended retention options for enterprise customers, and the edge case around transferred projects. #### Xcode compilation cache: new flag to disable caching without disabling analytics {#2026-03-10-xcode-compilation-cache-new-flag-to-disable-caching-without-disabling-analytics} The [Xcode compilation cache FAQ](/bitrise-build-cache/build-cache-for-xcode/xcode-compilation-cache-faq) now documents the `--no-bitrise-build-cache` flag, which lets you disable caching temporarily while keeping analytics and build history intact. ### 2026 February #### Build Cache: clear cache button replaces Settings dropdown {#2026-02-20-build-cache-clear-cache-button-replaces-settings-dropdown} The [Clearing the Build Cache](/bitrise-build-cache/getting-started-with-the-build-cache/clearing-the-build-cache) guide has been updated to reflect the current UI: the Settings dropdown was replaced by a **Clear Cache** button. The guide includes a new screenshot and a note that clearing the cache requires Workspace owner permissions. #### New guide: Endpoint Detection and Response (EDR) on Bitrise {#2026-02-20-new-guide-endpoint-detection-and-response-edr-on-bitrise} A new page under Integrations explains how Bitrise uses Endpoint Detection and Response (EDR) as part of its corporate security program, and clarifies that EDR agents are not deployed on Bitrise-hosted CI runners. #### OIDC for AWS guide updated {#2026-02-13-oidc-for-aws-guide-updated} The [OIDC for AWS](/bitrise-platform/integrations/oidc-authentication/oidc-for-aws) guide has been updated with additional clarifications on configuration and usage. #### New guide: GitHub App migration API {#2026-02-03-new-guide-github-app-migration-api} A new guide explains how to use the Bitrise API to bulk-migrate projects from OAuth-based GitHub connections to the GitHub App integration, including caveats about reverting the migration. See [Adding and managing apps](/bitrise-ci/api/adding-and-managing-apps) for details. ### 2026 January #### Tool setup: new tool versions added {#2026-01-27-tool-setup-new-tool-versions-added} The [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions) guide has been updated with newly supported tool versions in the tool setup feature. #### Build artifact retention policy documented {#2026-01-19-build-artifact-retention-policy-documented} The [Build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) page now includes a section on the artifact retention policy, covering default retention periods by artifact type and options for Enterprise customers. The policy takes effect on March 31, 2026. #### Pipeline rebuild: dynamic parallel workflows explained {#2026-01-12-pipeline-rebuild-dynamic-parallel-workflows-explained} The guide on rebuilding failed pipelines now includes an explanation of how dynamic parallel Workflows affect rebuild options — specifically, when you can rebuild individual Workflows versus all unsuccessful ones. See [Rebuilding a failed build](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline) for details. --- ## Docs changelog(Bitrise-rde) This page tracks documentation updates: new guides, updated procedures, and changes reflecting new or updated Bitrise features. Subscribe to RSS ### 2026 September #### Track Remote Dev Environments usage across API, CLI, MCP, and UI {#2026-09-01-track-remote-dev-environments-usage-across-api-cli-mcp-and-ui} You can now check RDE workspace usage through the REST API, the `rde usage` CLI command, the MCP server, or the UI. See [Remote Dev Environments API](/bitrise-rde/configuration/rde-api). ### 2026 August #### CodePush delta updates {#2026-08-31-codepush-delta-updates} Learn what delta updates are, why they matter, and which version Bitrise currently supports. See [Delta updates](/release-management/codepush/delta-updates). #### Enable Build Cache writes for React Native on non-Bitrise CI {#2026-08-26-enable-build-cache-writes-for-react-native-on-non-bitrise-ci} Docs now show how to pass `--cache-push` so a non-Bitrise CI provider can write to the Build Cache, not just read from it. See [Configuring the Build Cache for React Native in non-Bitrise CI environments](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-non-bitrise-ci-environments). #### GitHub stacked pull requests {#2026-08-25-github-stacked-pull-requests} Trigger conditions and `$BITRISEIO_GIT_BRANCH_DEST` now explain how Bitrise handles GitHub stacked pull requests, matching against the stack's base branch. See [About build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/about-build-triggers). #### Remote Dev Environments FAQ, and a corrected session retention model {#2026-08-24-remote-dev-environments-faq-and-a-corrected-session-retention-model} New [Remote Dev Environments FAQ](/bitrise-rde/getting-started/rde-faq) answers the most common questions about sessions, storage, connecting, credentials, AI coding agents, and limits. The session retention documentation was also corrected. Terminated sessions are not cleaned up after a fixed period: a session's persistent disk is kept until you delete it, or until the stack it was created from is removed under the [stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). [Key concepts](/bitrise-rde/getting-started/key-concepts) now also explains that a session stays permanently tied to the stack it was created from and can't be moved to a different one. #### Manage Remote Dev Environments access from Collaboration {#2026-08-14-manage-remote-dev-environments-access-from-collaboration} RDE is now a standalone product in workspace collaboration: grant or revoke the **RDE User** role for members and groups from the **Collaboration** page, or assign it through SCIM with `rde:rde_admin`. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). #### Utility builds beta for Pro plans {#2026-08-06-utility-builds-beta-for-pro-plans} Short Linux builds that run on the Linux Small machine type don't count against your build quota during the beta. See [Utility builds](/bitrise-ci/run-and-analyze-builds/utility-builds). #### Edit modular YAML in the Workflow Editor {#2026-08-05-edit-modular-yaml-in-the-workflow-editor} The Workflow Editor now loads every module of a configuration split with the `include` keyword, shows the merged result, and pushes your changes back to your repository in one step. See [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). ### 2026 July #### Linux tooling steps scoped to the Docker-based image {#2026-07-30-linux-tooling-steps-scoped-to-the-docker-based-image} The tooling-access steps for Build Hub Linux machines apply only to the deprecated Docker-based image. If you use `linux-bitvirt-2026`, you can skip them. See [Configuring Build Hub for GitHub Actions](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#enabling-linux-machines-to-access-tooling). #### Select Bazel RBE worker pools by name {#2026-07-30-select-bazel-rbe-worker-pools-by-name} Remote Build Execution for Bazel now routes builds with a single `Pool=` execution property, instead of separate architecture and OS properties. #### CodePush SDK setup steps rewritten {#2026-07-30-codepush-sdk-setup-steps-rewritten} The React Native and Expo setup guides now match the current CodePush SDK, with the Expo instructions first. See [Configuring your mobile app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). #### Bitrise CI API reference corrections {#2026-07-24-bitrise-ci-api-reference-corrections} The API documentation now covers the pipeline outgoing-webhook event type, the full set of app role groups, optional Android keystore parameters, and the correct build notification defaults. #### Configuration YAML reference gains missing limits {#2026-07-24-configuration-yaml-reference-gains-missing-limits} The reference now documents the `status_report_name` and `parallel` limits, trigger priority, and the values `should_always_run` actually accepts. #### Workspace invitations can be rate-limited {#2026-07-24-workspace-invitations-can-be-rate-limited} Invitations sent from Workspaces on non-paid plans may be rate-limited. See [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). #### Developing a new step guide rewritten {#2026-07-20-developing-a-new-step-guide-rewritten} The walkthrough for building your own Step has been rewritten, with inaccurate statements corrected and background material trimmed. #### RDE CLI docs refreshed to match current commands {#2026-07-14-rde-cli-docs-refreshed-to-match-current-commands} The RDE CLI reference now covers stack-based session creation, running commands in a session with `session exec`, VNC tunneling, workspace selection, and the reconnect behavior of `rde claude`. See [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli). #### Building a Slack-native coding agent {#2026-07-10-building-a-slack-native-coding-agent} A new recipe walks through a reference architecture for a Slack-native coding agent: a locked-down orchestrator that delegates coding work to disposable Remote Dev Environments, plus an open source reference implementation you can try. See [Building a Slack-native coding agent](/bitrise-rde/recipes/building-a-slack-native-coding-agent-recipe). #### Bitrise Desktop App for macOS {#2026-07-09-bitrise-for-mac-menu-bar-app-guide} A new guide covers the Bitrise Desktop App for macOS: installing it, signing in, selecting a workspace and project, configuring filters and notifications, and troubleshooting. See [Bitrise Desktop App for macOS](/bitrise-ci/run-and-analyze-builds/bitrise-desktop-app-for-macos). #### Product subscriptions can now be canceled independently {#2026-07-07-product-subscriptions-can-now-be-canceled-independently} Each product (Bitrise CI, Build Cache, Release Management, and so on) has its own independently cancellable subscription, and add-ons can be canceled on their own too. The docs now walk through the updated **Plan & Billing** cancellation flow. See [Workspace billing and invoicing](/bitrise-platform/workspaces/workspace-billing-and-invoicing). #### Bitrise MCP server drops self-registration tools {#2026-07-02-bitrise-mcp-server-drops-self-registration-tools} The `register` and `verify_registration` tools, along with the `registration` API group, are no longer part of the Bitrise MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools). ### 2026 June #### RDE API reference now available in-site {#2026-06-29-rde-api-reference-now-available-in-site} The Remote Dev Environments REST API reference is now part of docs.bitrise.io as a native interactive explorer, covering 42 endpoints across user, workspace, sessions, templates, and saved inputs. See [RDE API reference](/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api). #### Remote Dev Environments docs now available {#2026-06-29-remote-dev-environments-docs-now-available} Documentation for Bitrise Remote Dev Environments (RDE) is now available, covering key concepts, a quickstart, configuration options (templates, saved inputs), and the available interfaces: CLI, MCP server, UI, and VS Code plugin. See [Remote Dev Environments](/bitrise-rde). #### Agent onboarding guide updated with OAuth flow {#2026-06-26-agent-onboarding-guide-updated-with-oauth-flow} The [onboarding guide for AI agents](/bitrise-platform/ai/onboarding-for-agents) now covers the full OAuth sign-in flow in detail: how your agent triggers browser authorization, creating an account during sign-in, email confirmation for password-based accounts, and troubleshooting steps for common issues. #### Entra ID SCIM provisioning guide {#2026-06-23-entra-id-scim-provisioning-guide} You can now set up automatic user and group provisioning for your Bitrise workspace using Microsoft Entra ID SCIM. The guide covers generating SCIM credentials, configuring Entra ID, attribute mapping, group and deprovisioning behavior, and migrating existing workspace members. See [Entra ID SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-entra-id-scim-for-bitrise). #### Bitrise CI API reference is now interactive {#2026-06-22-bitrise-ci-api-reference-is-now-interactive} The Bitrise CI API reference is now available as a full interactive explorer at `/en/bitrise-api`, replacing the previous SwaggerUI embed. Endpoints are grouped by tag with a sidebar, and you can try requests directly from the docs. See [Bitrise CI API reference](/bitrise-api). #### CodePush CLI docs expanded with full reference {#2026-06-19-codepush-cli-docs-expanded-with-full-reference} The CodePush CLI documentation has been expanded and restructured. A new reference page covers all commands, global flags, environment variables, and exit codes. The [Using the CodePush CLI](/release-management/codepush/codepush-cli/using-the-codepush-cli) page now includes workflow examples, JSON output, and Bitrise CI integration details. The code signing page adds a directory naming warning and a React Native >= 0.61 Android setup note. See [CodePush CLI](/release-management/codepush/codepush-cli/about-the-codepush-cli). #### AI agent onboarding tip added to sign-up page {#2026-06-18-ai-agent-onboarding-tip-added-to-sign-up-page} The [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) page now includes a tip pointing AI agents and coding assistants to the [dedicated onboarding runbook](/bitrise-platform/ai/onboarding-for-agents), which covers how to create a Bitrise account and connect everything directly from an agent session without a website visit. #### GitHub App integration: event subscriptions clarified {#2026-06-17-github-app-integration-event-subscriptions-clarified} The [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) page now has an Event subscriptions section explaining that the Bitrise GitHub App subscribes to `push`, `pull_request`, and `issue_comment` events via GitHub's app installation mechanism, not through repo-level webhooks. The section also warns that any existing manual webhooks pointing to `hooks.bitrise.io` must be removed after switching to the GitHub App to avoid duplicate builds. #### Bitrise MCP: new registration tools and API group {#2026-06-15-bitrise-mcp-new-registration-tools-and-api-group} The Bitrise MCP server now includes a `registration` API group with two unauthenticated tools — `register` and `verify_registration` — that let an AI agent onboard a brand-new Bitrise user without a token. The agent sends a one-time password to the user's email via `register`, then calls `verify_registration` with the OTP to receive a personal access token. These tools are most useful with the remote (HTTP) MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools) for the full reference. #### Bitrise MCP: install guides added for six tools {#2026-06-15-bitrise-mcp-install-guides-added-for-six-tools} Step-by-step install guides for the Bitrise MCP server are now available for VS Code, Cursor, Claude, Windsurf, Kiro, Gemini CLI, and other Copilot-compatible IDEs. Each guide covers how to configure the MCP server and authenticate with your Bitrise token. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) to get started. #### Workflow Editor can now push bitrise.yml directly to the repository {#2026-06-11-workflow-editor-can-now-push-bitrise-yml-directly-to-the-repository} The Workflow Editor now supports pushing changes to a repository-stored `bitrise.yml` directly from the editor — either to the current branch or a new branch — without manually copying and committing. See [Storing an app's configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml) for the updated flow. #### Build Hub: Gradle dependency mirroring explained {#2026-06-10-build-hub-gradle-dependency-mirroring-explained} The Build Hub documentation now includes an explanation of how Gradle dependency mirroring works, giving you a clearer picture of caching behaviour for Gradle projects running on Build Hub. #### Configuration YAML docs updated for YAML/Visual mode switcher {#2026-06-09-configuration-yaml-docs-updated-for-yaml-visual-mode-switcher} References throughout the docs have been updated to reflect the new toggle between YAML and Visual editing modes in the Workflow Editor. Where instructions previously referred to the left navigation menu, they now point to the **YAML** toggle at the top of the editor. #### New guide: Maven Central repository manager {#2026-06-08-new-guide-maven-central-repository-manager} A new guide covering the Maven Central repository manager is now available under [Build Cache getting started](/bitrise-build-cache/getting-started-with-the-build-cache/maven-central-repository-manager). It explains how Bitrise's proxy cache works for Maven dependencies, covers special cases like dependency verification and custom Docker images, and documents the opt-out process. #### Bitrise MCP server: OAuth is now the primary authentication method {#2026-06-08-bitrise-mcp-server-oauth-is-now-the-primary-authentication-method} The Bitrise MCP server now uses OAuth as the primary authentication method. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) for the updated setup steps. ### 2026 May #### Build distribution: custom access links for installable artifacts {#2026-05-29-build-distribution-custom-access-links-for-installable-artifacts} In Release Management, you can now create shareable install links. See [Custom access links](/release-management/build-distribution/distributing-builds-to-testers#custom-access-link) for details. #### Modular YAML: increased file and nesting limits for GitHub users {#2026-05-28-modular-yaml-increased-file-and-nesting-limits-for-github-users} The modular YAML configuration guide has been updated to reflect the new, higher file count and nesting limits for GitHub users. See [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration) for the updated limits. #### Python projects now supported {#2026-05-20-python-projects-now-supported} Bitrise now detects Python projects automatically and offers default workflows. The [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) and [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guides have been updated to include Python. ### 2026 April #### Next.js and Flutter Web project types documented {#2026-04-20-next-js-and-flutter-web-project-types-documented} The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide and [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) page now cover Next.js (as an extension of Node.js) and Flutter Web project types. ### 2026 March #### M4 machine type added to build machine docs {#2026-03-30-m4-machine-type-added-to-build-machine-docs} The [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types) page now lists the M4 machine type alongside the existing M4 Pro, M2 Pro, and M1 options, with region availability for each. #### Ruby projects now supported {#2026-03-25-ruby-projects-now-supported} Bitrise now detects Ruby projects automatically and offers default workflows. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to include Ruby. #### Pro Trial: credit card required to access the full trial {#2026-03-24-pro-trial-credit-card-required-to-access-the-full-trial} New users now need to provide a valid credit card (which won't be charged) to access the full Pro Trial. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to explain this. #### New page: build artifact retention policy {#2026-03-20-new-page-build-artifact-retention-policy} A dedicated [Build artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy) page is now available, covering default retention periods by artifact type, extended retention options for enterprise customers, and the edge case around transferred projects. #### Xcode compilation cache: new flag to disable caching without disabling analytics {#2026-03-10-xcode-compilation-cache-new-flag-to-disable-caching-without-disabling-analytics} The [Xcode compilation cache FAQ](/bitrise-build-cache/build-cache-for-xcode/xcode-compilation-cache-faq) now documents the `--no-bitrise-build-cache` flag, which lets you disable caching temporarily while keeping analytics and build history intact. ### 2026 February #### Build Cache: clear cache button replaces Settings dropdown {#2026-02-20-build-cache-clear-cache-button-replaces-settings-dropdown} The [Clearing the Build Cache](/bitrise-build-cache/getting-started-with-the-build-cache/clearing-the-build-cache) guide has been updated to reflect the current UI: the Settings dropdown was replaced by a **Clear Cache** button. The guide includes a new screenshot and a note that clearing the cache requires Workspace owner permissions. #### New guide: Endpoint Detection and Response (EDR) on Bitrise {#2026-02-20-new-guide-endpoint-detection-and-response-edr-on-bitrise} A new page under Integrations explains how Bitrise uses Endpoint Detection and Response (EDR) as part of its corporate security program, and clarifies that EDR agents are not deployed on Bitrise-hosted CI runners. #### OIDC for AWS guide updated {#2026-02-13-oidc-for-aws-guide-updated} The [OIDC for AWS](/bitrise-platform/integrations/oidc-authentication/oidc-for-aws) guide has been updated with additional clarifications on configuration and usage. #### New guide: GitHub App migration API {#2026-02-03-new-guide-github-app-migration-api} A new guide explains how to use the Bitrise API to bulk-migrate projects from OAuth-based GitHub connections to the GitHub App integration, including caveats about reverting the migration. See [Adding and managing apps](/bitrise-ci/api/adding-and-managing-apps) for details. ### 2026 January #### Tool setup: new tool versions added {#2026-01-27-tool-setup-new-tool-versions-added} The [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions) guide has been updated with newly supported tool versions in the tool setup feature. #### Build artifact retention policy documented {#2026-01-19-build-artifact-retention-policy-documented} The [Build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) page now includes a section on the artifact retention policy, covering default retention periods by artifact type and options for Enterprise customers. The policy takes effect on March 31, 2026. #### Pipeline rebuild: dynamic parallel workflows explained {#2026-01-12-pipeline-rebuild-dynamic-parallel-workflows-explained} The guide on rebuilding failed pipelines now includes an explanation of how dynamic parallel Workflows affect rebuild options — specifically, when you can rebuild individual Workflows versus all unsuccessful ones. See [Rebuilding a failed build](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline) for details. --- ## Docs changelog(Insights) This page tracks documentation updates: new guides, updated procedures, and changes reflecting new or updated Bitrise features. Subscribe to RSS ### 2026 September #### Track Remote Dev Environments usage across API, CLI, MCP, and UI {#2026-09-01-track-remote-dev-environments-usage-across-api-cli-mcp-and-ui} You can now check RDE workspace usage through the REST API, the `rde usage` CLI command, the MCP server, or the UI. See [Remote Dev Environments API](/bitrise-rde/configuration/rde-api). ### 2026 August #### CodePush delta updates {#2026-08-31-codepush-delta-updates} Learn what delta updates are, why they matter, and which version Bitrise currently supports. See [Delta updates](/release-management/codepush/delta-updates). #### Enable Build Cache writes for React Native on non-Bitrise CI {#2026-08-26-enable-build-cache-writes-for-react-native-on-non-bitrise-ci} Docs now show how to pass `--cache-push` so a non-Bitrise CI provider can write to the Build Cache, not just read from it. See [Configuring the Build Cache for React Native in non-Bitrise CI environments](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-non-bitrise-ci-environments). #### GitHub stacked pull requests {#2026-08-25-github-stacked-pull-requests} Trigger conditions and `$BITRISEIO_GIT_BRANCH_DEST` now explain how Bitrise handles GitHub stacked pull requests, matching against the stack's base branch. See [About build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/about-build-triggers). #### Remote Dev Environments FAQ, and a corrected session retention model {#2026-08-24-remote-dev-environments-faq-and-a-corrected-session-retention-model} New [Remote Dev Environments FAQ](/bitrise-rde/getting-started/rde-faq) answers the most common questions about sessions, storage, connecting, credentials, AI coding agents, and limits. The session retention documentation was also corrected. Terminated sessions are not cleaned up after a fixed period: a session's persistent disk is kept until you delete it, or until the stack it was created from is removed under the [stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). [Key concepts](/bitrise-rde/getting-started/key-concepts) now also explains that a session stays permanently tied to the stack it was created from and can't be moved to a different one. #### Manage Remote Dev Environments access from Collaboration {#2026-08-14-manage-remote-dev-environments-access-from-collaboration} RDE is now a standalone product in workspace collaboration: grant or revoke the **RDE User** role for members and groups from the **Collaboration** page, or assign it through SCIM with `rde:rde_admin`. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). #### Utility builds beta for Pro plans {#2026-08-06-utility-builds-beta-for-pro-plans} Short Linux builds that run on the Linux Small machine type don't count against your build quota during the beta. See [Utility builds](/bitrise-ci/run-and-analyze-builds/utility-builds). #### Edit modular YAML in the Workflow Editor {#2026-08-05-edit-modular-yaml-in-the-workflow-editor} The Workflow Editor now loads every module of a configuration split with the `include` keyword, shows the merged result, and pushes your changes back to your repository in one step. See [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). ### 2026 July #### Linux tooling steps scoped to the Docker-based image {#2026-07-30-linux-tooling-steps-scoped-to-the-docker-based-image} The tooling-access steps for Build Hub Linux machines apply only to the deprecated Docker-based image. If you use `linux-bitvirt-2026`, you can skip them. See [Configuring Build Hub for GitHub Actions](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#enabling-linux-machines-to-access-tooling). #### Select Bazel RBE worker pools by name {#2026-07-30-select-bazel-rbe-worker-pools-by-name} Remote Build Execution for Bazel now routes builds with a single `Pool=` execution property, instead of separate architecture and OS properties. #### CodePush SDK setup steps rewritten {#2026-07-30-codepush-sdk-setup-steps-rewritten} The React Native and Expo setup guides now match the current CodePush SDK, with the Expo instructions first. See [Configuring your mobile app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). #### Bitrise CI API reference corrections {#2026-07-24-bitrise-ci-api-reference-corrections} The API documentation now covers the pipeline outgoing-webhook event type, the full set of app role groups, optional Android keystore parameters, and the correct build notification defaults. #### Configuration YAML reference gains missing limits {#2026-07-24-configuration-yaml-reference-gains-missing-limits} The reference now documents the `status_report_name` and `parallel` limits, trigger priority, and the values `should_always_run` actually accepts. #### Workspace invitations can be rate-limited {#2026-07-24-workspace-invitations-can-be-rate-limited} Invitations sent from Workspaces on non-paid plans may be rate-limited. See [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). #### Developing a new step guide rewritten {#2026-07-20-developing-a-new-step-guide-rewritten} The walkthrough for building your own Step has been rewritten, with inaccurate statements corrected and background material trimmed. #### RDE CLI docs refreshed to match current commands {#2026-07-14-rde-cli-docs-refreshed-to-match-current-commands} The RDE CLI reference now covers stack-based session creation, running commands in a session with `session exec`, VNC tunneling, workspace selection, and the reconnect behavior of `rde claude`. See [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli). #### Building a Slack-native coding agent {#2026-07-10-building-a-slack-native-coding-agent} A new recipe walks through a reference architecture for a Slack-native coding agent: a locked-down orchestrator that delegates coding work to disposable Remote Dev Environments, plus an open source reference implementation you can try. See [Building a Slack-native coding agent](/bitrise-rde/recipes/building-a-slack-native-coding-agent-recipe). #### Bitrise Desktop App for macOS {#2026-07-09-bitrise-for-mac-menu-bar-app-guide} A new guide covers the Bitrise Desktop App for macOS: installing it, signing in, selecting a workspace and project, configuring filters and notifications, and troubleshooting. See [Bitrise Desktop App for macOS](/bitrise-ci/run-and-analyze-builds/bitrise-desktop-app-for-macos). #### Product subscriptions can now be canceled independently {#2026-07-07-product-subscriptions-can-now-be-canceled-independently} Each product (Bitrise CI, Build Cache, Release Management, and so on) has its own independently cancellable subscription, and add-ons can be canceled on their own too. The docs now walk through the updated **Plan & Billing** cancellation flow. See [Workspace billing and invoicing](/bitrise-platform/workspaces/workspace-billing-and-invoicing). #### Bitrise MCP server drops self-registration tools {#2026-07-02-bitrise-mcp-server-drops-self-registration-tools} The `register` and `verify_registration` tools, along with the `registration` API group, are no longer part of the Bitrise MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools). ### 2026 June #### RDE API reference now available in-site {#2026-06-29-rde-api-reference-now-available-in-site} The Remote Dev Environments REST API reference is now part of docs.bitrise.io as a native interactive explorer, covering 42 endpoints across user, workspace, sessions, templates, and saved inputs. See [RDE API reference](/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api). #### Remote Dev Environments docs now available {#2026-06-29-remote-dev-environments-docs-now-available} Documentation for Bitrise Remote Dev Environments (RDE) is now available, covering key concepts, a quickstart, configuration options (templates, saved inputs), and the available interfaces: CLI, MCP server, UI, and VS Code plugin. See [Remote Dev Environments](/bitrise-rde). #### Agent onboarding guide updated with OAuth flow {#2026-06-26-agent-onboarding-guide-updated-with-oauth-flow} The [onboarding guide for AI agents](/bitrise-platform/ai/onboarding-for-agents) now covers the full OAuth sign-in flow in detail: how your agent triggers browser authorization, creating an account during sign-in, email confirmation for password-based accounts, and troubleshooting steps for common issues. #### Entra ID SCIM provisioning guide {#2026-06-23-entra-id-scim-provisioning-guide} You can now set up automatic user and group provisioning for your Bitrise workspace using Microsoft Entra ID SCIM. The guide covers generating SCIM credentials, configuring Entra ID, attribute mapping, group and deprovisioning behavior, and migrating existing workspace members. See [Entra ID SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-entra-id-scim-for-bitrise). #### Bitrise CI API reference is now interactive {#2026-06-22-bitrise-ci-api-reference-is-now-interactive} The Bitrise CI API reference is now available as a full interactive explorer at `/en/bitrise-api`, replacing the previous SwaggerUI embed. Endpoints are grouped by tag with a sidebar, and you can try requests directly from the docs. See [Bitrise CI API reference](/bitrise-api). #### CodePush CLI docs expanded with full reference {#2026-06-19-codepush-cli-docs-expanded-with-full-reference} The CodePush CLI documentation has been expanded and restructured. A new reference page covers all commands, global flags, environment variables, and exit codes. The [Using the CodePush CLI](/release-management/codepush/codepush-cli/using-the-codepush-cli) page now includes workflow examples, JSON output, and Bitrise CI integration details. The code signing page adds a directory naming warning and a React Native >= 0.61 Android setup note. See [CodePush CLI](/release-management/codepush/codepush-cli/about-the-codepush-cli). #### AI agent onboarding tip added to sign-up page {#2026-06-18-ai-agent-onboarding-tip-added-to-sign-up-page} The [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) page now includes a tip pointing AI agents and coding assistants to the [dedicated onboarding runbook](/bitrise-platform/ai/onboarding-for-agents), which covers how to create a Bitrise account and connect everything directly from an agent session without a website visit. #### GitHub App integration: event subscriptions clarified {#2026-06-17-github-app-integration-event-subscriptions-clarified} The [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) page now has an Event subscriptions section explaining that the Bitrise GitHub App subscribes to `push`, `pull_request`, and `issue_comment` events via GitHub's app installation mechanism, not through repo-level webhooks. The section also warns that any existing manual webhooks pointing to `hooks.bitrise.io` must be removed after switching to the GitHub App to avoid duplicate builds. #### Bitrise MCP: new registration tools and API group {#2026-06-15-bitrise-mcp-new-registration-tools-and-api-group} The Bitrise MCP server now includes a `registration` API group with two unauthenticated tools — `register` and `verify_registration` — that let an AI agent onboard a brand-new Bitrise user without a token. The agent sends a one-time password to the user's email via `register`, then calls `verify_registration` with the OTP to receive a personal access token. These tools are most useful with the remote (HTTP) MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools) for the full reference. #### Bitrise MCP: install guides added for six tools {#2026-06-15-bitrise-mcp-install-guides-added-for-six-tools} Step-by-step install guides for the Bitrise MCP server are now available for VS Code, Cursor, Claude, Windsurf, Kiro, Gemini CLI, and other Copilot-compatible IDEs. Each guide covers how to configure the MCP server and authenticate with your Bitrise token. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) to get started. #### Workflow Editor can now push bitrise.yml directly to the repository {#2026-06-11-workflow-editor-can-now-push-bitrise-yml-directly-to-the-repository} The Workflow Editor now supports pushing changes to a repository-stored `bitrise.yml` directly from the editor — either to the current branch or a new branch — without manually copying and committing. See [Storing an app's configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml) for the updated flow. #### Build Hub: Gradle dependency mirroring explained {#2026-06-10-build-hub-gradle-dependency-mirroring-explained} The Build Hub documentation now includes an explanation of how Gradle dependency mirroring works, giving you a clearer picture of caching behaviour for Gradle projects running on Build Hub. #### Configuration YAML docs updated for YAML/Visual mode switcher {#2026-06-09-configuration-yaml-docs-updated-for-yaml-visual-mode-switcher} References throughout the docs have been updated to reflect the new toggle between YAML and Visual editing modes in the Workflow Editor. Where instructions previously referred to the left navigation menu, they now point to the **YAML** toggle at the top of the editor. #### New guide: Maven Central repository manager {#2026-06-08-new-guide-maven-central-repository-manager} A new guide covering the Maven Central repository manager is now available under [Build Cache getting started](/bitrise-build-cache/getting-started-with-the-build-cache/maven-central-repository-manager). It explains how Bitrise's proxy cache works for Maven dependencies, covers special cases like dependency verification and custom Docker images, and documents the opt-out process. #### Bitrise MCP server: OAuth is now the primary authentication method {#2026-06-08-bitrise-mcp-server-oauth-is-now-the-primary-authentication-method} The Bitrise MCP server now uses OAuth as the primary authentication method. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) for the updated setup steps. ### 2026 May #### Build distribution: custom access links for installable artifacts {#2026-05-29-build-distribution-custom-access-links-for-installable-artifacts} In Release Management, you can now create shareable install links. See [Custom access links](/release-management/build-distribution/distributing-builds-to-testers#custom-access-link) for details. #### Modular YAML: increased file and nesting limits for GitHub users {#2026-05-28-modular-yaml-increased-file-and-nesting-limits-for-github-users} The modular YAML configuration guide has been updated to reflect the new, higher file count and nesting limits for GitHub users. See [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration) for the updated limits. #### Python projects now supported {#2026-05-20-python-projects-now-supported} Bitrise now detects Python projects automatically and offers default workflows. The [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) and [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guides have been updated to include Python. ### 2026 April #### Next.js and Flutter Web project types documented {#2026-04-20-next-js-and-flutter-web-project-types-documented} The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide and [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) page now cover Next.js (as an extension of Node.js) and Flutter Web project types. ### 2026 March #### M4 machine type added to build machine docs {#2026-03-30-m4-machine-type-added-to-build-machine-docs} The [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types) page now lists the M4 machine type alongside the existing M4 Pro, M2 Pro, and M1 options, with region availability for each. #### Ruby projects now supported {#2026-03-25-ruby-projects-now-supported} Bitrise now detects Ruby projects automatically and offers default workflows. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to include Ruby. #### Pro Trial: credit card required to access the full trial {#2026-03-24-pro-trial-credit-card-required-to-access-the-full-trial} New users now need to provide a valid credit card (which won't be charged) to access the full Pro Trial. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to explain this. #### New page: build artifact retention policy {#2026-03-20-new-page-build-artifact-retention-policy} A dedicated [Build artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy) page is now available, covering default retention periods by artifact type, extended retention options for enterprise customers, and the edge case around transferred projects. #### Xcode compilation cache: new flag to disable caching without disabling analytics {#2026-03-10-xcode-compilation-cache-new-flag-to-disable-caching-without-disabling-analytics} The [Xcode compilation cache FAQ](/bitrise-build-cache/build-cache-for-xcode/xcode-compilation-cache-faq) now documents the `--no-bitrise-build-cache` flag, which lets you disable caching temporarily while keeping analytics and build history intact. ### 2026 February #### Build Cache: clear cache button replaces Settings dropdown {#2026-02-20-build-cache-clear-cache-button-replaces-settings-dropdown} The [Clearing the Build Cache](/bitrise-build-cache/getting-started-with-the-build-cache/clearing-the-build-cache) guide has been updated to reflect the current UI: the Settings dropdown was replaced by a **Clear Cache** button. The guide includes a new screenshot and a note that clearing the cache requires Workspace owner permissions. #### New guide: Endpoint Detection and Response (EDR) on Bitrise {#2026-02-20-new-guide-endpoint-detection-and-response-edr-on-bitrise} A new page under Integrations explains how Bitrise uses Endpoint Detection and Response (EDR) as part of its corporate security program, and clarifies that EDR agents are not deployed on Bitrise-hosted CI runners. #### OIDC for AWS guide updated {#2026-02-13-oidc-for-aws-guide-updated} The [OIDC for AWS](/bitrise-platform/integrations/oidc-authentication/oidc-for-aws) guide has been updated with additional clarifications on configuration and usage. #### New guide: GitHub App migration API {#2026-02-03-new-guide-github-app-migration-api} A new guide explains how to use the Bitrise API to bulk-migrate projects from OAuth-based GitHub connections to the GitHub App integration, including caveats about reverting the migration. See [Adding and managing apps](/bitrise-ci/api/adding-and-managing-apps) for details. ### 2026 January #### Tool setup: new tool versions added {#2026-01-27-tool-setup-new-tool-versions-added} The [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions) guide has been updated with newly supported tool versions in the tool setup feature. #### Build artifact retention policy documented {#2026-01-19-build-artifact-retention-policy-documented} The [Build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) page now includes a section on the artifact retention policy, covering default retention periods by artifact type and options for Enterprise customers. The policy takes effect on March 31, 2026. #### Pipeline rebuild: dynamic parallel workflows explained {#2026-01-12-pipeline-rebuild-dynamic-parallel-workflows-explained} The guide on rebuilding failed pipelines now includes an explanation of how dynamic parallel Workflows affect rebuild options — specifically, when you can rebuild individual Workflows versus all unsuccessful ones. See [Rebuilding a failed build](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline) for details. --- ## Docs changelog(Release-management) This page tracks documentation updates: new guides, updated procedures, and changes reflecting new or updated Bitrise features. Subscribe to RSS ### 2026 September #### Track Remote Dev Environments usage across API, CLI, MCP, and UI {#2026-09-01-track-remote-dev-environments-usage-across-api-cli-mcp-and-ui} You can now check RDE workspace usage through the REST API, the `rde usage` CLI command, the MCP server, or the UI. See [Remote Dev Environments API](/bitrise-rde/configuration/rde-api). ### 2026 August #### CodePush delta updates {#2026-08-31-codepush-delta-updates} Learn what delta updates are, why they matter, and which version Bitrise currently supports. See [Delta updates](/release-management/codepush/delta-updates). #### Enable Build Cache writes for React Native on non-Bitrise CI {#2026-08-26-enable-build-cache-writes-for-react-native-on-non-bitrise-ci} Docs now show how to pass `--cache-push` so a non-Bitrise CI provider can write to the Build Cache, not just read from it. See [Configuring the Build Cache for React Native in non-Bitrise CI environments](/bitrise-build-cache/build-cache-for-react-native/configuring-the-build-cache-for-react-native-in-non-bitrise-ci-environments). #### GitHub stacked pull requests {#2026-08-25-github-stacked-pull-requests} Trigger conditions and `$BITRISEIO_GIT_BRANCH_DEST` now explain how Bitrise handles GitHub stacked pull requests, matching against the stack's base branch. See [About build triggers](/bitrise-ci/run-and-analyze-builds/build-triggers/about-build-triggers). #### Remote Dev Environments FAQ, and a corrected session retention model {#2026-08-24-remote-dev-environments-faq-and-a-corrected-session-retention-model} New [Remote Dev Environments FAQ](/bitrise-rde/getting-started/rde-faq) answers the most common questions about sessions, storage, connecting, credentials, AI coding agents, and limits. The session retention documentation was also corrected. Terminated sessions are not cleaned up after a fixed period: a session's persistent disk is kept until you delete it, or until the stack it was created from is removed under the [stack deprecation and removal policy](/bitrise-build-hub/infrastructure/build-stacks/stack-deprecation-and-removal-policy). [Key concepts](/bitrise-rde/getting-started/key-concepts) now also explains that a session stays permanently tied to the stack it was created from and can't be moved to a different one. #### Manage Remote Dev Environments access from Collaboration {#2026-08-14-manage-remote-dev-environments-access-from-collaboration} RDE is now a standalone product in workspace collaboration: grant or revoke the **RDE User** role for members and groups from the **Collaboration** page, or assign it through SCIM with `rde:rde_admin`. See [Managing RDE access](/bitrise-rde/configuration/managing-rde-access). #### Utility builds beta for Pro plans {#2026-08-06-utility-builds-beta-for-pro-plans} Short Linux builds that run on the Linux Small machine type don't count against your build quota during the beta. See [Utility builds](/bitrise-ci/run-and-analyze-builds/utility-builds). #### Edit modular YAML in the Workflow Editor {#2026-08-05-edit-modular-yaml-in-the-workflow-editor} The Workflow Editor now loads every module of a configuration split with the `include` keyword, shows the merged result, and pushes your changes back to your repository in one step. See [Editing a modular configuration in the Workflow Editor](/bitrise-ci/configure-builds/configuration-yaml/editing-a-modular-configuration-in-the-workflow-editor). ### 2026 July #### Linux tooling steps scoped to the Docker-based image {#2026-07-30-linux-tooling-steps-scoped-to-the-docker-based-image} The tooling-access steps for Build Hub Linux machines apply only to the deprecated Docker-based image. If you use `linux-bitvirt-2026`, you can skip them. See [Configuring Build Hub for GitHub Actions](/bitrise-build-hub/build-hub-for-github-actions/configuring-build-hub-for-github-actions#enabling-linux-machines-to-access-tooling). #### Select Bazel RBE worker pools by name {#2026-07-30-select-bazel-rbe-worker-pools-by-name} Remote Build Execution for Bazel now routes builds with a single `Pool=` execution property, instead of separate architecture and OS properties. #### CodePush SDK setup steps rewritten {#2026-07-30-codepush-sdk-setup-steps-rewritten} The React Native and Expo setup guides now match the current CodePush SDK, with the Expo instructions first. See [Configuring your mobile app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). #### Bitrise CI API reference corrections {#2026-07-24-bitrise-ci-api-reference-corrections} The API documentation now covers the pipeline outgoing-webhook event type, the full set of app role groups, optional Android keystore parameters, and the correct build notification defaults. #### Configuration YAML reference gains missing limits {#2026-07-24-configuration-yaml-reference-gains-missing-limits} The reference now documents the `status_report_name` and `parallel` limits, trigger priority, and the values `should_always_run` actually accepts. #### Workspace invitations can be rate-limited {#2026-07-24-workspace-invitations-can-be-rate-limited} Invitations sent from Workspaces on non-paid plans may be rate-limited. See [Workspace collaboration](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration). #### Developing a new step guide rewritten {#2026-07-20-developing-a-new-step-guide-rewritten} The walkthrough for building your own Step has been rewritten, with inaccurate statements corrected and background material trimmed. #### RDE CLI docs refreshed to match current commands {#2026-07-14-rde-cli-docs-refreshed-to-match-current-commands} The RDE CLI reference now covers stack-based session creation, running commands in a session with `session exec`, VNC tunneling, workspace selection, and the reconnect behavior of `rde claude`. See [Bitrise RDE CLI](/bitrise-rde/rde-options/bitrise-rde-cli). #### Building a Slack-native coding agent {#2026-07-10-building-a-slack-native-coding-agent} A new recipe walks through a reference architecture for a Slack-native coding agent: a locked-down orchestrator that delegates coding work to disposable Remote Dev Environments, plus an open source reference implementation you can try. See [Building a Slack-native coding agent](/bitrise-rde/recipes/building-a-slack-native-coding-agent-recipe). #### Bitrise Desktop App for macOS {#2026-07-09-bitrise-for-mac-menu-bar-app-guide} A new guide covers the Bitrise Desktop App for macOS: installing it, signing in, selecting a workspace and project, configuring filters and notifications, and troubleshooting. See [Bitrise Desktop App for macOS](/bitrise-ci/run-and-analyze-builds/bitrise-desktop-app-for-macos). #### Product subscriptions can now be canceled independently {#2026-07-07-product-subscriptions-can-now-be-canceled-independently} Each product (Bitrise CI, Build Cache, Release Management, and so on) has its own independently cancellable subscription, and add-ons can be canceled on their own too. The docs now walk through the updated **Plan & Billing** cancellation flow. See [Workspace billing and invoicing](/bitrise-platform/workspaces/workspace-billing-and-invoicing). #### Bitrise MCP server drops self-registration tools {#2026-07-02-bitrise-mcp-server-drops-self-registration-tools} The `register` and `verify_registration` tools, along with the `registration` API group, are no longer part of the Bitrise MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools). ### 2026 June #### RDE API reference now available in-site {#2026-06-29-rde-api-reference-now-available-in-site} The Remote Dev Environments REST API reference is now part of docs.bitrise.io as a native interactive explorer, covering 42 endpoints across user, workspace, sessions, templates, and saved inputs. See [RDE API reference](/bitrise-rde-api/api-reference/bitrise-remote-dev-environments-api). #### Remote Dev Environments docs now available {#2026-06-29-remote-dev-environments-docs-now-available} Documentation for Bitrise Remote Dev Environments (RDE) is now available, covering key concepts, a quickstart, configuration options (templates, saved inputs), and the available interfaces: CLI, MCP server, UI, and VS Code plugin. See [Remote Dev Environments](/bitrise-rde). #### Agent onboarding guide updated with OAuth flow {#2026-06-26-agent-onboarding-guide-updated-with-oauth-flow} The [onboarding guide for AI agents](/bitrise-platform/ai/onboarding-for-agents) now covers the full OAuth sign-in flow in detail: how your agent triggers browser authorization, creating an account during sign-in, email confirmation for password-based accounts, and troubleshooting steps for common issues. #### Entra ID SCIM provisioning guide {#2026-06-23-entra-id-scim-provisioning-guide} You can now set up automatic user and group provisioning for your Bitrise workspace using Microsoft Entra ID SCIM. The guide covers generating SCIM credentials, configuring Entra ID, attribute mapping, group and deprovisioning behavior, and migrating existing workspace members. See [Entra ID SCIM](/bitrise-platform/accounts/saml-sso-in-bitrise/setting-up-entra-id-scim-for-bitrise). #### Bitrise CI API reference is now interactive {#2026-06-22-bitrise-ci-api-reference-is-now-interactive} The Bitrise CI API reference is now available as a full interactive explorer at `/en/bitrise-api`, replacing the previous SwaggerUI embed. Endpoints are grouped by tag with a sidebar, and you can try requests directly from the docs. See [Bitrise CI API reference](/bitrise-api). #### CodePush CLI docs expanded with full reference {#2026-06-19-codepush-cli-docs-expanded-with-full-reference} The CodePush CLI documentation has been expanded and restructured. A new reference page covers all commands, global flags, environment variables, and exit codes. The [Using the CodePush CLI](/release-management/codepush/codepush-cli/using-the-codepush-cli) page now includes workflow examples, JSON output, and Bitrise CI integration details. The code signing page adds a directory naming warning and a React Native >= 0.61 Android setup note. See [CodePush CLI](/release-management/codepush/codepush-cli/about-the-codepush-cli). #### AI agent onboarding tip added to sign-up page {#2026-06-18-ai-agent-onboarding-tip-added-to-sign-up-page} The [Signing up for Bitrise](/bitrise-platform/getting-started/signing-up-for-bitrise) page now includes a tip pointing AI agents and coding assistants to the [dedicated onboarding runbook](/bitrise-platform/ai/onboarding-for-agents), which covers how to create a Bitrise account and connect everything directly from an agent session without a website visit. #### GitHub App integration: event subscriptions clarified {#2026-06-17-github-app-integration-event-subscriptions-clarified} The [GitHub App integration](/bitrise-platform/repository-access/github-app-integration) page now has an Event subscriptions section explaining that the Bitrise GitHub App subscribes to `push`, `pull_request`, and `issue_comment` events via GitHub's app installation mechanism, not through repo-level webhooks. The section also warns that any existing manual webhooks pointing to `hooks.bitrise.io` must be removed after switching to the GitHub App to avoid duplicate builds. #### Bitrise MCP: new registration tools and API group {#2026-06-15-bitrise-mcp-new-registration-tools-and-api-group} The Bitrise MCP server now includes a `registration` API group with two unauthenticated tools — `register` and `verify_registration` — that let an AI agent onboard a brand-new Bitrise user without a token. The agent sends a one-time password to the user's email via `register`, then calls `verify_registration` with the OTP to receive a personal access token. These tools are most useful with the remote (HTTP) MCP server. See [Bitrise MCP tools](/bitrise-platform/ai/bitrise-mcp/tools) for the full reference. #### Bitrise MCP: install guides added for six tools {#2026-06-15-bitrise-mcp-install-guides-added-for-six-tools} Step-by-step install guides for the Bitrise MCP server are now available for VS Code, Cursor, Claude, Windsurf, Kiro, Gemini CLI, and other Copilot-compatible IDEs. Each guide covers how to configure the MCP server and authenticate with your Bitrise token. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) to get started. #### Workflow Editor can now push bitrise.yml directly to the repository {#2026-06-11-workflow-editor-can-now-push-bitrise-yml-directly-to-the-repository} The Workflow Editor now supports pushing changes to a repository-stored `bitrise.yml` directly from the editor — either to the current branch or a new branch — without manually copying and committing. See [Storing an app's configuration YAML](/bitrise-ci/configure-builds/configuration-yaml/storing-an-apps-configuration-yaml) for the updated flow. #### Build Hub: Gradle dependency mirroring explained {#2026-06-10-build-hub-gradle-dependency-mirroring-explained} The Build Hub documentation now includes an explanation of how Gradle dependency mirroring works, giving you a clearer picture of caching behaviour for Gradle projects running on Build Hub. #### Configuration YAML docs updated for YAML/Visual mode switcher {#2026-06-09-configuration-yaml-docs-updated-for-yaml-visual-mode-switcher} References throughout the docs have been updated to reflect the new toggle between YAML and Visual editing modes in the Workflow Editor. Where instructions previously referred to the left navigation menu, they now point to the **YAML** toggle at the top of the editor. #### New guide: Maven Central repository manager {#2026-06-08-new-guide-maven-central-repository-manager} A new guide covering the Maven Central repository manager is now available under [Build Cache getting started](/bitrise-build-cache/getting-started-with-the-build-cache/maven-central-repository-manager). It explains how Bitrise's proxy cache works for Maven dependencies, covers special cases like dependency verification and custom Docker images, and documents the opt-out process. #### Bitrise MCP server: OAuth is now the primary authentication method {#2026-06-08-bitrise-mcp-server-oauth-is-now-the-primary-authentication-method} The Bitrise MCP server now uses OAuth as the primary authentication method. See [Bitrise MCP](/bitrise-platform/ai/bitrise-mcp) for the updated setup steps. ### 2026 May #### Build distribution: custom access links for installable artifacts {#2026-05-29-build-distribution-custom-access-links-for-installable-artifacts} In Release Management, you can now create shareable install links. See [Custom access links](/release-management/build-distribution/distributing-builds-to-testers#custom-access-link) for details. #### Modular YAML: increased file and nesting limits for GitHub users {#2026-05-28-modular-yaml-increased-file-and-nesting-limits-for-github-users} The modular YAML configuration guide has been updated to reflect the new, higher file count and nesting limits for GitHub users. See [Modular YAML configuration](/bitrise-ci/configure-builds/configuration-yaml/modular-yaml-configuration) for the updated limits. #### Python projects now supported {#2026-05-20-python-projects-now-supported} Bitrise now detects Python projects automatically and offers default workflows. The [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) and [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guides have been updated to include Python. ### 2026 April #### Next.js and Flutter Web project types documented {#2026-04-20-next-js-and-flutter-web-project-types-documented} The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide and [Default workflows](/bitrise-ci/workflows-and-pipelines/workflows/default-workflows) page now cover Next.js (as an extension of Node.js) and Flutter Web project types. ### 2026 March #### M4 machine type added to build machine docs {#2026-03-30-m4-machine-type-added-to-build-machine-docs} The [Build machine types](/bitrise-platform/infrastructure/build-machines/build-machine-types) page now lists the M4 machine type alongside the existing M4 Pro, M2 Pro, and M1 options, with region availability for each. #### Ruby projects now supported {#2026-03-25-ruby-projects-now-supported} Bitrise now detects Ruby projects automatically and offers default workflows. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to include Ruby. #### Pro Trial: credit card required to access the full trial {#2026-03-24-pro-trial-credit-card-required-to-access-the-full-trial} New users now need to provide a valid credit card (which won't be charged) to access the full Pro Trial. The [Getting started with Bitrise CI](/bitrise-ci/getting-started/getting-started) guide has been updated to explain this. #### New page: build artifact retention policy {#2026-03-20-new-page-build-artifact-retention-policy} A dedicated [Build artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy) page is now available, covering default retention periods by artifact type, extended retention options for enterprise customers, and the edge case around transferred projects. #### Xcode compilation cache: new flag to disable caching without disabling analytics {#2026-03-10-xcode-compilation-cache-new-flag-to-disable-caching-without-disabling-analytics} The [Xcode compilation cache FAQ](/bitrise-build-cache/build-cache-for-xcode/xcode-compilation-cache-faq) now documents the `--no-bitrise-build-cache` flag, which lets you disable caching temporarily while keeping analytics and build history intact. ### 2026 February #### Build Cache: clear cache button replaces Settings dropdown {#2026-02-20-build-cache-clear-cache-button-replaces-settings-dropdown} The [Clearing the Build Cache](/bitrise-build-cache/getting-started-with-the-build-cache/clearing-the-build-cache) guide has been updated to reflect the current UI: the Settings dropdown was replaced by a **Clear Cache** button. The guide includes a new screenshot and a note that clearing the cache requires Workspace owner permissions. #### New guide: Endpoint Detection and Response (EDR) on Bitrise {#2026-02-20-new-guide-endpoint-detection-and-response-edr-on-bitrise} A new page under Integrations explains how Bitrise uses Endpoint Detection and Response (EDR) as part of its corporate security program, and clarifies that EDR agents are not deployed on Bitrise-hosted CI runners. #### OIDC for AWS guide updated {#2026-02-13-oidc-for-aws-guide-updated} The [OIDC for AWS](/bitrise-platform/integrations/oidc-authentication/oidc-for-aws) guide has been updated with additional clarifications on configuration and usage. #### New guide: GitHub App migration API {#2026-02-03-new-guide-github-app-migration-api} A new guide explains how to use the Bitrise API to bulk-migrate projects from OAuth-based GitHub connections to the GitHub App integration, including caveats about reverting the migration. See [Adding and managing apps](/bitrise-ci/api/adding-and-managing-apps) for details. ### 2026 January #### Tool setup: new tool versions added {#2026-01-27-tool-setup-new-tool-versions-added} The [Configuring tool versions](/bitrise-ci/configure-builds/configuring-build-settings/configuring-tool-versions) guide has been updated with newly supported tool versions in the tool setup feature. #### Build artifact retention policy documented {#2026-01-19-build-artifact-retention-policy-documented} The [Build artifacts](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online) page now includes a section on the artifact retention policy, covering default retention periods by artifact type and options for Enterprise customers. The policy takes effect on March 31, 2026. #### Pipeline rebuild: dynamic parallel workflows explained {#2026-01-12-pipeline-rebuild-dynamic-parallel-workflows-explained} The guide on rebuilding failed pipelines now includes an explanation of how dynamic parallel Workflows affect rebuild options — specifically, when you can rebuild individual Workflows versus all unsuccessful ones. See [Rebuilding a failed build](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/rebuilding-a-failed-build#rebuilding-a-failed-pipeline) for details. --- ## Bitrise CI metrics Insights allows you to track three main categories of CI metrics: - Build metrics. - Test metrics. - Utilization. In addition, Insights can provide data for: - The [Bitrise Build Cache](/bitrise-build-cache). - Git operations: [Git Insights](/insights/git-insights). ### Build metrics You can access build metrics from the charts on the **Overview** page or by selecting **Builds** on the left. The build metrics are available on app-, Pipeline, Stage, Workflow-, and Step level as well: - **Top build time (p90):** The 90th percentile of build times of successful builds. In other words, out of 100 successful builds, the 90th slowest build took this long. This metric is calculated based on your Pipelines' run time if you don't have any filters selected. - **Typical build time (p50):** The median time of a successful build. In other words, out of 100 successful builds, the 50th slowest build took this long. This metric is calculated based on your Pipelines' run time if you don't have any filters selected. - **Failure rate:** The rate of failed builds, or the rate at which a given Workflow failed. For example, if a Workflow failed six times out of ten, its failure rate is 60%. This metric is calculated based on your Pipelines' failure rate if you don't have any filters selected. - **Build count:** The total number of builds started of the app or Workflow, based on the filters and the timeframe you set. - **Total duration:** The total duration of all builds of the app or Workflow, based on the filters and the timeframe you set. ### Test metrics Access testing metrics by opening the main Insights page and selecting **Tests** on the left. Similarly to basic build metrics, you can apply filters to test runs: you can filter for individual test suites, test cases, or modules, as well as to branches of your app's repository. - **Top duration (p90):** The 90th percentile of a test suite or a test case duration. If you filter on a specific test case, **Top duration (p90)** shows the 90th percentile duration of the specific test case. Otherwise, it shows the 90th percentile duration of the test suite(s) of the app or Workflow, based on the filters and the timeframe you set. 90th percentile means that out of 100 successful test executions, the 90th slowest took this much time to finish. - **Typical duration (p50):** The median (50th percentile) of a test suite or a test case duration. If you filter on a specific test case, **Typical duration (p50)** shows the 50th percentile duration of the specific test case. Otherwise, it shows the 50th percentile duration of the test suite(s) of the app or Workflow, based on the filters and the timeframe you set. 50th percentile means that out of 100 successful test executions, the 50th slowest took this much time to finish. - **Failure rate:** Test failure rate shows you how frequently a test suite or test case fails. For example, if you performed the test suite or test case 100 times, if 10 out of 100 failed, that's a 10% failure rate. If you filter on a specific test case, **Failure rate** shows the failure rate of the specific test case. Otherwise, it shows the failure rate of the test suite(s) of the app or Workflow based on the filters and the timeframe you set. - **Total duration:** The total duration of all tests of the app or Workflow, based on the filters and the timeframe you set. - **Test runs**: The total number of test runs. - **Flaky runs**: The number of test runs that produce inconsistent results despite no changes in the code. ### Utilization metrics :::important[Availability] The full utilization data described here is only available to users on a custom Enterprise plan. On other plans, you can only see your credit usage. ::: Access utilization metrics by opening the main Insights page and selecting **Utilization** on the left. The **Utilization** page shows the resources used for Bitrise builds, enabling efficient tracking of your costs. By default, the page shows all metrics based on your billing cycle. This helps to track commitments and spending during a cycle without having to do any calculations of your own. The page also shows how much time remains of the current cycle. You can change this default frame of reference in the dropdown menu in the top right corner. The **Utilization** page always shows your overall infrastructure utilization. This metric aggregates all your infrastructure utilization, including build minutes, cache storage, artifacts storage and network egress. The page compares this aggregate total to your total commitment, displaying both a monetary value and a percentage value. - **Credit usage**: Insights tracks the amount of credits used on each app and, if you need it, each Workflow of a given app. - **Build minutes**: Track how much time you spent building on the different machine types, enabling efficient tracking of computing resource consumption. You can set filters to show the data on multiple levels: build minutes per app, Pipeline, Stage, or Workflow. - **Cached invocations**: This metric shows the number of build tool invocations using the build cache. Only those invocations are counted which downloaded data from the cache. - **Network egress**: Data transfer from the build cache to external networks or clients to retrieve build artifacts. This includes data downloaded to a local development environment or to any other CI environment other than Bitrise. You can set filters and create a breakdown view of the data based on username to see how much egress is consumed by local users. --- ## Build cache metrics Build cache metrics provide data-based visibility into the [Bitrise Build Cache](https://bitrise.io/platform/devops/build-caching) system. You can achieve more consistent and reliable CI/CD workflows by reducing the unpredictability that comes with inefficient caching. If your Bitrise Build Cache is correctly set up, you need no additional configuration to access data in Insights. The following Build Cache metrics are available: - **Invocation count**: This metric shows how frequently the cache is used in your builds and helps you understand the frequency and type of commands being executed. A high invocation count indicates strong cache adoption while a low count might mean caching isn't utilized to its full effect. - **Uploads/downloads**: This measures the amount of data transfer to and from the build cache per each command. High data transfer volumes can point to excessive uploads or downloads which might slow down your builds. If downloads aren't significantly lower than uploads, it might indicate inefficient caching. Insights shows the p50 (median) value and the p90 value per invocation for both uploads and downloads: that is, how much data a given invocation uploads and downloads. ![p90-uploads.png](/img/_paligo/uuid-cb1811cf-42dd-3707-9288-42d1291a9780.png) - **Cache hit rate**: This measures the percentage of data requests that can be served by the build cache. Insights shows the p10 hit rate (meaning only 10% of cases will have an equivalent or lower hit rate) and the median (p50) hit rate. The p10 value is particularly important because a low hit rate suggests suboptimal cache configuration or incorrectly defined cache keys. For Build Cache metrics - like any other metrics in Insights - you can: - [Create a dashboard](/insights/getting-started-with-insights#creating-a-new-dashboard). - [Set alerts](/insights/configuring-alerts-in-insights) for specific thresholds. ### Common use cases for build cache metrics If your metrics show sudden and significant variation, you can check each related invocation to find out when the issue started. Filter to the relevant item/time period and then select the **Related invocations** tab. This can be useful for both uploads/downloads or cache hit rate. For example, if there is a sudden spike in uploads compared to downloads, it might mean that data is being repeatedly generated and stored but rarely reused, reducing efficiency: ![trends.png](/img/_paligo/uuid-5d4f1f7c-0ca9-93fb-251c-4b63c26f1f4b.png) ![issues-list.png](/img/_paligo/uuid-7d6dc7a5-d2ad-0a24-e940-6ce654e08db4.png) For another example, here's a sudden change in cache hit rate for a given Workflow, suggesting a weak spot in the caching setup: ![cache-hit-rate-workflow.png](/img/_paligo/uuid-cf5db37b-0d3a-2292-c706-28a35c9c342e.png) You can look at the invocation count to identify when a project started (when the invocation count suddenly spikes) or stopped (when the invocation count suddenly drops) using the Build Cache: ![started-build-cache.png](/img/_paligo/uuid-d2661447-265a-5f94-41dc-40c36c7acad6.png) ![stopped-using-cache.png](/img/_paligo/uuid-8f7bf7cb-1d82-dacf-ecc0-b3e98438c118.png) This can help, for example, detecting and fixing configuration issues that break the cache setup. --- ## Command metrics Command metrics provides data-driven visibility into your Gradle and Bazel command performance. Command metrics are available as part of the [Bitrise Build Cache](https://bitrise.io/platform/devops/build-caching): if you have a working Build Cache setup, you will have access to these metrics in Insights. :::note[Caching performance] Even though command metrics are available only with the Bitrise Build Cache, they don't measure cache performance. For that, see [Build cache metrics](/insights/available-metrics-in-insights/build-cache-metrics). ::: You can view command performance by logging into Insights and selecting **Commands** on the left navigation menu. The following metrics are available: - **Duration (p50 and p90)**: The duration metric measures command execution times. Knowing how long your commands are running help pinpoint bottlenecks, optimize build times, and improve productivity. For example, you can identify which commands are taking longer than expected and focus your optimization efforts there. - **Error rate**: The rate of commands that fail. A lower error rate means more reliable builds and fewer disruptions to your CI/CD pipeline. High error rates on specific commands can flag a need for action, to dive deeper and resolve the cause of any instability. - **Invocation count**: This metric measures how often specific Gradle and Bazel commands are executed. It can highlight commands that are overused or run reduntantly. If you see a certain command running too often, it may be worth investigating if you can restructure your pipeline to avoid overusing commands. Like for any other metrics in Insights, you can: - [Create a dashboard](/insights/getting-started-with-insights#the-dashboards-page). - [Set alerts](/insights/configuring-alerts-in-insights) for specific thresholds. --- ## Configuring alerts in Insights Insights allows you to configure alerts. Alerts monitor specified metrics and notify you when they reach a certain threshold. For example, you can configure an alert to notify you when a build of any of your apps exceeds 15 minutes or consumes more than a 1000 credits. You can configure alerts for: - Builds - Tests - Credit usage For each category, you can set alerts for any of the available metrics: [Bitrise CI metrics](/insights/available-metrics-in-insights/bitrise-ci-metrics). For each alert, you have to choose how to receive the notification. There are three options: - Microsoft Teams: The alert will post a notification to a Teams channel of your choice. [You need to configure incoming webhooks in Teams](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=dotnet). - Slack: The alert will post a notification to a Slack channel of your choice. You need [a Slack app with incoming webhooks enabled](https://api.slack.com/messaging/webhooks). - Email: The alert will notify you via email. ### Creating a new alert You can create a new alert at any time in Insights: 1. Open Insights for your project. 1. Go to the **Create alert** page. To do so, you have two options: - Select **Alerts** from the left menu and click on **Create alert**. ![create-alert-button.png](/img/_paligo/uuid-6df6ae6a-869d-58a9-dbea-2fa93fba24e2.png) - Click on the bell icon above any metric in **Builds**, **Tests**, or **Credits**. ![bell.png](/img/_paligo/uuid-d7b270fb-8c64-ce2d-c083-c1dbcfdde87f.png) 1. Choose a metric type and a specific metric within that type in the **Metric type** section. ![metric-type.png](/img/_paligo/uuid-3cab36a0-7c43-5fb3-40cb-d7c03cd8ab00.png) 1. In the **Filters** section, select a project then click **Add filter** to add filter conditions. If you don't select a project, the alert will apply to every project in the workspace, without filters. You can create filters for a specific [Pipeline](/bitrise-ci/workflows-and-pipelines/build-pipelines/pipelines-with-stages/configuring-a-pipeline-with-stages), a Workflow, or even a Step. You can also filter for branches, [stacks](/bitrise-build-hub/infrastructure/build-stacks/about-build-stacks), and [machine types](/bitrise-platform/infrastructure/build-machines/about-build-machines). ![alert-filters.png](/img/_paligo/uuid-918b42a8-4b92-3f05-5514-1b137c85e283.png) 1. In the **Conditions** section, set up the alert conditions. - **Direction**: Choose whether to create an alert when a given threshold is above, equal, or below a certain limit. - **Threshold**: The value the direction applies to. The exact nature of it depends on the metric you chose: for example, if you chose credit usage, you can set an amount of credits consumed to trigger an alert. - **Monitored window**: The time period that the alert monitors. 1. In the **Notifications** section, name the alert in the **Alert name** field. 1. In the **Notification providers** section, click **Add new** and choose between three notification providers from the dropdown menu: - **Slack**: Create an incoming webhook that posts into a selected channel and paste the webhook URL. To do so, you need to create a Slack app and enable incoming webhooks in the app: [Sending messages using incoming webhooks](https://api.slack.com/messaging/webhooks). - **Teams**: Create an incoming webhook for a selected Teams channel and paste the webhook URL: [Create incoming webhooks for Teams](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=dotnet). - **Email**: Set a valid email address. The alert will send a notification to the address. 1. When you're ready, click **Create** to finish the alert. ### Editing an existing alert Once an alert is in place in Insights, you can modify it at any time from the **Alerts** page. You can change the threshold, the granularity (the time period the alert applies to), or modify the notification providers. :::important[Metric type can't be changed] You can't modify the metric type that the alert monitors. For example, if the alert is monitoring build failure rate, you can't change it to monitor credit usage instead. Similarly, you can't change the filtering: if you were monitoring a specific app, you can't change the alert to monitor a different app instead. If you need a similar alert for a different metric or with a different filter, duplicate the existing alert: [Duplicating an existing alert](/insights/configuring-alerts-in-insights#duplicating-an-existing-alert). ::: To edit an alert: 1. Open Insights for your app. 1. On the left, select **Alerts**. ![alerts.png](/img/_paligo/uuid-3c75e562-bf1f-266f-ec68-910589ed408e.png) 1. Select the alert you need and on the right, click the **View alert** button. ![existing-alert.png](/img/_paligo/uuid-387f919f-49c9-14ae-cb62-1bc4f47cda1e.png) 1. On the alert's page, click the ellipsis in the top right corner to open the context menu. ![edit-alert.png](/img/_paligo/uuid-a493c03e-ab64-9b02-748d-556fdd1c1b1a.png) 1. Select **Edit alert**. 1. Modify the threshold, the granularity, or the notification provider. 1. Click **Save**. ### Duplicating an existing alert You can duplicate any existing alert and then modify it during the alert creation process. This allows users to quickly create new alerts based on existing ones. To duplicate an alert: 1. Open Insights for your app. 1. On the left, select **Alerts**. ![alerts.png](/img/_paligo/uuid-3c75e562-bf1f-266f-ec68-910589ed408e.png) 1. Select the alert you need and on the right, click the **View alert** button. ![existing-alert.png](/img/_paligo/uuid-387f919f-49c9-14ae-cb62-1bc4f47cda1e.png) 1. On the alert's page, click the ellipsis in the top right corner to open the context menu. ![edit-alert.png](/img/_paligo/uuid-a493c03e-ab64-9b02-748d-556fdd1c1b1a.png) 1. Select **Duplicate**. 1. The duplicate feature takes you [to the **Create alert** page](/insights/configuring-alerts-in-insights#creating-a-new-alert), with the existing alerts values already set. Make your changes and then click **Create** at the bottom of the page. --- ## Getting started with Insights Insights constantly tracks the performance of all the projects of your Workspaces. You can get aggregated build data of all your projects, detailed metrics of each project, and you can even categorize the metrics as you see fit using dashboards. Insights also allows you to view bottlenecks: it shows you the Workflows and tests that take the most time or cost you the highest amount of credits. To get to your Workspace's Insights page: 1. Log in to your Bitrise account. 1. In the top right corner, open the account selector dropdown menu and select a Workspace. 1. On the header, click **Insights**. This takes you to the **Overview** page of the selected Workspace. ### The Overview page On the **Overview**, you can see aggregated build data of the selected Workspace. You can see both aggregated build data and project-level build data in the form of charts that cover the [selected timeframe](/insights/getting-started-with-insights#viewing-data-from-a-specific-timeframe). ![Insights_overview.gif](/img/_paligo/uuid-dbb181a9-053e-bed3-133f-11e485313efa.gif) You can switch between Workspaces at any time: in the top right corner, open the account selector dropdown menu and select a Workspace. ### Accessing the build metrics You can get to the detailed build metrics of your Workspace or a specific app in two ways: you can simply select **Builds** on the left, or you can choose a specific metric from the **Overview** page of the Workspace. We'll go through the second method: 1. Open the **Overview** page of your Workspace. 1. Find the metric you need. For example, **Build failure rate**. 1. Click **View details**. If you have more than one project in the Workspace, on the Details page you will see the aggregated metrics for all projects of the Workspace by default. 1. From the leftmost dropdown menu, select the project you need. 1. Optionally, you can dig deeper by adding filters using the **Add filter** button to view specific data. You can filter for: - Pipelines: metrics of builds that ran with a specific Pipeline of the project. - Stages: metric of builds that ran with a specific Stage of a Pipeline. - Workflows: metrics of builds that ran with a specific Workflow of the project. - Branches: metrics of builds of a specific branch. - Machine types: metrics of builds that ran on a specific machine type. - Stacks: metrics of builds that ran on a specific stack. ![filtering_highlight.png](/img/_paligo/uuid-0242fdf7-4025-4aca-215a-ffbecf5e62b9.png) 1. Scroll down to see individual builds, their data, including the Steps they ran with. For the available build metrics, check out [Bitrise CI metrics](/insights/available-metrics-in-insights/bitrise-ci-metrics). ### Accessing the testing metrics of an app Insights allows you to keep track of testing metrics, right down to the level of individual testing modules. To do this, you need a testing Step that exports its results to the [**Deploy to Bitrise.io - Build Artifacts, Test Reports, and Pipeline intermediate files**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step. The following Steps do this automatically, without any need for additional configuration: - [**Xcode Test for iOS**](https://github.com/bitrise-steplib/steps-xcode-test) - [**Android Unit Test**](https://github.com/bitrise-steplib/bitrise-step-android-unit-test) - [**iOS Device Testing**](https://github.com/bitrise-steplib/steps-virtual-device-testing-for-ios) - [**Virtual Device Testing for Android**](https://github.com/bitrise-steplib/steps-virtual-device-testing-for-android) - [**Flutter Test**](https://github.com/bitrise-steplib/bitrise-step-flutter-test) If you use any of these Steps to run your tests, you can check your metrics in Insights: 1. Open Insights. 1. On the left, select **Tests**. 1. From the leftmost dropdown menu, select the project you need. 1. Optionally, you can dig deeper by using filters to view specific testing data. You can filter for: - Test suites - Test cases - Modules - Branches ![testing_metrics.png](/img/_paligo/uuid-ce8ef015-6c7d-9b31-d3ce-69669a18b4ac.png) 1. Scroll down to see the individual test cases. For the available test metrics, check out [Bitrise CI metrics](/insights/available-metrics-in-insights/bitrise-ci-metrics). ### Bottlenecks The **Bottlenecks** section helps you understand where you can save the most time or credits. We show you which of your Workflows and tests take the longest time and cost the highest amount of credits. To access the Bottlenecks page, simply select **Bottlenecks** on the left. The bottlenecks are divided into the three basic categories we use for all metrics: **Builds**, **Tests**, and **Credits**. Each category has three metrics: - **Failing Workflows/Failing tests**: these are the failing Workflows or test cases that have the highest impact on the time or credits used on your builds. - **Build time/Run time**: Workflows with increasing build times, or test cases with increasing run times. - **Usage/Flakiness**: Workflows that consumed the highest amount of resources (either time or credits), or test cases with the most flaky runs. ### Viewing data from a specific timeframe By default, all Insights pages display your metrics on a weekly basis from the last 12 weeks. Modify the basis and timeframe by opening the respective dropdown menu in the top right of the page, and selecting the options you need. ![builds_timeframe.png](/img/_paligo/uuid-a5b75043-f9b0-b1c3-51ac-dc1be80e1034.png) ### The Dashboards page You can use the Insights Dashboards page to categorize the charts of your Workspace so that you can view them in one place. You can combine charts from the Builds, Tests, and Credits tab into a single dashboard, and you can have as many dashboards as you want. ![dashboards.png](/img/_paligo/uuid-fc575279-c87c-1046-a747-4ea6a59fae5f.png) #### Creating a new dashboard You can create a new dashboard either from the Dashboards page or by clicking on the **Add to dashboard** button (![Add_To_dashboard.png](/img/_paligo/uuid-26a387b3-ea77-211f-b2f8-09325e1cc44a.png)) and clicking the **Create dashboard** button. We will focus on the former method in this guide: 1. Open Insights. 1. On the left, select **Dashboards**. 1. Click on **Create dashboard** to open the **Create dashboard** window. ![Create_dashboard.png](/img/_paligo/uuid-6da7408c-facc-9a1a-b494-b9acdf47accb.png) 1. Add the name of the dashboard under the **Dashboard name** filed and optionally add a description under the **Description** field. 1. Select the default view of granularity and time range. You can also change these options later. 1. Click on **Create**. #### Accessing a dashboard To access a dashboard: 1. Open Insights. 1. On the left, select **Dashboards**. 1. Click on the name of the dashboard or the arrow icon ("![project_selector_arrow.png](/img/_paligo/uuid-06b2413b-0794-39ff-c8b0-176c85c8e1e1.png)") to open a specific dashboard. From here, you can see the charts you previously added to your dashboard. For more information, check out [Adding a chart to a dashboard](/insights/getting-started-with-insights#adding-a-chart-to-a-dashboard). #### Adding a chart to a dashboard You can add any chart from the **Builds**, **Tests**, and **Credits** tabs to your dashboard: 1. Open Insights. 1. Select the **Builds**, **Tests**, or **Credits** tab on the left. 1. Search for the metric you want to add to your dashboard. 1. Click on the **Add to dashboard** ( ![Add_To_dashboard.png](/img/_paligo/uuid-26a387b3-ea77-211f-b2f8-09325e1cc44a.png) ) button next to it. 1. Insert a name under the **Chart name** field. 1. Select the dashboard where you want to place this chart using the dropdown menu. 1. Click **Add**. That's it! From now on you will be able to see your chart on the **Dashboard** page. :::tip[Removing a chart from a dashboard] You can remove a chart from a dashboard using the edit mode. For more information, check out [Editing a dashboard](/insights/getting-started-with-insights#editing-a-dashboard). ::: #### Editing a dashboard Once you have created a dashboard, you can edit it as you see fit. Among other things, you can edit the default time range or delete charts you may no longer need. To do so, you must use the **Edit mode**: 1. Open Insights. 1. On the left, select **Dashboards**. 1. [Access the dashboard](/insights/getting-started-with-insights#accessing-a-dashboard) you would like to edit. 1. Click the options menu (⋮), then click **Edit mode**. ![Edit_mode.png](/img/_paligo/uuid-d21f2840-9772-4870-9818-a3fd1162be1f.png) 1. In the edit mode, you may change the dashboard's general settings by clicking on the **Settings** button. You can also change the name of previously added charts or remove them using the icons next to them. ![Edit_mode_opened.png](/img/_paligo/uuid-cac01df1-7cc0-598f-62b5-87a237ecc669.png) 1. Click on **Save** after you finish editing the dashboard. ### Creating alerts You can create alerts for metrics that you would like to keep an eye on to trigger when a specific threshold is reached. You can then push the alert notifications to Slack channels, email addresses, or Teams channels. To learn more about alerts: [Configuring alerts in Insights](/insights/configuring-alerts-in-insights). --- ## Git Insights Git Insights enables you to quantify and optimize Git collaboration. It provides crucial metrics like pull request cycle time and merge frequency. :::important[Git provider requirements] Git Insights is only available if your repository is hosted on one of three Git providers: - GitHub - GitLab - Bitbucket. ::: ### Configuring webhooks for Git Insights To use Git Insights, you need to [register a webhook](/bitrise-platform/integrations/webhooks/adding-incoming-webhooks) with your Git provider. Without a webhook, Bitrise can't access your pull request data. :::important[Updating existing webhooks] If you already have webhooks registered to [automatically trigger builds](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) on Bitrise, check that their permissions match the requirements of Git Insights and update them if necessary. ::: Git Insights requires the following webhook permission from the three supported Git providers: - **[GitHub](https://docs.github.com/en/webhooks/using-webhooks/editing-webhooks)**: Pushes, Pull requests. ![github-webhook-permissions.png](/img/_paligo/uuid-7a681d2b-732b-b061-0eb1-ecd158c0a9b9.png) - **[GitLab](https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#configure-a-webhook-in-gitlab)**: Push events/All branches, Merge request events. ![gitlab-webhook-settings.png](/img/_paligo/uuid-130fe737-4629-1dfa-3234-9c03ad22f5dc.png) - **[Bitbucket](https://support.atlassian.com/bitbucket-cloud/docs/manage-webhooks/)**: Repository: Push; Pull request: Created, Updated, Merged. ### Accessing Git Insights To access Git Insights: 1. Log in to Bitrise. 1. Select a Workspace in the top right corner of the Dashboard. 1. On the menubar on the top, select **Insights**. 1. On the left, select **Git**. ![git_-insights.png](/img/_paligo/uuid-33016129-6c3c-5427-c4ac-8dca1c01770d.png) ### Using Git Insights Git Insights can show aggregated metrics for all apps of a Workspace, or metrics for each individual app: ![apps-filter.png](/img/_paligo/uuid-0b5537ea-42ab-780f-cd11-05072d508a72.png) You can also filter for the target branch of the pull requests: once you selected an app, click **Add filter** next to the app dropdown menu. Git Insights offers two main metrics for now: cycle time and merge frequency. **Cycle time** means the time elapsed between opening a PR and merging it. It is further broken down into two separate metrics: - **Development time**: The time between the first commit of a PR and opening the PR. - **Review time**: The time it takes from opening the PR to the PR being merged into the target branch. **Merge frequency** means the number of times a PR has been merged in a given period. You can see these metrics on the main chart where you can switch between displaying cycle time and merge frequency: ![git-main-chart.png](/img/_paligo/uuid-ef391d65-8868-242c-c6b6-380d117676b7.png) The **Breakdown** tab allows users to view detailed information for each application or target branch by time period. For example, you can check the total merge frequency for a target branch in any given week over a month: ![breakdown-tab.png](/img/_paligo/uuid-7bf083ec-108e-2c84-cb3e-b47a85b69a48.png) The content depends on your settings and filters: - If you look at the aggregated data of all applications, the **Breakdown** tab displays data on a per application basis. - If you filter the data for a specific application, the **Breakdown** tab displays data on a per target branch basis. The **Related PRs** tab shows relevant metrics for each individual PR that is represented in the dataset. By clicking anywhere in the row, you can go to the PR's page. --- ## Insights(2) --- ## Credit usage :::important[Credit-based plans only] This article is only relevant if you are on a [credit based (pay-by-minute) subscription plan](http://www.bitrise.io/pricing). Users who aren’t on a credit based plan don’t see the Credits page on Insights. ::: Keeping an eye on your credit usage can help to avoid surprises caused by changes which result in increased credit usage. Using Bitrise Insights you can see your credit usage trends and if you notice any negative trend you can use Insights to track down what is causing that. ### Tracking overall credit usage When you open Bitrise Insights you start on the **Overview** page. Scroll down to the Credit usage section to see your Workspace’s overall credit usage and the top 5 apps using the most amount of credits. ![overview-credits.png](/img/_paligo/uuid-c0daa517-7b8f-10d5-c390-511c68829d40.png) If you want to predict your credit usage switch over to the **Credits** page, either by clicking the **Credits** option under the **EXPLORE** section in the left sidebar, or click the **View details** button in the **Credit usage** section. On the **Credits** page by default you’ll see your last 12 weeks (3 months) credit usage trend on a week-by-week basis.To predict how much credits you’ll use you have a few options. ![credits-page-home.png](/img/_paligo/uuid-cf875ee5-ad50-e67e-eeb9-059ac158285d.png) Switch to monthly view to see your last 6 months credit usage, the trend of your credit usage, and the current month’s usage so far. Alternatively you can also switch to daily view (**Last 30 days**) and change the chart to **Cumulative** to see how much credit you used in the last 30 days and the trend of it: ![cumulative-credits.png](/img/_paligo/uuid-b309f819-a995-58ae-e686-2e98ac27a1c3.png) If the trend is fairly stable (no large jumps and drops) then most likely you’ll use about the same amount of credits than what you did in the last 30 days, which you can see in the upper left corner under **Credit usag**e. Comparing this daily to the monthly view should give you a good guidance about how much credit usage you should expect in the month and how that compares to your previous months' credit usage. ### Credit usage by app, Workflow or Step Open the **Credits page** under the **EXPLORE** section in the left sidebar. You can also switch to weekly view, to the last 12 weeks, if you’re not already in weekly view: ![weekly-view.png](/img/_paligo/uuid-0c1048ad-a593-b587-4dad-63c8cb4ddfc1.png) Just like on any other Explore pages you’ll see two charts. The upper chart always shows you data for the filters you set. The lower chart is called the breakdown chart and it shows you data one level deeper than what you filtered on. If you have only a single app in your Workspace then Insights will automatically select that app when you open any of the Explore pages. If you have multiple apps in your Workspace, when you open the **Credits** page the upper chart shows you the overall credit use of the Workspace across all of your apps in the Workspace. The lower chart in this case shows you the same data but on a per app basis. From this you can see which app used the most amount of credits in the selected time period. ![costliest-app.png](/img/_paligo/uuid-27ec3df6-bdce-7f78-95be-647668661e56.png) Here on the breakdown chart you can see that we have this application which used the most amount of credits in this Workspace. Filter down to that app, and on the next level you'll find the per Workflow breakdown. The upper chart now shows what is filtered on, so in this case it's the selected app's credit usage. On the lower, breakdown chart you can see which is the Workflow which used the most credits. ![costliest-workflow.png](/img/_paligo/uuid-71015c65-9c35-e1b8-e5fc-9bf9d1833731.png) Let's filter down to that Workflow. The chart now reflects this filtering and shows the credit usage trend of the Workflow. From here we should find out what is causing this credit usage increase in this Workflow. This might be caused by slower builds, increased amount of builds, or by changing the machine type to one which uses more credits per minute. To investigate this switch over to the **Builds** page. When you switch to any other Explore pages the filters you previously selected will carry over, so you won’t have to select the same app and Workflow again.In this case going through the metric tabs most metrics seem stable during this period, but we can see a similar pattern on the **Total duration** metric: ![total-duration.png](/img/_paligo/uuid-f20ee280-d116-8015-6f87-2fd8b74da9a2.png) Similar to the **Credits** page, the **Builds** page also has 2 charts on it. The top one shows the selected metric (**Total duration** in this case) for the relevant filters (for the selected app and Workflow). The lower breakdown chart shows the per step distribution of the total build duration. From this we can see that the **iOS Device Testing** Step took the most amount of time and it also correlates with the overall trend. As build times and build count was consistent for the whole 12 weeks, and the only other metric which had a change during this period was **Failure rate**, let’s switch over to that tab: What we can see here is that where we had the drop in credit usage as well as in total duration the **iOS Device Testing** Step had a 100% failure rate. As failed Steps usually take less time to finish, let’s check the related builds as well in the **Related builds** section under the charts. ![ios-device-testing.png](/img/_paligo/uuid-c81ac3ec-31ee-45b9-3be1-497feae7a780.png) To find the relevant builds we’ll zoom into the period where failure rate increased. The easiest way is to click-hold-and-drag on the chart. Let’s filter down to just this single Step as well in the **Related builds** section: ![related-builds.png](/img/_paligo/uuid-86def2f6-adbf-52b0-1bf9-dbe7ca05c08f.png) Now we can scroll through the build history and see how the build time of this Step changed. At the end of the period, where the failure rate was 100% we can see that it only took a few seconds: ![step-failed-quickly.png](/img/_paligo/uuid-86871cee-ac96-75d5-d63b-bc5daa5b56c2.png) As we keep scrolling we can see that back in early December where we still had successful builds the Step took multiple minutes to complete: ![step-took-long.png](/img/_paligo/uuid-c92d5036-7f13-9541-6a80-0614d27e928d.png) So in this case the drop on the total duration (and in credits) was caused by this Step failing a lot, which meant that builds completed quicker, until the issue with the tests was fixed, when the Step and the builds once again took longer to finish, but could actually run and finish the tests. Another place which worth to be checked periodically is the **Bottlenecks** page: ![bottlenecks-overview.png](/img/_paligo/uuid-6b2fbeca-bd57-7bfa-2ba6-7bb84f9036b4.png) On this page you can find a **Credits** section where Bitrise Insights highlights you negative trends which consumed the most amount of credits. **Failing Workflow**s shows you Workflows which had a lot of credit usage on failed builds. On the example above you can see that the Workflow called test failed in 73.68% of the cases in the last 7 days and those failed builds consumed 624 credits in total. Build time shows slowing build trends, where the build took longer in the last 7 days than in the 7 days before that, and tells you the credit impact of that negative trend. The **Usage** bottleneck simply lists you the Workflows which used the most amount of credits in the last 7 days. Clicking any of these bottleneck items will open the relevant Explore page filtered down to the Workflow. --- ## Monitoring and optimizing your slowest mobile builds Slow builds result in people having to wait for the build to finish. Even if they switch to do something else while the build is running, there will be a context switch when they have to switch back once the build is done. During a pull request review, you might have to do multiple builds, as you do changes and improvements based on the reviewer’s feedback or based on automatic linters. The slower the mobile build, the more you’ll have to wait throughout the pull request process. Slow builds are even worse if the build fails afterward. In that case, you’ll have to fix or change something and then do the build again — costing you even more build time. If the build takes a long time, you’ll have to wait a lot for the build to fail, and then fix the issue and start a new build, and wait for that too. This is especially bad if a release or deploy build fails, where you usually have to fix it as soon as possible and try it again. Another impact of slow builds is how quickly you can iterate on the mobile build’s configuration. Whenever you make changes you’ll want to test the new configuration by starting a new build. If that build takes a long time your iterations will be slow. This is even more important if you then have to do follow-up changes, either because that test build fails, or because you forget to add something to the configuration — or maybe you’ll just want to clean up a few things. If the build is slow you’ll have to wait a long time between every iteration. The faster you can iterate the more things you can try, the more improvements you can do, and the more chances you’ll have to make mistakes and fix them in a given amount of time. The main goal is to reduce the wait time throughout the development process. If you have mobile builds which take a long time to finish that means that sooner or later you’ll have to wait for it, and most likely lose time either 1) because of context switching or, 2) because you can’t do anything useful while you’re waiting for the results of that build. ### Finding slow builds So, how can you monitor your build time and how can you diagnose and improve them using Bitrise Insights? When you open Bitrise Insights you can find the **Successful build time** chart on the **Overview** page. Here you can see your overall build time trends in the whole Workspace and you can also see the top 5 slowest apps' build time trends. From here you can continue your investigation using either the **View details** button or by clicking the **Builds** page under the **Explore** section in the left sidebar: ![builds-explore.png](/img/_paligo/uuid-c73e996d-b1f3-422a-f317-5ec31fedcd68.png) When you open the **Build Explore** page there are two relevant [metrics](/insights/available-metrics-in-insights/bitrise-ci-metrics) you can check related to build times. The **Top build time (p90)**, which is the 90th percentile, and the **Typical build time (p50)**, which is the 50th percentile. :::note[Percentile definitions] 50th percentile means that out of a hundred builds the 50th slowest one took this long to finish. The 90th percentile means that out of a hundred builds 90 finished around this time or faster. ::: On the **Build Explore** page, you can start from the Workspace level, which you can see on the upper chart if there are no filters applied. Using the intelligent breakdown (the 2nd chart) you can drill into the data to find which application, which Workflow, and which Step is affecting the build time trend that you are checking. Let's go through an example. Here on the breakdown chart, you can see that we have this application which is the slowest in this Workspace: ![explore-builds-example.png](/img/_paligo/uuid-1789f853-23db-4863-8ecc-70e6a837ad2f.png) Filter down to that app in the dropdown menu on the top left, and on the next level, you'll find the per Workflow breakdown. The upper chart now shows you what is filtered on, so in this case, it's the selected app's p90 build time. On the lower breakdown chart, you can see which Workflow takes the longest. Let's filter down to that Workflow. ![filter-by-workflow.png](/img/_paligo/uuid-f1483521-2b52-d69c-9cbb-ae0eff053094.png) The upper chart now reflects this filtering, and the breakdown chart switched over to per-step build times. Using the breakdown chart you can find out which Step is causing the build time trend that we are investigating. Under the graphs, you can also see the build history which is filtered based on the filters that you set at the top and also on the time range that you set in the top right corner. When you find the builds that correlate with the trend that you're checking then you can quickly jump to the relevant build's page and then continue your investigation there: ![build-history.png](/img/_paligo/uuid-ac92de93-beb4-8a7d-d28c-0fe5cc8296b8.png) ### Diagnosing bottlenecks in your builds On the **Bottlenecks** page, Insights shows you negative trends from the last 7 days. The relevant bottleneck to look out for is the **Build time** one, which lists workflows that became slower in the last 7 days compared to the previous 7 days. ![bottlenecks-overview.png](/img/_paligo/uuid-6b2fbeca-bd57-7bfa-2ba6-7bb84f9036b4.png) It lists the Workflows based on the time impact of that slowing trend. This is usually a good place to check, as the time impact calculated here reflects both the % increase in the 50th percentile build time. It also takes into account how many builds you had in the last 7-day period. For example, one of your Workflows took 2 minutes more to build, but you only had a few builds with that Workflow — on the other hand, another Workflow had only a 1-minute build time increase, but had tens or hundreds of builds with that Workflow. In this case, the second Workflow will have a higher time impact and will be listed higher on **Bottlenecks**. If you don’t have any Workflows listed in the **Build time** section that means that none of your Workflows had a significant build time increase. Monitor and improve the most important metrics, and you'll reduce the wait time in your app development process. In addition to that, you'll also improve developer productivity and happiness! If you have any questions or feedback, please let us know using the Give feedback button in the bottom left corner on any of the Bitrise Insights pages! --- ## Tracking build failure rate For every failed build, you’ll most likely have to 1) spend time to fix the failure, 2) then try the build again, and 3) then wait for the retried build to finish. Even if you can switch to do something else while the build is running there will be a context switch when you have to switch back once the build is done. If your build failure rate is high on a specific app’s or Workflow’s builds, that means people frequently spend time on debugging, fixing and then retrying builds. Failure rate is especially crucial for long builds, as the engineers will have to wait even more when they do a fix and then run a new build. Tracking and reducing the frequency of failed builds can help minimizing the time and effort spent on resolving build failures and increase the overall efficiency and productivity of your team. The main goal is to reduce the wait time throughout the development process. If you have builds which fail frequently that means that sooner rather than later you’ll have a failing build, where you’ll have to check why it failed, fix the issue, and then try it again and wait for the build to hopefully pass. As part of this you’ll likely lose time either because of context switching or because you can’t do anything useful while you’re waiting for the results of that build. ### Finding frequently failing builds When you open Bitrise Insights, you can find the **Build failure** rate chart on the **Overview** page. Here you can see your overall build failure rate trend in the whole Workspace and you can also see the top 5 most frequently failing apps' build failure rate trends. From here you can continue your investigation using either the View details button or by clicking the **Builds** page under the **EXPLORE** section in the left sidebar. After you open the **Builds** page switch to the **Failure rate** tab. ![failure-rate-tab.png](/img/_paligo/uuid-605f48bd-0c0c-9003-4605-0b682c26dc57.png) On the **Builds** page, depending on which filters are applied, you can start from the Workspace level which you can see on the upper chart. Using the intelligent breakdown (the 2nd, lower chart) you can drill into the data to find which application, which workflow, which step is causing the build failure rate trend that you are checking. Let's go through an example. Here on the breakdown chart you can see that we have this application which is failing most frequently in this Workspace: ![most-failing-app.png](/img/_paligo/uuid-80961ec0-a95b-8cce-6af1-263d07fcc5a4.png) Filter down to that application, and on the next level you'll find the per Workflow breakdown. The upper chart now shows what is filtered on, so in this case it's the selected app's failure rate. On the lower, breakdown chart you can see which is the Workflow which fails most frequently. Let's filter down to that Workflow: ![workflow-breakdown-chart.png](/img/_paligo/uuid-211085d7-b298-e040-1432-189aa06bca6c.png) The upper chart now reflects this filtering, and the breakdown chart switched over to per Step failure rate. Using the breakdown chart you can find out which Step is causing the failure rate trend that we are investigating. Under the graphs you can also see the build history which is filtered based on the filters that you set at the top and also on the time range that you set in the top right corner. Hovering on the bars you can see how long specific Steps took and in which build that step failed. When you find the builds which correlate with the trend that you're checking then you can quickly jump to the relevant build's page and then continue your investigation there. ![failed-build-history.png](/img/_paligo/uuid-6507d4b6-e17c-fe9a-7fcf-286e99bf5447.png) ### Diagnosing bottlenecks causing builds to fail There’s another page that is worth checking periodically in Insights: the **Bottlenecks** page: ![bottlenecks-menu-option.png](/img/_paligo/uuid-3861bf61-778c-af22-dad4-28d5b52cf1f0.png) On the **Bottlenecks** page Insights shows you negative trends from the last 7 days. The relevant bottleneck is the **Failing Workflows** one, which lists Workflows which consumed the most amount of time to fail. It lists the Workflows based on the time impact of the failing builds. This is usually a good place to check as the time impact calculation here reflects both how frequently the builds of a given Workflow fail as well as how long those failing builds take. The time impact listed on this page is the total amount build time of the failing builds for that Workflow in the last 7 days. In the example above it means that the **bullseye** app’s **test** Workflow builds failed in 73.68% of the cases, and in total those failed builds consumed 1 hour and 38 minutes in the last 7 days. By listing the Workflows based on time impact instead of based on just the failure rate, the **Bottlenecks** page helps you to focus on the most impactful build failure trends. As an example, if you have a Workflow which had only a few builds and those all failed, while another Workflow had tens or hundreds of builds and it failed in 50% of the cases, if both Workflows builds are about the same length the second Workflow will be ranked higher, as overall those failed builds caused more wait time for engineers. Keeping an eye on and improving your build failure rate helps you to reduce wait time during the app development process and to increase the efficiency and productivity of your team. --- ## Tracking flaky tests Flaky tests are a persistent issue that can make a mobile developer's life frustrating and challenging. Failing tests that produce different results even when the code hasn’t changed can cause confusion and setbacks, leading to time-consuming and frustrating debugging sessions. Eliminating flaky tests is essential for ensuring a stable and reliable testing process. This article explores the importance of tracking flaky tests with Bitrise Insights, and how to diagnose the causes behind them. Additionally, it also discusses how Bitrise Insights can detect flaky tests, and how developers can use the tool to track, identify, and diagnose the flakiness of their tests. ### The importance of tracking flaky tests First, what is a flaky test and how is it calculated? A test is flaky if it produces different results even when the code isn’t changed. For example, this simple code will sometimes fail and other times it’ll be successful, without any code change: ```bash randNum := r1.Intn(100) require.Equal(t, true, randNum > 40, "More than 40?") ``` Flaky tests are a special case of failing tests, and probably the most crucial ones to fix. Flaky tests are a persistent problem that can make a developer's life frustrating and challenging. They are a unique type of failing tests that may cause confusion and setbacks even when the code change being made is functioning as intended. Unlike other failing tests, flaky tests can cause failures in seemingly unrelated parts of the code, leading to time-consuming and frustrating debugging sessions. Fixing flaky tests is essential for ensuring a stable and reliable testing process. Eliminating flaky tests is not only important to prevent time waste, but is also crucial to improving developers' confidence in the tests. If tests fail randomly, developers will start to ignore test failures over time. Bitrise Insights can detect when a test produces inconsistent results for the same code state. For builds which have a code commit hash information specified when triggered (usually all builds except manually triggered and scheduled ones) it can detect this across builds (where the commit hash is the same, but the test had multiple different results on the same commit hash). Insights can also detect flaky tests in a given build, if the same test was performed multiple times in a single build, even if the build did not have a commit hash specified when it was triggered (common for manual and scheduled builds). ### Finding flaky tests When you open Bitrise Insights, you start on the **Overview** page. From here, you can go to either the **Bottlenecks** page, which lists the top 3 most flaky tests, or you can go to the **Tests** page under the **EXPLORE** section to list and filter all your flaky tests. This will help you track and investigate flaky tests. You can identify and quarantine flaky tests with [some of our testing Steps](/bitrise-ci/testing/detecting-and-quarantining-flaky-tests). Let’s check the **Bottlenecks** page first. When you open the **Bottlenecks** page you’ll see all the negative trends and issues Bitrise Insights detected in the last 7 days. When you’re checking flaky tests you can use the **Flakiness** section: ![flakiness-bottlenecks.png](/img/_paligo/uuid-f995aafc-a3ef-b1d1-5d31-751c5507e60a.png) This **Bottlenecks** section lists the test cases which had the most flaky runs in the last 7 days. Click on any of them and you’ll land on the relevant section of the **Tests** page. Another way to go about it, is to go to the **Tests** page and switch to the **Flaky runs** metric tab: ![flaky-runs-tab.png](/img/_paligo/uuid-3bbc4214-3819-7b12-200a-d211bc965b7e.png) Just like on any other **Tests** metric pages, you’ll see two charts. The upper chart always shows you data for the filters you set. The lower chart is called the breakdown chart and it shows you data “one level deeper” than what you filtered on. If you only have a single app in your Workspace, Bitrise Insights will automatically select that app when you open any of the Explore pages. If you have multiple apps in your workspace, when you open the **Tests** page, the upper chart will show you the overall flaky runs of the workspace across all of your apps in that specific workspace. The lower chart in this case shows you the same data but on a per app basis. From this you can see which app had the most flaky runs in the selected time period: ![flakiest-app.png](/img/_paligo/uuid-9b72d008-6924-060b-2efc-96f96390b627.png) Here, on the breakdown chart you can see that we have this application which had the most amount of flaky test runs in this workspace. Filter down to that app, and on the next level you'll find the per test suite breakdown: The upper chart now shows selected filters view, which in this case is the selected app's flaky test runs. On the lower breakdown chart, you can see which the test suite which had the most flaky test runs: Let's filter down to that test suite to investigate it a little further: ![flakiest-test-suite.png](/img/_paligo/uuid-7c7f36d3-3226-2a6c-3549-cd3321895ef1.png) The upper chart now reflects this filtering, and the breakdown chart switched over to per branch flaky runs. Under the graphs you can see the **Test cases** list, which is filtered based on the filters that you set at the top and also on the time/date range that you set in the top right corner. Using this **Test cases** table you can find which test case is flaky most frequently (**Flaky rate**) or which test case had the most amount of flaky runs (**Flaky runs**) in the selected time period, app, and test suite. ![test-cases-list.png](/img/_paligo/uuid-4775415f-854a-3e11-430a-34c233f7fc5f.png) Select the test case which had the most flaky runs to continue your investigation. This will set the relevant filters for you to focus only on this specific test case. As a result, the charts at the top will now only show the flaky run trends of this specific test case. Under the charts, Bitrise Insights automatically switched over to the **Related test case runs** tab: ![related-test-cases-runs-tab.png](/img/_paligo/uuid-b53b6a0d-3e15-8891-131e-9c1b5637f0bc.png) The **Related test case runs** table lists the specific executions of the test case which had inconsistent results, either in a given build, or across builds with the same commit hash. As you can see on this example, the **testFlakyFeature()** test case had both successful and failed results for the same commit (for commit `f74ca14` and also for `c84f1fd`). Using the **Related test case runs** table you can see all the previous flaky runs of this specific test case, how long that run was and whether it was successful or not. Using the buttons in the test run popup you can quickly jump to the relevant build’s page and to the relevant test report’s page and then continue your investigation there: ![case-report-card.png](/img/_paligo/uuid-603588f5-3a76-1594-bd18-53063a966a21.png) Keeping an eye on and fixing flaky tests helps you to reduce time waste during the app development process and to increase the overall test confidence of the team. --- ## Tracking test failure rate When your mobile app’s tests fail in a continuous integration (CI) environment, it typically indicates that the build has also failed. This means that someone will need to make code changes or fixes and then retry the build and test it again, leading to a cycle of iterations. Even if someone switches to other tasks while the test and build are running, there will be a context switch when they have to return to the task once the test and build are done. ### The importance of test failure rate A high mobile app test failure rate suggests that people frequently spend time debugging, fixing, and then retrying — and waiting for — tests and builds. Failure rate is especially critical for long tests and builds as engineers will have to wait even more when they do a fix and then run a new build and test. By tracking and analyzing where and why your mobile app’s tests fail the most, teams can improve their testing process and make it more resilient over time. Meaning, the time and effort spent on resolving test failures are minimized and the overall efficiency and productivity of your team are increased. The main goal of tracking your mobile app’s failing tests is to reduce the wait time throughout the development process. If you have tests that fail frequently, it means that sooner or later you’ll have to wait for that test and the related build, fix the issue, and then try it again. As part of this cyclical process, you’ll likely lose time either due to 1) context switching or, 2) because you can’t do anything useful while you’re waiting for the results of that test and build. ### Finding frequently failing tests When you open Bitrise Insights, you can start with the Build failure rate chart on the **Overview** page to find the most frequently failing apps and builds. If you’re only interested in tests, you can switch to the **Tests** page under the **EXPLORE** section in the left sidebar. After you open the **Tests** page, switch to the **Failure rate** tab. ![test-failure-rate-tab.png](/img/_paligo/uuid-fd3ff35c-c57e-151a-20ad-8170daf832dd.png) On all of the **Tests** metric pages. you’ll see two charts. The upper chart always shows you data for the filters you set. The lower chart is called the breakdown chart and it shows data one level deeper than what you filtered on. If you have only a single app in your Workspace then Insights will automatically select that app when you open any of the Explore pages. However, if you have multiple apps in your Workspace, when you open the **Tests** page the upper chart it will show you the overall test failure rate of the Workspace — based on test suite failure rates in all of your apps in the workspace.The lower chart, in this example, shows you the same data — but on a per-application basis. From this you can see which app’s test suites are failing the most. Here’s a working example. On the breakdown chart, you can see the application that has the most frequently failing test suites in the Workspace. When filtering down into that app, you'll find the per test suite breakdown: ![most-failing-app-test.png](/img/_paligo/uuid-c46c2c36-ef48-dd8e-7fd4-d025a8c1403d.png) The upper chart now shows what is filtered — so in this case, the selected app's test suite failure rate is being displayed. On the lower, breakdown chart, you can see which test suite failed most frequently. Let's filter down to that test suite. ![filter-test-suite.png](/img/_paligo/uuid-0fffb4e5-f4e4-037e-3378-fde21e261acb.png) The upper chart now reflects this filtering, and the breakdown chart switched over to per branch failure rate. Under the graphs, you can see the **Test cases** list, which is filtered based on the filters that you set at the top and also on the time range that you set in the top right corner. Using this **Test cases** table, you can find which test case is failing most frequently (**Failure rate**) or which test case failed the most amount of times (**Failure count**) in the selected time period, app, and test suite. ![test-case-history.png](/img/_paligo/uuid-704db8ad-4a9b-ce01-8631-97ca9682edcc.png) Select the most frequently failing test case to continue your investigation. This will set the relevant filters for you to focus only on this specific test case. As a result, the charts at the top will now only show the failure rate trend of this specific test case. Under the charts, the Insights filter automatically switched over to the **Related test case runs** tab: ![related-test-cases.png](/img/_paligo/uuid-7d85c0ea-4806-d797-750e-ef3b092eb2db.png) Using the **Related test case runs** table, you can see all the previous runs of this specific test case, how long that run was, and whether it was successful or not. Using the buttons on the right side you can quickly jump to the relevant build’s page and to the relevant test report’s page and then continue your investigation there: Keeping an eye on and improving your test failure rate helps you to reduce wait time during the app development process and to increase the efficiency and productivity of your team. --- ## Adding and connecting an app Before you can manage releases through the API, you need to add the app to Release Management and connect it to a store. The Apps sub-API base URL: `https://api.bitrise.io/release-management/v2/apps/v1`. See the [Apps API reference](/release-management-api/apps/api-reference/release-management-api) for the full list of endpoints, parameters, and schemas. ### Adding a new app | Endpoint | Function | Required role | | --- | --- | --- | | [`POST /`](/release-management-api/apps/api-reference/create-app) | Add a new app. | Release manager | | [`GET /`](/release-management-api/apps/api-reference/list-apps) | List all apps in a workspace. | Any | | [`GET /{id}`](/release-management-api/apps/api-reference/get-app) | Get details of a specific app. | Any | | [`DELETE /{id}`](/release-management-api/apps/api-reference/delete-app) | Remove an app from Release Management. | Release manager | To add an app, call `POST /` with the required fields: - `platform`: The app platform: `ios` or `android`. - `store_app_id`: The app's store identifier. For iOS: the App Store Connect numeric app ID. For Android: the package name (e.g. `com.example.myapp`). - `workspace_slug`: The slug of the Bitrise workspace that will own the app. - `store_credential_id`: The numeric integer ID of the Apple or Google service credential configured in your workspace. Required to connect the app to the store immediately. To skip this and connect later, set `manual_connection: true` instead. **iOS** ```bash curl -X POST "https://api.bitrise.io/release-management/v2/apps/v1/" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "platform": "ios", "store_app_id": "1234567890", "workspace_slug": "YOUR_WORKSPACE_SLUG", "store_app_name": "My iOS App", "store_credential_id": YOUR_APPLE_CREDENTIAL_ID, "framework": "native_ios" }' ``` **Android** ```bash curl -X POST "https://api.bitrise.io/release-management/v2/apps/v1/" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "platform": "android", "store_app_id": "com.example.myapp", "workspace_slug": "YOUR_WORKSPACE_SLUG", "store_app_name": "My Android App", "store_credential_id": YOUR_GOOGLE_CREDENTIAL_ID, "framework": "native_android" }' ``` The response includes the new app's `id`. ```json { "id": "YOUR_APP_ID", "created_at": "2026-01-01T00:00:00.000Z", "platform": "android", "project_id": "YOUR_PROJECT_ID", "workspace_slug": "YOUR_WORKSPACE_SLUG", "icon_id": null, "icon_url": null, "app_name": "My Android App", "current_user_release_management_admin": false, "framework": "native_android", "latest_version": null, "latest_version_date": null, "latest_build_version": "", "latest_build_version_code": "", "license": "basic", "store_app_id": "com.example.myapp", "store_connected": true, "store_credential_id": 12345 } ``` Save this value — you'll need it in all subsequent API calls for this app. :::note[Store credentials] The `store_credential_id` refers to an Apple or Google service credential configured in your workspace. You can manage credentials in Bitrise from **Workspace settings > Integrations**. ::: You can connect the app to the store later using `PATCH /{id}`. ### Connecting an app to the store | Endpoint | Function | Required role | | --- | --- | --- | | [`PATCH /{id}`](/release-management-api/apps/api-reference/update-app) | Update app settings, including store connection. | Release manager | If you added an app with `manual_connection: true` or need to update the store credentials, use `PATCH /{id}`: ```bash curl -X PATCH "https://api.bitrise.io/release-management/v2/apps/v1/APP_ID" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "connect_to_store": true, "store_credential_id": YOUR_CREDENTIAL_ID }' ``` You can also update the `store_app_id` via `PATCH /{id}` if the app was initially registered with an incorrect identifier. ### Listing apps To list all apps in a workspace: ```bash curl -X GET "https://api.bitrise.io/release-management/v2/apps/v1/?workspace_slug=YOUR_WORKSPACE_SLUG" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Accept: application/json" ``` Optional query parameters: - `platform`: Filter by `ios` or `android`. - `project_id`: Filter by an associated Bitrise CI project ID. - `search`: Search by app name. - `items_per_page`: Results per page (default: 10, max: 50). - `page`: Page number (default: 1). ### Removing an app :::warning[Deletion is permanent] Removing an app from Release Management deletes all associated releases, artifacts, and configuration. This cannot be undone. ::: ```bash curl -X DELETE "https://api.bitrise.io/release-management/v2/apps/v1/APP_ID" \ -H "Authorization: YOUR_ACCESS_TOKEN" ``` --- ## Distributing builds to testers You can upload build artifacts to Release Management and distribute them to tester groups directly via the API. Tester groups can be internal (Bitrise users you add by their user slug) or external (testers you add by email, with no Bitrise account required). This covers both the artifact upload flow (Apps sub-API) and tester group management (Build Distributions sub-API). - **Apps sub-API base URL:** `https://api.bitrise.io/release-management/v2/apps/v1`. See the [Apps API reference](/release-management-api/apps/api-reference/release-management-api). - **Build Distributions sub-API base URL:** `https://api.bitrise.io/release-management/v2/build-distributions/v1`. See the [Build Distributions API reference](/release-management-api/build-distributions/api-reference/release-management-api-build-distributions). ### Uploading a build artifact | Endpoint | Sub-API | Function | | --- | --- | --- | | [`GET /installable-artifacts/{id}/upload-url`](/release-management-api/apps/api-reference/generate-installable-artifact-upload-url) | Apps | Generate a presigned upload URL. | | [`GET /installable-artifacts/{id}/status`](/release-management-api/apps/api-reference/get-installable-artifact-status) | Apps | Check upload and processing status. | | [`GET /installable-artifacts`](/release-management-api/apps/api-reference/list-installable-artifacts) | Apps | List uploaded artifacts for an app. | | [`GET /installable-artifacts/{id}`](/release-management-api/apps/api-reference/get-installable-artifact) | Apps | Get details of an artifact. | | [`DELETE /installable-artifacts/{id}`](/release-management-api/apps/api-reference/delete-installable-artifact) | Apps | Delete an artifact. | #### Step 1: Generate an upload URL Generate a presigned S3 upload URL for your build artifact. The response includes both the upload URL and confirms the artifact ID. ```bash ARTIFACT_ID=$(uuidgen | tr '[:upper:]' '[:lower:]') curl -X GET "https://api.bitrise.io/release-management/v2/apps/v1/installable-artifacts/${ARTIFACT_ID}/upload-url?app_id=APP_ID&file_name=MyApp.ipa&file_size_bytes=52428800" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Accept: application/json" ``` Required query parameters: - `app_id`: The RM app ID. - `file_name`: The filename of the artifact (e.g., `MyApp.ipa` or `MyApp.apk`). - `file_size_bytes`: The file size in bytes. Optional query parameters: - `with_public_page`: Set to `true` to enable a public install page immediately. - `branch`: The source branch this build came from. - `workflow`: The CI workflow that produced this build. #### Step 2: Upload the binary You can upload `.ipa` (iOS), `.apk`, or `.aab` (Android) files. Use the `method`, `url`, and `headers` from the previous response exactly as returned — the headers vary per upload and typically include `Content-Type` and `X-Goog-Content-Length-Range`: ```bash # Use the method, url, and headers exactly as returned by the Step 1 response. curl -X PUT "PRESIGNED_UPLOAD_URL" \ -H "Content-Type: " \ -H "X-Goog-Content-Length-Range: " \ --data-binary "@/path/to/MyApp.aab" ``` #### Step 3: Check processing status After upload, wait for Bitrise to finish processing the artifact: ```bash curl -X GET "https://api.bitrise.io/release-management/v2/apps/v1/installable-artifacts/${ARTIFACT_ID}/status" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Accept: application/json" ``` The response returns the current `status`. Poll this endpoint until the status indicates the artifact is ready for distribution. ### Listing installable artifacts To act on an artifact you didn't just upload yourself, look it up with [`GET /installable-artifacts`](/release-management-api/apps/api-reference/list-installable-artifacts): ```bash curl -X GET "https://api.bitrise.io/release-management/v2/apps/v1/installable-artifacts?app_id=APP_ID&items_per_page=10&page=1" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Accept: application/json" ``` :::note[Use `uid`, not `id`] Each item in the response includes both an `id` and a `uid` field. Use `uid` as the `ARTIFACT_ID` in other calls — `id` is a separate identifier and won't work in the endpoints on this page. ::: ### Enabling a public install page You can make a build available via a public URL that testers can open directly without a Bitrise account. ```bash curl -X PATCH "https://api.bitrise.io/release-management/v2/apps/v1/installable-artifacts/ARTIFACT_ID/public-install-page" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "with_public_page": true }' ``` ### Adding what-to-test notes Attach test instructions to a build that testers can see when they receive the notification. ```bash curl -X PATCH "https://api.bitrise.io/release-management/v2/apps/v1/installable-artifacts/ARTIFACT_ID/what-to-test" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "what_to_test": "Focus on the new onboarding flow. Check that the splash screen animation completes before login." }' ``` The `what_to_test` field accepts up to 4,000 characters. ### Creating custom access links Custom access links let you share a build with restricted access: optionally protected by a code and with an expiry date. For more information, see [Custom access links](/release-management/build-distribution/distributing-builds-to-testers#custom-access-link). :::note A custom access link is different from the [public install page](/bitrise-ci/deploying/ios-deployment/installing-an-ipa-file-from-the-public-install-page) link: the public install page is permanent and has no access controls. ::: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/apps/v1/installable-artifacts/ARTIFACT_ID/custom-access-links" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "External QA team", "expires_at": "2026-07-31T23:59:59Z", "access_code": "qa-team-2026" }' ``` The `access_code` must be 8–64 characters. Omit `expires_at` to create a link that does not expire. ### Managing tester groups Tester groups let you notify groups of internal testers when a new build is ready. For more information, see [Tester groups](/release-management/build-distribution/tester-groups). | Endpoint | Function | | --- | --- | | [`POST /tester-groups`](/release-management-api/build-distributions/api-reference/create-tester-group) | Create a tester group. | | [`GET /tester-groups`](/release-management-api/build-distributions/api-reference/list-tester-groups) | List tester groups for an app. | | [`PUT /tester-groups/{id}`](/release-management-api/build-distributions/api-reference/update-tester-group) | Update a tester group. | | [`POST /tester-groups/{id}/add-testers`](/release-management-api/build-distributions/api-reference/add-testers-to-tester-group) | Add testers to a group. | | [`POST /tester-groups/{id}/notify`](/release-management-api/build-distributions/api-reference/notify-tester-group) | Notify a group about a new build. | | [`DELETE /tester-groups/{id}`](/release-management-api/build-distributions/api-reference/delete-tester-group) | Delete a tester group. | #### Creating a tester group Set the `type` query parameter to choose between an internal group (Bitrise users, added by user slug) or an external group (testers added by email, no Bitrise account required). `type` defaults to `internal` when omitted. **Internal** ```bash curl -X POST "https://api.bitrise.io/release-management/v2/build-distributions/v1/tester-groups" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "app_id": "APP_ID", "name": "iOS Beta Testers", "auto_notify": true }' ``` **External** ```bash curl -X POST "https://api.bitrise.io/release-management/v2/build-distributions/v1/tester-groups?type=external" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "app_id": "APP_ID", "name": "External QA testers", "auto_notify": true, "emails": ["tester1@example.com", "tester2@example.com"] }' ``` The `emails` array accepts up to 1,000 addresses (each up to 255 characters) and is ignored for internal groups. A tester is created for every address and added to the group. Setting `auto_notify: true` means testers are automatically emailed when a new build is uploaded. #### Adding testers to a group Set the `type` query parameter to match the group's type — `type` defaults to `internal` when omitted. The array that doesn't match the group's type is ignored. **Internal** ```bash curl -X POST "https://api.bitrise.io/release-management/v2/build-distributions/v1/tester-groups/GROUP_ID/add-testers" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "user_slugs": ["USER_SLUG_1", "USER_SLUG_2"] }' ``` :::tip[Finding user slugs] To find the user slugs of workspace members, use `GET /tester-groups/{id}/potential-testers?search=name-or-email` to search for eligible testers. The response includes each user's `slug`. ::: **External** ```bash curl -X POST "https://api.bitrise.io/release-management/v2/build-distributions/v1/tester-groups/GROUP_ID/add-testers?type=external" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "emails": ["tester1@example.com", "tester2@example.com"] }' ``` The `emails` array accepts up to 1,000 addresses. A tester is created or reused for each address. #### Notifying a tester group Send a notification to a tester group about a specific build: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/build-distributions/v1/tester-groups/GROUP_ID/notify" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "test_build_id": "ARTIFACT_ID" }' ``` The build must be distribution-ready before you can notify testers. A successful call returns `204 No Content`. ### Listing uploaded builds To list all builds available for distribution for a specific version: ```bash curl -X GET "https://api.bitrise.io/release-management/v2/build-distributions/v1/test-builds?app_id=APP_ID&version=1.5.0" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Accept: application/json" ``` --- ## Creating an app version An app version moves through the release process — from the release candidate stage through approvals, store submission, and production release. The Store Releases sub-API base URL: `https://api.bitrise.io/release-management/v2/store-releases/v1`. See the [Store Releases API reference](/release-management-api/store-releases/api-reference/release-management-api-app-versions) for the full list of endpoints, parameters, and schemas. | Endpoint | Function | Required role | | --- | --- | --- | | [`POST /app-versions`](/release-management-api/store-releases/api-reference/create-release) | Create a new app version. | Release manager | | [`GET /app-versions`](/release-management-api/store-releases/api-reference/list-releases) | List app versions for an app. | Any | | [`GET /app-versions/{id}`](/release-management-api/store-releases/api-reference/get-release) | Get details of an app version. | Any | | [`PATCH /app-versions/{id}`](/release-management-api/store-releases/api-reference/update-release) | Update an app version. | Release manager | | [`DELETE /app-versions/{id}`](/release-management-api/store-releases/api-reference/delete-release) | Delete an app version. | Release manager | To create an app version: 1. Call `POST /app-versions` with the required fields: - `name`: The version name for this app version. - `app_id`: The ID of the app in Release Management (returned when you [added the app](/release-management/api/adding-and-connecting-an-app)). :::note[Version format for iOS] For iOS apps, `name` is used as the App Store Connect version string and must follow the `X.Y.Z` format (e.g., `1.2.0`). ::: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "1.5.0", "app_id": "APP_ID", "description": "Spring feature release", "artifact_source": "ci" }' ``` The response includes the app version's `id`, which you'll use in subsequent calls. ```json { "id": "YOUR_APP_VERSION_ID", "name": "1.5.0", "status": "scheduled", "description": "Spring feature release", "connected_app_id": "YOUR_APP_ID", "artifact_source": "ci", "platform": "android", "store_app_id": "com.example.myapp", "created_at": "2026-01-01T00:00:00.000Z", "released_at": null, "release_candidate_id": null, "stages": [ { "name": "release-candidate", "status": "pending" }, { "name": "approvals", "status": "pending" }, { "name": "app-store-review", "status": "pending" }, { "name": "release", "status": "pending" } ] } ``` ### Configuring release automation You can define automation rules that trigger CI builds automatically when an app version reaches a certain stage. For a full overview of how automation works, see [Release automation](/release-management/releases/configuring-a-release/release-automation). Set the `automation` field when creating or updating an app version: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "1.5.0", "app_id": "APP_ID", "artifact_source": "ci", "release_branch": "release/1.5.0", "workflow": "release", "automation": [ { "event_name": "release_candidate_set", "workflow_name": "run-tests" }, { "event_name": "approvals_completed", "workflow_name": "upload-to-store" } ] }' ``` Available automation `event_name` values depend on the platform. For the full, up-to-date list and what triggers each event, see [Automation events](/release-management/releases/configuring-a-release/release-automation#automation-events). **iOS** - `release_candidate_set`: A new release candidate is selected. - `testflight_upload_finished`: TestFlight processing finishes for an uploaded build. - `beta_review_approved`: Apple approves the beta app review. - `beta_review_rejected`: Apple rejects the beta app review. - `release_for_apple_app_store_testing_group`: The build is released to a TestFlight testing group. - `approvals_completed`: All approval tasks are marked complete. - `submitted_for_review`: The app version is submitted for App Store review. - `review_status_changed` / `review_cancelled`: The review submission status changes. - `release_started`: The rollout to the App Store starts. - `release_completed`: The app version is fully rolled out. **Android** - `release_candidate_set`: A new release candidate is selected. - `google_play_store_upload_finished`: The build finishes uploading to the Google Play console. - `release_on_google_play_store_testing_track`: The release candidate is released on a Google Play testing track. - `approvals_completed`: All approval tasks are marked complete. - `release_started`: The rollout starts (full release or the first stage of a staged rollout). - `release_completed`: The app version is fully rolled out. - `release_percentage_changed`: The staged rollout percentage changes (not triggered on the first rollout). ### Adding approval tasks to an app version | Endpoint | Function | Required role | | --- | --- | --- | | [`POST /app-versions/{id}/approvals`](/release-management-api/store-releases/api-reference/create-approval-task) | Create an approval task. | Release manager | | [`GET /app-versions/{id}/approvals`](/release-management-api/store-releases/api-reference/list-approval-tasks) | List approval tasks. | Any | | [`PATCH /app-versions/{id}/approvals/{task_id}`](/release-management-api/store-releases/api-reference/update-approval-task) | Update or complete an approval task. | Assigned user | You can create approval tasks that team members must complete before the app version proceeds. ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/APP_VERSION_ID/approvals" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "summary": "QA sign-off", "description": "Verify all test cases pass on the release build", "assigned_user_slug": "USER_SLUG", "due_date": "2026-07-10" }' ``` To mark an approval task as complete: ```bash curl -X PATCH "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/APP_VERSION_ID/approvals/TASK_ID" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "completed": true }' ``` ### Applying a preset to an app version If you have [release presets](/release-management/api/creating-presets) configured, apply one when creating the app version to inherit its automation, approvals, and notification settings: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "1.5.0", "app_id": "APP_ID", "presets_id": "PRESET_ID" }' ``` ### Deleting an app version :::warning[Deletion is permanent] Deleting an app version removes it and all associated data. This cannot be undone. ::: ```bash curl -X DELETE "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/APP_VERSION_ID" \ -H "Authorization: YOUR_ACCESS_TOKEN" ``` A successful response returns `204 No Content` with an empty body. --- ## Creating and managing presets Presets are reusable release configuration templates. They let you define automation rules, approval tasks, notifications, and CI build settings once and apply them consistently across multiple releases. The Apps sub-API base URL: `https://api.bitrise.io/release-management/v2/apps/v1`. See the [Apps API reference](/release-management-api/apps/api-reference/release-management-api) for the full list of endpoints, parameters, and schemas. ### Creating a preset | Endpoint | Function | Required role | | --- | --- | --- | | [`POST /presets`](/release-management-api/apps/api-reference/create-preset) | Create a new preset. | Release manager | | [`GET /presets`](/release-management-api/apps/api-reference/get-presets-list) | List presets for an app. | Any | | [`GET /presets/{id}`](/release-management-api/apps/api-reference/get-presets) | Get a specific preset. | Any | | [`PUT /presets/{id}`](/release-management-api/apps/api-reference/update-presets) | Update a preset. | Release manager | | [`DELETE /presets/{id}`](/release-management-api/apps/api-reference/delete-preset) | Delete a preset. | Release manager | To create a preset, call `POST /presets` with at least a name and the app it belongs to. Required fields: - `app_id`: The ID of the app in Release Management. - `template_name`: A descriptive name for the preset. ```bash curl -X POST "https://api.bitrise.io/release-management/v2/apps/v1/presets" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "app_id": "APP_ID", "template_name": "Standard release" }' ``` ### Creating a preset with full configuration A preset can bundle automation rules, approval tasks, Slack notifications, and upload settings into a single reusable template. #### Automation Automation rules trigger a CI workflow when a release reaches a specific stage. Set the `automation` field to an array of event/workflow pairs: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/apps/v1/presets" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "app_id": "APP_ID", "template_name": "Standard release", "automation": [ { "event_name": "release_candidate_set", "workflow_name": "run-tests" }, { "event_name": "approvals_completed", "workflow_name": "upload-to-store" } ] }' ``` #### Approval tasks Approval tasks are created automatically for every release that uses this preset. Set the `approvals` field to define the tasks: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/apps/v1/presets" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "app_id": "APP_ID", "template_name": "Standard release", "approvals": [ { "summary": "QA sign-off", "description": "Verify all test cases pass on the release build" } ] }' ``` #### Slack notifications To send Slack notifications at key release stages, pass the ID of a configured Slack integration in the `notifications` field. For more information, see [Slack integration](/bitrise-platform/workspaces/workspace-slack-integration). ```bash curl -X POST "https://api.bitrise.io/release-management/v2/apps/v1/presets" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "app_id": "APP_ID", "template_name": "Standard release", "notifications": { "slack_notification_integration_id": "YOUR_SLACK_INTEGRATION_ID" } }' ``` #### Automatic store upload Set `auto_upload: true` to automatically upload the build to the store once it's ready, without a manual trigger: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/apps/v1/presets" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "app_id": "APP_ID", "template_name": "Standard release", "auto_upload": true }' ``` You can combine any of these settings in a single request. Save the `id` from the response — you'll use it when [creating app versions](/release-management/api/creating-an-app-version#applying-a-preset-to-an-app-version). :::note[Default preset] Setting `default: true` marks this preset as the one automatically applied to new releases. Only one preset per app can be the default. ::: ### Listing presets for an app ```bash curl -X GET "https://api.bitrise.io/release-management/v2/apps/v1/presets?app_id=APP_ID" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Accept: application/json" ``` ### Updating a preset Use `PUT /presets/{id}` to replace the preset's configuration. All fields are optional. ```bash curl -X PUT "https://api.bitrise.io/release-management/v2/apps/v1/presets/PRESET_ID" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "default": true, "auto_upload": false, "automation": [ { "event_name": "release_candidate_set", "workflow_name": "run-extended-tests" } ], "approvals": [ { "summary": "QA sign-off" }, { "summary": "Security review" } ] }' ``` ### Deleting a preset ```bash curl -X DELETE "https://api.bitrise.io/release-management/v2/apps/v1/presets/PRESET_ID" \ -H "Authorization: YOUR_ACCESS_TOKEN" ``` :::important[Existing releases not affected] Deleting a preset does not affect releases that were created using it. The settings are copied to the release at creation time. ::: --- ## Release Management API Bitrise offers a REST API for Release Management. The base URL for the API is . The API is available in two versions: - v1: https://api.bitrise.io/release-management/v1. This is deprecated. - v2: The current version. It has domain-specific sub APIs, with the URLs described here: [Sub APIs](/release-management/release-management-api#sub-apis). The API offers the same features that are available on the GUI. You can: - Connect apps. - Configure presets. - Manage releases in all stages, including the release candidate stage and the approval stage. - Distribute your apps. ### Sub APIs The v2 API is organized into four sub APIs, each with its own base URL: | Sub-API | Description | Base URL | | --- | --- | --- | | Apps | Covers connected apps, installable artifacts, presets, public assets, outgoing webhooks, and Apple App Store draft versions. | `https://api.bitrise.io/release-management/v2/apps/v1` | | Build Distributions | Covers tester groups, testers, and build distributions. | `https://api.bitrise.io/release-management/v2/build-distributions/v1` | | Store Releases | Covers app versions, approvals, beta distribution, and store releases for both the App Store and Google Play. | `https://api.bitrise.io/release-management/v2/store-releases/v1` | | Code Push | Covers deployments and updates. | `https://api.bitrise.io/release-management/v2/code-push/v1` | ### Migration from v1 to v2 The main structural differences between v1 and v2: - App identification: In v1, the app ID was a path parameter (for example, `/apps/{app_id}/installable-artifacts`). In v2, `app_id` is passed as a query parameter to the relevant sub-API. - Tester groups and build distributions: Moved from the Apps sub-API to the dedicated Build Distributions sub-API. - Code Push packages renamed: The `packages` resource in v1 Code Push is called `updates` in v2. - Store releases: Apple App Store and Google Play store release management is now under the Store Releases sub-API. Each deprecated v1 endpoint's description specifies the equivalent v2 endpoint to use. Refer to [the API docs](https://api.bitrise.io/release-management/api-docs/index.html) for the full list. ### Authentication Authentication works the same way [as the Bitrise API](/bitrise-ci/api/authenticating-with-the-bitrise-api): you need [a Personal Access Token](/bitrise-platform/accounts/personal-access-tokens) or [a Workspace token](/bitrise-platform/workspaces/workspace-api-token) to authenticate your API calls. Certain endpoints are only available to users with the **Release manager** role and some endpoints are only available on the Standard plan. Typically, these endpoints are used to access end-user-facing functions, such as submitting the app for App Store review and releasing the app to the App Store or Google Play. Trying to access the endpoints tied to these roles will return a `403 Permission denied` response. ### Documentation You can find detailed documentation of the API endpoints: [API docs](https://api.bitrise.io/release-management/api-docs/index.html). You can test all endpoints on the site. In addition to the technical details, you can also check whether an endpoint is available on a given Bitrise payment plan. ### Localization codes for the App Store API For certain calls to the App Store API, you might need localization codes: for example, when creating a **What to test** description for an iOS release, you might need that description in several different languages. You can find the supported localization codes [in Apple's documentation](https://developer.apple.com/documentation/appstoreconnectapi/app_store/app_metadata/app_info_localizations/managing_metadata_in_your_app_by_using_locale_shortcodes). --- ## Releasing an app to the store Once your release has a release candidate uploaded to the store and all approvals are completed, you can release it to users. For iOS, this also requires submitting the app for App Store review first. Android releases skip straight to the release step. The Store Releases sub-API base URL: `https://api.bitrise.io/release-management/v2/store-releases/v1`. See the [Store Releases API reference](/release-management-api/store-releases/api-reference/release-management-api-app-versions) for the full list of endpoints, parameters, and schemas. ### Configuring beta distribution (iOS) Before submitting for full release, you can distribute the build to beta testers through TestFlight (iOS only). #### Listing TestFlight testing groups Returns the TestFlight testing groups associated with the release. Use the `id` values from the response to start distribution to a specific group. ```bash curl -X GET "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/beta-distribution/testing-groups" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Accept: application/json" ``` #### Starting beta distribution to a TestFlight group Makes the release build available to testers in a specific TestFlight group. Testers receive a notification and can install the build directly from the TestFlight app. ```bash curl -X PATCH "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/beta-distribution/testing-groups/GROUP_ID" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" ``` #### Adding what-to-test notes for TestFlight Attaches testing instructions to the release build. Testers see these notes in the TestFlight app when they receive the build notification. ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/beta-distribution/what-to-test" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "locale": "en-US", "whats_new": "Fixed login issue and improved onboarding flow." }' ``` ### Adding release notes (Android) Release notes appear on the app's Google Play Store listing under **What's new**, and are shown to users before and after they update the app. You can provide notes in multiple languages — Google Play displays the version that matches the user's device language, falling back to `en-US` if no match is found. Pass an array of language/text pairs to the `release_notes` field, using [BCP 47 language tags](https://www.rfc-editor.org/rfc/bcp/bcp47.txt) (e.g. `en-US`, `de-DE`, `fr-FR`): ```bash curl -X PUT "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/google-play-store/localized-release-notes" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "release_notes": [ { "language": "en-US", "text": "Fixed login issue and improved onboarding flow." }, { "language": "de-DE", "text": "Login-Problem behoben und Onboarding-Flow verbessert." } ] }' ``` Each release note text can be up to 500 characters. ### Submitting for store review (iOS) :::note[Android] Android releases submitted via the API go directly to the configured Google Play track and do not require a separate review submission step. Proceed to the release step below. ::: | Endpoint | Function | Required role | | --- | --- | --- | | [`POST /app-versions/{id}/apple-app-store/review/submit`](/release-management-api/store-releases/api-reference/submit-release-candidate-for-review) | Submit the release for App Store review. | Release manager | | [`GET /app-versions/{id}/apple-app-store/review/status`](/release-management-api/store-releases/api-reference/get-review-status) | Get the current App Store review status. | Any | | [`POST /app-versions/{id}/apple-app-store/review/cancel`](/release-management-api/store-releases/api-reference/cancel-review) | Cancel a pending review submission. | Release manager | Submit the release for App Store review: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/apple-app-store/review/submit" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "copy_primary_whats_new": true, "localizations": [ { "locale": "en-US", "whats_new": "Bug fixes and performance improvements.", "description": "Updated description for this version.", "keywords": "productivity, task manager" } ] }' ``` Setting `copy_primary_whats_new: true` copies the primary locale's "What's new" text to all other localizations that have no text set. To check the review status: ```bash curl -X GET "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/apple-app-store/review/status" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Accept: application/json" ``` ### Configuring release settings **iOS** Before releasing, configure how the update rolls out to users: ```bash curl -X PATCH "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/apple-app-store/release/settings" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "release_type": "AFTER_APPROVAL", "phased_release": true }' ``` `release_type` options: - `AFTER_APPROVAL`: Release automatically once approved by Apple. - `MANUAL`: Hold the release until you manually trigger it. - `SCHEDULED`: Release at a specific date and time (requires `earliest_release_date` in ISO 8601 format). `phased_release: true` rolls the update out to users over 7 days rather than all at once. **Android** For Android you can schedule the rollout to a fraction of users (staged rollout): ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/google-play-store/staged-rollout-schedule" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "location": "America/New_York", "schedule": [ { "percentage": 10, "when": "2026-07-20T09:00:00-04:00" }, { "percentage": 50, "when": "2026-07-22T09:00:00-04:00" }, { "percentage": 100, "when": "2026-07-25T09:00:00-04:00" } ] }' ``` ### Releasing to users **iOS** | Endpoint | Function | Required role | | --- | --- | --- | | [`POST /app-versions/{id}/apple-app-store/release`](/release-management-api/store-releases/api-reference/create-store-release-ios) | Release the app to the App Store. | Release manager | | [`GET /app-versions/{id}/apple-app-store/release/status`](/release-management-api/store-releases/api-reference/get-release-status) | Get the release status. | Any | | [`POST /app-versions/{id}/apple-app-store/release/pause`](/release-management-api/store-releases/api-reference/pause-phased-release-ios) | Pause a phased release. | Release manager | | [`POST /app-versions/{id}/apple-app-store/release/continue`](/release-management-api/store-releases/api-reference/continue-phased-release-ios) | Continue a paused phased release. | Release manager | | [`POST /app-versions/{id}/apple-app-store/release/complete`](/release-management-api/store-releases/api-reference/complete-phased-release-ios) | Complete a phased release immediately. | Release manager | Trigger the release: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/apple-app-store/release" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" ``` Check the release status: ```bash curl -X GET "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/apple-app-store/release/status" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Accept: application/json" ``` To complete a phased release immediately (rolling out to 100% of users right away): ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/apple-app-store/release/complete" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" ``` **Android** | Endpoint | Function | Required role | | --- | --- | --- | | [`POST /app-versions/{id}/google-play-store/release`](/release-management-api/store-releases/api-reference/create-store-release-android) | Release to all or a fraction of users. | Release manager | Release to all users: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/google-play-store/release" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "user_fraction": 1.0 }' ``` For a staged rollout starting at 10%: ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/google-play-store/release" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "user_fraction": 0.1 }' ``` The `user_fraction` value ranges from `0` to `1`, where `1` equals 100% of users. ### Setting up release webhooks You can configure outgoing webhooks to receive notifications when a release reaches key stages. ```bash curl -X POST "https://api.bitrise.io/release-management/v2/store-releases/v1/app-versions/RELEASE_ID/outgoing-webhooks" \ -H "Authorization: YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "events": ["release_started", "submitted_for_review"], "webhook_configuration_id": "WEBHOOK_CONFIG_ID" }' ``` Set `all_events: true` instead of listing individual events to receive notifications for all release lifecycle events. --- ## Distributing builds to testers(Build-distribution) Release Management offers a convenient, secure solution to distribute the builds of your mobile apps to testers without having to engage with either TestFlight or Google Play. Once you have installable artifacts, Bitrise can generate both private and public install links that testers or other stakeholders can use to install the app on real devices via over-the-air installation. You can access all your distributable builds on the **Build distribution** page: these are the builds you can distribute to internal testers. Distributable builds are the following: - For iOS apps, they are IPAs with Development, Ad-hoc, or Enterprise provisioning. - For Android apps, only APKs are distributable to testers. AABs are not. Each distributable build has its own page that includes installation instructions and metadata. The metadata includes, among other things, the source of the artifact, its creation time, size, and supported device types. You can set up tester groups so that testers can get access to the build details page and install the app from there. Workspace owners, Workspace managers and project admins can also send notification emails to tester groups from the build page. For details, see [Tester groups](/release-management/build-distribution/tester-groups). You can upload installable artifacts to the page from Bitrise CI builds or via our dedicated API. For details, see [Installable artifacts](/release-management/installable-artifacts). ### Accessing the build details page To access the build details page on Bitrise: :::note[Login required] You need a Bitrise user account to access the build details page. The account must be a member of the project's team. ::: 1. Open your connected app in Release Management. 1. Select **Build distribution** on the left. 1. Select the **Builds** tab. 1. Find the build you need and click the arrow on the right. ![build-details-access.png](/img/_paligo/uuid-55dc2023-f61b-5331-f1af-94924727ff25.png) ### Installing artifacts You can install build artifacts from its build details page. To do so: 1. [Access the build details page](#accessing-the-build-details-page) of the build. You can also access the build details page from a notification email. 1. Click **Download artifact** on the top right. ![build-details-page.png](/img/_paligo/uuid-60a84ba2-ab5d-e077-877b-a2be85014efc.png) - If your app is an Android app, the download will start immediately. - If your app is an iOS app, you'll see a dialog that provides instructions for installing the app on a device. ![ios-download-rm.png](/img/_paligo/uuid-58a8bc7f-8220-32ed-3cc3-193aa78e8cf4.png) ### Enabling the public install page The public install page allows you to distribute your installable artifacts to testers who don't have Bitrise accounts. 1. Access the build details page of the build. 1. In the **Install this version** section, toggle the **Public install page** option on. :::important[Required access] Only Workspace owners, Workspace managers, and project admins have the right to enable or disable the public install page for a build. ::: ![build-details-page.png](/img/_paligo/uuid-60a84ba2-ab5d-e077-877b-a2be85014efc.png) 1. Click **Get link** to open a dialog that contains both a URL and a QR code. ### Custom access link You can quickly generate a shareable install link for an APK or non-store IPA artifact, with an optional expiration time and an optional access code. Those who receive the link can install the build without a Bitrise account. :::note This link is different from the [public install page](/bitrise-ci/deploying/ios-deployment/installing-an-ipa-file-from-the-public-install-page) link: the public install page is permanent and has no access controls. ::: Users with the following [access roles](/release-management/configuring-connected-apps/release-management-roles-and-permissions) can create custom access links: - Workspace owners - Workspace managers - Release managers - Project admins You can create multiple access links for the same artifact, with different expiration times, or no expiration time at all. All share links are publicly accessible to anyone who has the URL. #### Creating a custom access link 1. [Access the build details page of the build](/release-management/build-distribution/distributing-builds-to-testers). 1. Go to the **Public access** tab. 1. Click **New custom link**. 1. Add a link name. ![SCR-20260529-kgaj.png](/img/_paligo/uuid-4099a4ad-c75e-1d78-ea84-7b05cd49d8f6.png) 1. Optionally, check **Expiry** and set an expiry date for the link. After the provided date, the link will be no longer accessible. 1. Optionally, check **Access code** and set a code in the input field. Testers will need this code to access the link. 1. When ready, click **Create link**. ### Adding instructions for testers You can set testing instructions for your testers for each installable artifact, let them know what's been added to a build and what you would like them to test. You can check the instructions on the build details page of an installable artifact and on the [public install page](/bitrise-ci/deploying/ios-deployment/installing-an-ipa-file-from-the-public-install-page). :::important[Editing access] Users with the following roles can edit the testing instructions: - Workspace owner - Project admin - Release Manager Users with the App tester role have read-only access. For more information about roles, see: [Release Management roles and permissions](/release-management/configuring-connected-apps/release-management-roles-and-permissions). ::: To add testing instructions to an installable artifact: 1. [Access the build details page](/release-management/build-distribution/distributing-builds-to-testers). You can also access the build details page from a notification email. 1. Find the **What to test** section, and click **Edit**. ![2025-09-04-rm-what-to-test.png](/img/_paligo/uuid-aac41e7c-0756-9d0b-d3a3-9fdf2db628dc.png) 1. Write a message to your testers, let them know what to test. The message has a limit of 4000 characters. 1. Click **Save changes**. --- ## Tester groups Create tester groups in Release Management to to be able to distribute installable artifacts to testers automatically. When a new installable artifact is available, the tester groups can be: - Automatically notified via email. - Manually notified via email. The notification email contains a link to the build page in Release Management. A connected app can have multiple tester groups. You can select testers from the project team members of the connected app. :::important[Required access level] Users with the following roles can manage tester groups: - Workspace owner - Workspace manager - Project admin ::: ### Creating tester groups To create a new tester group: 1. Open your connected app in Release Management. 1. Select **Build distribution** and then the **Tester groups** tab. ![tester-group.png](/img/_paligo/uuid-5d668c02-0f6c-cbcb-3206-b2e5a711979f.png) 1. Click **+ New group**. 1. Enter a group name. The name must be unique: no other tester group can have the same name. You can change the name later. 1. Optionally, check the **Send notifications automatically** box. With this setting, every group member receives a notification when a new installable artifact is available. You can change this later. ### Adding members to tester groups A newly created tester group is empty. You can add [members of the Bitrise project](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) the app belongs to. To add members to a tester group: 1. Open your connected app in Release Management. 1. Select **Build distribution** and then the **Tester groups** tab. 1. Find the group and click the options menu (⋮). ![manage-tester-group.png](/img/_paligo/uuid-fd63cf77-e2f7-bfce-3000-4a80b87f158f.png) 1. Select **Manage testers**. 1. In the group page, click **Add testers**. 1. Select all the testers you need and click **Add**. ### Removing members from tester groups You can remove members from testing groups in two ways: - Removing them from a specific testing group. - Removing them from all testing groups at the same time. **Specific group** 1. Open your connected app in Release Management. 1. Select **Build distribution** and then the **Tester groups** tab. 1. Find the group and click the options menu (⋮). ![manage-tester-group.png](/img/_paligo/uuid-fd63cf77-e2f7-bfce-3000-4a80b87f158f.png) 1. Select **Manage testers**. 1. In the **Testers in this group** list, find the tester you want to remove and click the remove button. **All groups** 1. Open your connected app in Release Management. 1. Select **Build distribution** and then the **Testers** tab. 1. In the **All testers** list, find the tester you want to remove and click the remove button. ### Configuring notification settings for tester groups Tester groups can be notified automatically via email: whenever a new installable artifact is available for the app, each member of a tester group gets an email notification. The notification email contains a link to the build page in Release Management, from where you can install the app on a mobile device. :::note[New members] You can only send a notification once. If you add new members to the group after a notification email has been sent, those new members won't get a notification email. ::: To configure automatic notifications: 1. Open your connected app in Release Management. 1. Select **Build distribution** and then the **Tester groups** tab. 1. Find the group and click the options menu (⋮). 1. Select **Configure notifications**. 1. Toggle on **Automatic notifications**. ### Sending notifications to tester groups manually You can notify a tester group manually about a new installable build artifact. :::note[New members] You can only send a notification once. If you add new members to the group after a notification email has been sent, those new members won't get a notification email. ::: 1. Open your connected app in Release Management. 1. Select **Build distribution** and then the **Builds** tab. 1. Find the build you need from the list and click the arrow on the right. 1. On the build page, select the **Testing** tab. ![tester-settings-page.png](/img/_paligo/uuid-c8b3be87-8669-d4d7-d100-ad03c3055645.png) 1. Find the tester group and click **Send**. --- ## About CodePush Bitrise offers a hosted CodePush product, integrated with the rest of the Bitrise platform. You can use it with your React Native and Expo apps in Release Management, without hosting and operating your own infrastructure. CodePush enables React Native developers to deploy mobile app updates directly to their users' devices. The product consists of two parts: - CodePush in Bitrise Release Management, where developers publish, roll out and manage updates. This is a hosted service, operated by Bitrise. Get started [creating a CodePush deployment](/release-management/codepush/creating-a-codepush-deployment). - The [app SDK](https://github.com/bitrise-io/react-native-code-push) that handles available updates in your app. The SDK supports React Native New Architecture and Expo: [Configuring your app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). You need a Release Management [app](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management) to be able to push updates to your app users. ### CodePush plans and tiers Your CodePush use is measured by the following factors: - **Monthly active users**: A unique end user who downloads one or more CodePush updates within a single monthly billing cycle. Multiple downloads by the same person in that month count as a single MAU. - **Data transfer**: The total size of files delivered by CodePush updates to your users. - **Storage**: The total amount of space (GiB) allocated to your workspace for storing CodePush update artifacts. In each pricing tier for CodePush, we offer different limits for these factors: | Plan | Tier (MAU) | Monthly active users | Data transfer limit | Storage | Monthly fee | | --- | --- | --- | --- | --- | --- | | Basic | 100k MAU | 100,000 | 5,000 GiB | 5 GiB | $0 | | Pro | 250K MAU | 250,000 | 12,500 GiB | 25 GiB | $294 | | | 500K MAU | 500,000 | 25,000 GiB | 25 GiB | $572 | | | 1M MAU | 1,000,000 | 50,000 GiB | 25 GiB | $1,111 | | | 2M MAU | 2,000,000 | 100,000 GiB | 25 GiB | $2,156 | | | 3M MAU | 3,000,000 | 150,000 GiB | 25 GiB | $3,139 | | | 5M MAU | 5,000,000 | 250,000 GiB | 25 GiB | $5,072 | --- ## Code signing with CodePush Code signing is a security mechanism that adds a digital signature to your CodePush bundles (JavaScript updates). This signature allows the client app to verify that a trusted source created the update and that it has not been tampered with during delivery. CodePush code signing is done in three stages: 1. Generating an RSA keypair: - The private key is used to sign the CodePush bundles. - The public key is embedded into the mobile app to verify signatures. 1. When releasing a CodePush update, the Bitrise CodePush CLI signs the bundle using the private key. It creates a JWT (JSON Web Token) containing the bundle's hash, digitally signed with this private key. 1. The mobile app (with the embedded public key) verifies the JWT signature before applying the update. If verification fails, the update is rejected. ### Signing your app **iOS** 1. Use version 5.1.0 or higher of the app SDK. Earlier versions don't support code signing. 1. Make sure the Bitrise CodePush CLI version is 1.0.0 or higher to take advantage of code signing features. 1. Generate an RSA keypair in PEM format with Open SSL: ```bash openssl genrsa -out private_key.pem 2048 openssl rsa -in private_key.pem -pubout -out public_key.pem ``` You must keep the private key secure and never share it! The public key will be embedded inside the app itself. 1. Add the public key string inside your app’s `Info.plist`: ```xml CodePushPublicKey -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVJ2k... -----END PUBLIC KEY----- ``` 1. Rebuild your iOS app with the updated app SDK (>= 5.1.0) that supports code signing. 1. Bundle and sign your updates with the Bitrise CodePush CLI. :::warning The output directory must be named exactly `CodePush`. The SDK uses the directory name as a path prefix when verifying the package hash — any other name causes a hash mismatch and the update is silently rejected on-device. ::: ```bash bitrise :codepush bundle --platform ios --private-key-path ./private_key.pem ``` The signed JWT (`.codepushrelease` file) is generated inside the bundle directory and uploaded to the server. The uploaded `.zip` file contains both the `.codepushrelease` file and the bundled output file. 1. Push the already bundled update: ```bash bitrise :codepush push ./CodePush \ --deployment Staging \ --app-version 1.0.0 \ --private-key-path ./private_key.pem ``` :::tip Optionally, you can bundle, sign, and push in one command: ```bash bitrise :codepush push --bundle --platform ios \ --deployment Staging \ --app-version 1.0.0 \ --private-key-path ./private_key.pem ``` ::: **Android** 1. Use version 5.1.0 or higher of the app SDK. Earlier versions don't support code signing. 1. Make sure the Bitrise CodePush CLI version is 1.0.0 or higher to take advantage of code signing features. 1. Generate an RSA keypair in PEM format with Open SSL: ```bash openssl genrsa -out private_key.pem 2048 openssl rsa -in private_key.pem -pubout -out public_key.pem ``` You must keep the private key secure and never share it! The public key will be embedded inside the app itself. 1. Add the public key string in `/android/app/src/main/res/values/strings.xml`: ```xml -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArVJ2k... -----END PUBLIC KEY----- ``` 1. Configure the CodePush client instance. You can use a constructor: ```java new CodePush("deployment-key", getApplicationContext(), BuildConfig.DEBUG, R.string.CodePushPublicKey); ``` Or you can use a builder: ```java new CodePushBuilder("deployment-key", getApplicationContext()) .setIsDebugMode(BuildConfig.DEBUG) .setPublicKeyResourceDescriptor(R.string.CodePushPublicKey) .build(); ``` For React Native >= 0.61, follow the [Android setup guide](https://github.com/bitrise-io/react-native-code-push/blob/main/docs/setup-android.md) in the CodePush SDK repository. 1. Rebuild your Android app with the updated app SDK (>= 5.1.0) that supports code signing. 1. Bundle and sign your updates with the Bitrise CodePush CLI. :::warning The output directory must be named exactly `CodePush`. The SDK uses the directory name as a path prefix when verifying the package hash — any other name causes a hash mismatch and the update is silently rejected on-device. ::: ```bash bitrise :codepush bundle --platform android --private-key-path ./private_key.pem ``` The signed JWT (`.codepushrelease` file) is generated inside the bundle directory and uploaded to the server. The uploaded `.zip` file contains both the `.codepushrelease` file and the bundled output file. 1. Push the already bundled update: ```bash bitrise :codepush push ./CodePush \ --deployment Staging \ --app-version 1.0.0 \ --private-key-path ./private_key.pem ``` :::tip Optionally, you can bundle, sign, and push in one command: ```bash bitrise :codepush push --bundle --platform android \ --deployment Staging \ --app-version 1.0.0 \ --private-key-path ./private_key.pem ``` ::: ### Code signing support for Expo The app SDK and the Bitrise CodePush CLI both support code signing for Expo projects, too. The overall flow is the same as for standard React Native apps: generate an RSA key pair, embed the public key in the app, and sign bundles at release time using the --private-key-path flag. The main difference for managed Expo workflows is how the public key gets embedded: this typically requires [EAS Build](https://docs.expo.dev/build/introduction/) and a custom config plugin. When bundling and pushing updates, use the standard `bitrise :codepush` commands as usual. :::note The `--sourcemap-output` flag is not supported for Expo projects and should be omitted. ::: --- ## About the CodePush CLI The Bitrise CodePush CLI is a client for CodePush. Use it on your local machine to configure and manage your CodePush integration and updates. The CodePush CLI can run in two modes: as a [Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli) plugin (commands prefixed with `bitrise :codepush`), or as a standalone binary (commands prefixed with `codepush`). Both modes support the same commands and require a Bitrise API token to authenticate to the Bitrise CodePush server. The CodePush CLI is a Go binary that communicates with the Bitrise API over HTTPS. Most commands require a Bitrise API token for authentication. The exceptions are purely local operations: `bundle` invokes the React Native or Expo bundler directly on your machine (`npx react-native bundle` or `npx expo export:embed`), and `debug` streams logs from a connected device via `adb` or `xcrun` without making any API calls. With the CodePush CLI, you can: - Create, list, rename, and delete deployments. - Push updates, roll back to a previous release, promote a release between deployments, and patch the metadata of an existing release. - Show update details and update processing status for specific versions. - Initialize project configuration and store authentication information locally. - Generate JavaScript bundles for React Native and Expo projects. It auto-detects the project type, the entry file, Hermes, and the Metro config. You can also create and target different server environments with the CodePush CLI. For example, you can set a staging environment for your CodePush updates before you push them to the Bitrise CodePush server. The source code for the CodePush CLI is available on GitHub: [bitrise-io/bitrise-plugins-codepush-cli](https://github.com/bitrise-io/bitrise-plugins-codepush-cli). --- ## CodePush CLI authentication :::note The examples use plugin mode syntax. In standalone mode, replace `bitrise :codepush` with `codepush`. ::: To interact with the Bitrise API, which is required for CodePush commands, you need an API token. The token can be accessed in two ways: - By creating an Environment Variable (Env Var) and referring to it in your configuration. We recommend this for CI builds. - Storing the access token locally. We recommend this for local development. If you have both, the Env Var is resolved first and takes priority. ### Authenticating with an Env Var 1. [Generate a personal access token](/bitrise-platform/accounts/personal-access-tokens) and copy it. 1. Add the value of the token to the BITRISE_API_TOKEN Environment Variable. 1. When running a command, the CodePush CLI resolves the Env Var automatically. ### Storing the token locally 1. [Generate a personal access token](/bitrise-platform/accounts/personal-access-tokens) and copy it. 1. Run one of the following commands: ```bash # Interactive — prompts for your token bitrise :codepush auth login # Non-interactive bitrise :codepush auth login --token # or: -t ``` The token is stored in the user configuration directory with restricted permissions (0600): - macOS: `~/Library/Application Support/codepush/config.json` - Linux: `~/.config/codepush/config.json` ### Revoking a locally stored token If you want to revoke an API token that you stored locally for CodePush, you can do so at any time. If you revoke the token, you won't be able to interact with the Bitrise API unless you set the BITRISE_API_TOKEN Environment Variable. To revoke the token, run the following command: ```bash bitrise :codepush auth revoke ``` --- ## CodePush CLI reference :::note The examples use plugin mode syntax. In standalone mode, replace `bitrise :codepush` with `codepush`. ::: Run `bitrise :codepush --help` for detailed flags and usage of any command. ### Global flags | Flag | Description | |---|---| | `--app-id` | Release management app UUID (env: `CODEPUSH_APP_ID`) | | `--json`, `-j` | Output results as JSON to stdout | | `--server-url` | API server base URL (env: `CODEPUSH_SERVER_URL`) | | `--progress-style` | Progress indicator style: `bar` (default), `spinner`, `counter` | ### Commands #### Release management | Command | Description | |---|---| | `bundle` | Bundle JavaScript for an OTA update | | `push [bundle-path]` | Push an OTA update | | `rollback` | Rollback to a previous release | | `promote` | Promote a release from one deployment to another | | `patch` | Update metadata on an existing release | #### Deployment management | Command | Description | |---|---| | `deployment list` | List all deployments (`--display-keys` / `-k` to include key column) | | `deployment add ` | Create a new deployment (`--key` / `-k` for a custom deployment key) | | `deployment info ` | Show deployment details and latest release | | `deployment rename ` | Rename a deployment (`--name`, `-n`) | | `deployment remove ` | Delete a deployment (`--yes` / `-y` to confirm) | | `deployment history ` | Show release history (`--limit` / `-n`, default 10; `--display-author` / `-a` to include author column) | | `deployment clear ` | Delete all updates from a deployment (`--yes` / `-y` to confirm) | #### Update management | Command | Description | |---|---| | `update info ` | Show update details (`--label` / `-l` for specific version) | | `update status ` | Show update processing status (`--label` / `-l`) | | `update remove ` | Delete an update (`--label` / `-l` required, `--yes` / `-y` to confirm) | #### Setup | Command | Description | |---|---| | `init` | Initialize project config (`.codepush.json`) with app ID | | `auth login` | Store a Bitrise API token locally | | `auth revoke` | Remove the stored API token | #### Developer tools | Command | Description | |---|---| | `debug ` | Stream CodePush log output from a connected device or simulator (`android` or `ios`) | #### Other | Command | Description | |---|---| | `version` | Print version information | ### Environment variables | Variable | Description | |---|---| | `BITRISE_API_TOKEN` | API token for authentication | | `CODEPUSH_APP_ID` | Default release management app UUID (used when `--app-id` is not set) | | `CODEPUSH_DEPLOYMENT` | Default deployment name or UUID (used when `--deployment` is not set) | | `CODEPUSH_SERVER_URL` | API server base URL (used when `--server-url` is not set) | | `NO_COLOR` | Disable colored terminal output | #### Bitrise CI variables (read automatically) | Variable | Description | |---|---| | `BITRISE_BUILD_NUMBER` | Attached to push metadata | | `BITRISE_DEPLOY_DIR` | Directory for summary file export | | `GIT_CLONE_COMMIT_HASH` | Attached to push metadata | #### Exported variables (Bitrise CI) After a successful `push`, `rollback`, `promote`, or `patch`, the CLI exports these via `envman` for downstream Bitrise steps: | Variable | Description | |---|---| | `CODEPUSH_UPDATE_ID` | ID of the created or modified update | | `CODEPUSH_APP_VERSION` | App version of the release | | `CODEPUSH_LABEL` | Release label (patch command only) | ### Exit codes | Code | Meaning | |---|---| | `0` | Success | | `1` | Error (authentication failure, API error, validation error, etc.) | A non-zero exit code means the operation failed. Check stderr for the error message. --- ## Setting up the CodePush CLI The CodePush CLI can be installed in two ways: as a Bitrise CLI plugin, or as a standalone binary. Both support the same commands. Use plugin mode if you already use the Bitrise CLI; use standalone mode if you want to run the CLI independently. ### Plugin mode In plugin mode, commands are prefixed with `bitrise :codepush`. 1. [Install the Bitrise CLI](/bitrise-ci/bitrise-cli/installing-and-updating-the-bitrise-cli). 1. Run the following command: ```bash bitrise plugin install --source https://github.com/bitrise-io/bitrise-plugins-codepush-cli.git ``` 1. Verify the installation: ```bash bitrise :codepush ``` You can manage the plugin with standard Bitrise CLI commands: ```bash bitrise plugin list # confirm installation bitrise plugin update codepush # upgrade to latest version bitrise plugin uninstall codepush ``` ### Standalone mode In standalone mode, commands are prefixed with `codepush`. The Bitrise CLI is not required. 1. Download the binary for your platform from the [Releases page](https://github.com/bitrise-io/bitrise-plugins-codepush-cli/releases): | Platform | Binary | |---|---| | macOS (Apple Silicon) | `codepush-Darwin-arm64` | | macOS (Intel) | `codepush-Darwin-x86_64` | | Linux (x86_64) | `codepush-Linux-x86_64` | 1. Make it executable and move it to your PATH: ```bash chmod +x codepush-Darwin-arm64 mv codepush-Darwin-arm64 /usr/local/bin/codepush ``` 1. Verify the installation: ```bash codepush version ``` :::note[Differences from plugin mode] In standalone mode, `BITRISE_BUILD_NUMBER`, `BITRISE_DEPLOY_DIR`, and `GIT_CLONE_COMMIT_HASH` are not auto-populated, and `envman` exports (`CODEPUSH_UPDATE_ID`, `CODEPUSH_APP_VERSION`, `CODEPUSH_LABEL`) are unavailable for downstream steps. ::: ### Setting a custom server URL Set a different target environment for CodePush instead of the main Bitrise server. For example, you can set a staging environment as the base server URL. :::note The examples use plugin mode syntax. In standalone mode, replace `bitrise :codepush` with `codepush`. ::: There are three ways to do so: - Use any command with the `--server-url` flag: ```bash bitrise :codepush push --server-url https://api.staging.bitrise.io ``` - Export the `CODEPUSH_SERVER_URL` Environment Variable: ```bash export CODEPUSH_SERVER_URL=https://api.staging.bitrise.io ``` - Set the server URL during initializing with the `init` command. This writes the URL into the `.codepush.json` file: ```bash bitrise :codepush init --server-url https://api.staging.bitrise.io ``` The server URL is resolved in the following order: 1. The `--server-url` flag (highest priority) 1. The `CODEPUSH_SERVER_URL` environment variable 1. The `server_url` field in the `.codepush.json` file. 1. Default: https://api.bitrise.io --- ## Using the CodePush CLI :::note The examples use plugin mode syntax. In standalone mode, replace `bitrise :codepush` with `codepush`. ::: :::tip For a quick overview of all commands, flags, and environment variables, see the [CodePush CLI reference](/release-management/codepush/codepush-cli/codepush-cli-reference). ::: ### Setting up a project After successfully installing the CodePush CLI and setting up authentication, initialize a project to store your app ID locally: ```bash bitrise :codepush init ``` The command creates a `.codepush.json` file in the current directory. You can commit it to version control so your team shares the same configuration. When running `init` for the first time, the CLI prompts you for the app ID. You can get it from the app URL in Release Management: `https://app.bitrise.io/release-management/workspaces//connected-apps//`, or [via the API](https://api.bitrise.io/release-management/api-docs/index.html#/Connected%20Apps/ListApps). ```yaml Enter your app ID (UUID): >a3f47d2c-6b9e-4f1a-9d2b-7c8e5a1b2c3d ``` You can also pass it directly with `--app-id`, or set the `CODEPUSH_APP_ID` Environment Variable. The CLI resolves the app ID in the following order: 1. `--app-id` flag (highest priority) 1. `CODEPUSH_APP_ID` environment variable 1. `app_id` field in `.codepush.json` To overwrite an existing `.codepush.json`: ```bash bitrise :codepush init --force --app-id a3f47d2c-6b9e-4f1a-9d2b-7c8e5a1b2c3d ``` ### Release management #### Bundling your app The `bundle` command generates a JavaScript bundle for React Native and Expo projects. It auto-detects the project type, entry file, Hermes configuration, and Metro config. Bundle your app for each platform separately: ```bash bitrise :codepush bundle --platform ios bitrise :codepush bundle --platform android ``` If auto-detection fails, override the relevant flags manually: ```bash bitrise :codepush bundle --platform ios \ --entry-file index.js \ --config metro.config.js \ --pod-file ios/Podfile ``` For Android with Hermes, use `--gradle-file` instead of `--pod-file`: ```bash bitrise :codepush bundle --platform android \ --entry-file index.js \ --gradle-file android/app/build.gradle ``` #### Pushing updates The `push` command uploads a pre-built bundle to the CodePush server. You need to specify the deployment and the app version: ```bash bitrise :codepush push ./codepush-bundle \ --deployment Staging --app-version 1.0.0 ``` You can also bundle and push in one step with the `--bundle` flag: ```bash bitrise :codepush push --bundle --platform ios \ --deployment Staging --app-version 1.0.0 ``` #### Promoting a release The `promote` command copies a release from one deployment to another. It is most commonly used to move a release from a staging environment to production. ```bash bitrise :codepush promote \ --source-deployment Staging \ --destination-deployment Production \ --rollout 25 --description "Gradual rollout" ``` :::tip Pass `--no-duplicate-release-error` to exit 0 with a warning instead of an error when the target deployment already contains a release with identical content. ::: #### Patching a release The `patch` command updates metadata on an existing release without re-deploying the code. Patch a specific release by label: ```bash bitrise :codepush patch --deployment Production --label v5 --mandatory true ``` Increase the rollout percentage on the latest release: ```bash bitrise :codepush patch --deployment Production --rollout 50 ``` #### Rolling back The `rollback` command creates a new release that mirrors a previous version. Roll back to the immediately previous release: ```bash bitrise :codepush rollback --deployment Production ``` Roll back to a specific release by label: ```bash bitrise :codepush rollback --deployment Production --target-release v3 ``` ### Deployment management Create a deployment to get your deployment key. You need the deployment key to release CodePush updates to your app. List all deployments: ```bash bitrise :codepush deployment list bitrise :codepush deployment list --display-keys # include deployment keys ``` Create a new deployment: ```bash bitrise :codepush deployment add Beta ``` Create a new deployment with a custom deployment key: ```bash bitrise :codepush deployment add Beta --key my-custom-key ``` View deployment details and the latest release: ```bash bitrise :codepush deployment info Staging ``` View release history. By default, it shows the last 10 releases: ```bash bitrise :codepush deployment history Staging bitrise :codepush deployment history Staging --limit 25 bitrise :codepush deployment history Staging --display-author ``` Rename a deployment: ```bash bitrise :codepush deployment rename OldName --name NewName ``` Clear all releases from a deployment. This is a destructive operation; pass `--yes` to skip the confirmation prompt in CI: ```bash bitrise :codepush deployment clear Staging --yes ``` Delete a deployment. This is a destructive operation; pass `--yes` to skip the confirmation prompt in CI: ```bash bitrise :codepush deployment remove Beta --yes ``` ### Update management View details of the latest update in a deployment: ```bash bitrise :codepush update info Staging ``` View a specific update by label: ```bash bitrise :codepush update info Staging --label v5 ``` Check the processing status of an update. This is useful after a push to confirm the update was accepted: ```bash bitrise :codepush update status Staging ``` Delete a specific update. Use `--label` to specify the update and `--yes` to confirm: ```bash bitrise :codepush update remove Staging --label v3 --yes ``` ### JSON output Pass `--json` to any command to get machine-readable JSON output on stdout. Human-readable output always goes to stderr, so JSON output is clean for piping. Get push result as JSON: ```bash bitrise :codepush push ./CodePush \ --deployment Staging --app-version 1.0.0 --json ``` List deployments as JSON: ```bash bitrise :codepush deployment list --json ``` Parse output with `jq`: ```bash bitrise :codepush update info Staging --json | jq '.app_version' ``` ### Bitrise CI integration The CLI detects a Bitrise CI environment via the `BITRISE_BUILD_NUMBER` or `BITRISE_DEPLOY_DIR` environment variables. When running inside a Bitrise build, the CLI automatically: - Attaches build number and commit hash to push metadata. - Exports `codepush-bundle-summary.json` after bundling. - Exports `codepush-push-summary.json` after pushing. - Exports `codepush-patch-summary.json` after patching. - Exports environment variables via `envman` for downstream steps. - Disables interactive prompts and spinners. ### Workflow examples #### Full release lifecycle 1. Authenticate with your Bitrise API token: ```bash bitrise :codepush auth login --token $BITRISE_API_TOKEN ``` 1. Bundle the JavaScript for your target platform: ```bash bitrise :codepush bundle --platform ios ``` 1. Push to Staging with a limited rollout: ```bash bitrise :codepush push ./CodePush \ --deployment Staging \ --app-version 1.2.0 --rollout 10 --description "Fix login crash" ``` 1. Check the processing status to confirm the update was accepted: ```bash bitrise :codepush update status Staging ``` 1. Increase the rollout after verifying on test devices: ```bash bitrise :codepush patch --deployment Staging --rollout 100 ``` 1. Promote to Production: ```bash bitrise :codepush promote \ --source-deployment Staging \ --destination-deployment Production \ --rollout 25 ``` 1. If something goes wrong, roll back: ```bash bitrise :codepush rollback --deployment Production ``` #### Bitrise CI pipeline Set `BITRISE_API_TOKEN`, `CODEPUSH_APP_ID`, and `CODEPUSH_DEPLOYMENT` as environment variables in your Bitrise Workflow, then run a single command: ```bash bitrise :codepush push --bundle --platform ios --app-version $APP_VERSION ``` The CLI automatically detects the Bitrise environment, attaches build metadata (build number and commit hash), and exports summary files to `$BITRISE_DEPLOY_DIR`. #### Expo workflow Expo is auto-detected from `package.json` — no extra flags are needed. The CLI uses `npx expo export:embed` under the hood instead of `react-native bundle`. All other flags (deployment, app version, rollout, etc.) behave identically. ```bash bitrise :codepush push --bundle --platform ios \ --deployment Staging \ --app-version 1.0.0 ``` Two flags control the bundler behavior: - `--minify` (default `false`): whether to minify the bundle. Disabled by default to aid debugging; set `--minify=true` for the smallest possible bundle. - `--reset-cache` (default `true`): clears the Metro bundler cache before each run to ensure a clean output. Set `--reset-cache=false` to skip cache clearing and speed up repeated local runs. --- ## CodePush updates with Bitrise CI You can release your CodePush updates via a [Bitrise CI](/bitrise-ci) Workflow. The process requires: - Setting up CodePush credentials: create Secrets and [Environment Variables](/bitrise-ci/configure-builds/environment-variables) that hold the deployment ID and the deployment key from Bitrise CodePush. - Creating a Workflow that creates the update packages for both iOS and Android, and updates both to the Bitrise CodePush Server. ### Configuring CodePush credentials on Bitrise 1. [Get your credentials](/release-management/codepush/creating-and-releasing-codepush-updates#getting-your-codepush-credentials): you need the Release Management app IDs and the CodePush deployment IDs and deployment keys. 1. [Create Environment Variables](/bitrise-ci/configure-builds/environment-variables#setting-an-env-var-in-the-workflow-editor) for the deployment IDs and the connected app IDs: - `IOS_PROD_DEPLOYMENT_ID`: The deployment ID for the iOS app. - `ANDROID_PROD_DEPLOYMENT_ID`: The deployment ID for the Android app. - `IOS_CONNECTED_APP_ID`: The app ID for the iOS app. - `ANDROID_CONNECTED_APP_ID`: The app ID for the Android app. 1. [Create Secrets](/bitrise-ci/configure-builds/secrets#setting-a-secret) for the deployment key and the API token: - `IOS_PROD_DEPLOYMENT_KEY`: The deployment key of the iOS deployment from Bitrise CodePush. - `ANDROID_PROD_DEPLOYMENT_KEY`: The deployment key of the Android deployment from Bitrise CodePush. - `BITRISE_API_TOKEN`: Your personal access token or workspace API token. ### Creating a Workflow for CodePush updates This section shows you how to create a CI Workflow that will: - Create an update package for iOS. - Upload the iOS update package to Bitrise CodePush Server. - Create an update package for Android. - Upload the Android update package to Bitrise CodePush Server. **React Native app** 1. Create a Workflow and after the `git-clone` Step, add an `npm` Step with the `install` command: ```yaml --- format_version: '13' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: ios workflows: codepush_update_to_server: description: The workflow will generate and push your update to CodePush Server. steps: - git-clone@8: {} - npm@1: inputs: - command: install ``` 1. Add a `script` Step that extracts the app version using a JSON parser and set version in an Environment Variable using `envman`: ```yaml - script@1: title: Extract App Version inputs: - content: |- #!/bin/bash set -e # Extract version from app.json using jq (JSON parser) VERSION=$(jq -r '.version' package.json) # Verify version extraction if [ -z "$VERSION" ]; then echo "Error: Could not extract version from package.json" exit 1 fi echo "Extracted version from package.json: $VERSION" # Set the environment variable using envman envman add --key APP_VERSION --value "$VERSION" echo "Successfully set APP_VERSION=$VERSION" ``` 1. Add another `script` Step that clones the `release-management-recipes` repository from GitHub. This contains the upload script we'll use later. ```yaml - script@1: title: Get Release Management Recipes inputs: - content: >- #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x # write your script here git clone https://github.com/bitrise-io/release-management-recipes ``` 1. Generate your iOS update bundle and create a zip archive from it: ```yaml - script@1: title: Generate iOS Update Bundle inputs: - content: >- #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x npx react-native bundle \ --platform ios \ --dev false \ --entry-file index.js \ --bundle-output ./build/main.jsbundle \ --assets-dest ./build # Create zip archive zip -r update.zip ./build ``` 1. Upload the iOS update bundle to the CodePush Server with `upload_code_push_package.sh`: ```yaml - script@1: title: Upload iOS Update Bundle to Codepush Server inputs: - content: > #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x cd release-management-recipes UPLOAD_RESPONSE=$(PACKAGE_PATH=../update.zip \ AUTHORIZATION_TOKEN=$BITRISE_API_TOKEN \ CONNECTED_APP_ID=$IOS_CONNECTED_APP_ID \ DEPLOYMENT_ID=$IOS_PROD_DEPLOYMENT_ID \ APP_VERSION=$APP_VERSION /bin/bash ./api/upload_code_push_package.sh 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ]; then \ echo \"❌ upload_code_push_package.sh failed with exit code $EXIT_CODE\" \ echo \"$UPLOAD_RESPONSE\" \ exit $EXIT_CODE fi # Take only the last line of the response (final/latest status JSON object) FINAL_RESPONSE=$(echo "$UPLOAD_RESPONSE" | tail -n1) # Check explicitly for ERR_INTERNAL or other internal error indicators if echo \"$UPLOAD_RESPONSE\" | grep -q \"ERR_INTERNAL\"; then \ ERROR_MESSAGE=$(echo \"$FINAL_RESPONSE\" | jq -r '.message' || echo \"Unknown error\") \ echo \"❌ Server returned internal error: $ERROR_MESSAGE\" \ exit 1 fi # Now safely parse 'status' and 'status_reason' from the final response line PACKAGE_STATUS=$(echo "$FINAL_RESPONSE" | jq -r '.status' || echo "null") STATUS_REASON=$(echo "$FINAL_RESPONSE" | jq -r '.status_reason' || echo "") if [ "$PACKAGE_STATUS" = "processed_valid" ]; then echo "✅ Package uploaded and processed successfully." rm -rf ../build.zip rm -rf ../build else echo "⚠️ Package upload unexpected status: $PACKAGE_STATUS - Reason: $STATUS_REASON" exit 1 fi cd .. ``` 1. Generate the Android update bundle: ```yaml - script@1: title: Generate Android Update Bundle inputs: - content: | #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x npx react-native bundle \ --platform android \ --dev false \ --entry-file index.js \ --bundle-output ./build/index.android.bundle \ --assets-dest ./build # Create zip archive zip -r update.zip ./build ``` 1. Upload the Android update bundle to the CodePush Server: ```yaml - script@1: title: Upload Android Update Bundle to Codepush Server inputs: - content: | #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x cd release-management-recipes UPLOAD_RESPONSE=$(PACKAGE_PATH=../update.zip \ AUTHORIZATION_TOKEN=$BITRISE_API_TOKEN \ CONNECTED_APP_ID=$ANDROID_CONNECTED_APP_ID \ DEPLOYMENT_ID=$ANDROID_PROD_DEPLOYMENT_ID \ APP_VERSION=$APP_VERSION /bin/bash ./api/upload_code_push_package.sh 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ]; then echo "❌ upload_code_push_package.sh failed with exit code $EXIT_CODE" echo "$UPLOAD_RESPONSE" exit $EXIT_CODE fi # Take only the last line of the response (final/latest status JSON object) FINAL_RESPONSE=$(echo "$UPLOAD_RESPONSE" | tail -n1) # Check explicitly for ERR_INTERNAL or other internal error indicators if echo "$UPLOAD_RESPONSE" | grep -q "ERR_INTERNAL"; then ERROR_MESSAGE=$(echo "$FINAL_RESPONSE" | jq -r '.message' || echo "Unknown error") echo "❌ Server returned internal error: $ERROR_MESSAGE" exit 1 fi # Now safely parse 'status' and 'status_reason' from the final response line PACKAGE_STATUS=$(echo "$FINAL_RESPONSE" | jq -r '.status' || echo "null") STATUS_REASON=$(echo "$FINAL_RESPONSE" | jq -r '.status_reason' || echo "") if [ "$PACKAGE_STATUS" = "processed_valid" ]; then echo "✅ Package uploaded and processed successfully." else echo "⚠️ Package upload unexpected status: $PACKAGE_STATUS - Reason: $STATUS_REASON" exit 1 fi cd .. ``` **Expo app** 1. Create a Workflow and after the `git-clone` Step, add an `npm` Step with the `install` command: ```yaml --- format_version: '13' default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: ios workflows: codepush_update_deploy: description: | Uploads Update Bundle to Bitrise CodePush Server status_report_name: Executing for steps: - git-clone@8: {} - restore-npm-cache@2: {} - npm@1: inputs: - command: install ``` 1. Add a `script` Step that extracts the app version using `awk` and sets it as an Enviromment Variable: ```yaml - script@1: title: Extract App Version inputs: - content: |- #!/bin/bash set -e # Simpler version using awk APP_VERSION=$(awk -F'"' '/version:/ {print $2}' app.config.js) # Check if the version was successfully extracted if [ -z "$APP_VERSION" ]; then echo "Error: Failed to extract version from app.config.js" exit 1 fi echo "Extracted version: $APP_VERSION" # Set the environment variable using envman envman add --key APP_VERSION --value "$APP_VERSION" echo "Successfully set APP_VERSION=$APP_VERSION" ``` 1. Add another `script` Step that clones the `release-management-recipes` repository from GitHub. This contains the upload script we'll use later. ```yaml - script@1: title: Get Release Management Recipes inputs: - content: >- #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x # write your script here git clone https://github.com/bitrise-io/release-management-recipes ``` 1. Generate your iOS update bundle and create a zip archive from it: ```yaml - script@1: title: Generate iOS Update Bundle inputs: - content: |- #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x # write your script here npx expo export:embed \ --entry-file index.js \ --platform ios \ --dev false \ --reset-cache \ --bundle-output ./build/main.jsbundle \ --assets-dest ./build \ --minify false # Create zip archive zip -r update.zip ./build ``` 1. Upload the iOS update bundle to the CodePush Server with `upload_code_push_package.sh`: ```yaml - script@1: title: Upload iOS Update Bundle to Codepush Server inputs: - content: > #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x cd release-management-recipes UPLOAD_RESPONSE=$(PACKAGE_PATH=../update.zip \ AUTHORIZATION_TOKEN=$BITRISE_API_TOKEN \ CONNECTED_APP_ID=$IOS_CONNECTED_APP_ID \ DEPLOYMENT_ID=$IOS_PROD_DEPLOYMENT_ID \ APP_VERSION=$APP_VERSION /bin/bash ./api/upload_code_push_package.sh 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ]; then \ echo \"❌ upload_code_push_package.sh failed with exit code $EXIT_CODE\" \ echo \"$UPLOAD_RESPONSE\" \ exit $EXIT_CODE fi # Take only the last line of the response (final/latest status JSON object) FINAL_RESPONSE=$(echo "$UPLOAD_RESPONSE" | tail -n1) # Check explicitly for ERR_INTERNAL or other internal error indicators if echo \"$UPLOAD_RESPONSE\" | grep -q \"ERR_INTERNAL\"; then \ ERROR_MESSAGE=$(echo \"$FINAL_RESPONSE\" | jq -r '.message' || echo \"Unknown error\") \ echo \"❌ Server returned internal error: $ERROR_MESSAGE\" \ exit 1 fi # Now safely parse 'status' and 'status_reason' from the final response line PACKAGE_STATUS=$(echo "$FINAL_RESPONSE" | jq -r '.status' || echo "null") STATUS_REASON=$(echo "$FINAL_RESPONSE" | jq -r '.status_reason' || echo "") if [ "$PACKAGE_STATUS" = "processed_valid" ]; then echo "✅ Package uploaded and processed successfully." rm -rf ../build.zip rm -rf ../build else echo "⚠️ Package upload unexpected status: $PACKAGE_STATUS - Reason: $STATUS_REASON" exit 1 fi cd .. ``` 1. Generate the Android update bundle: ```yaml - script@1: title: Generate Android Update Bundle inputs: - content: | #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x # write your script here npx expo export:embed \ --entry-file index.js \ --platform android \ --dev false \ --reset-cache \ --bundle-output ./build/index.android.bundle \ --assets-dest ./build \ --minify false # Create zip archive zip -r update.zip ./build ``` 1. Upload the Android update bundle to the CodePush Server: ```yaml - script@1: title: Upload Android Update Bundle to Codepush Server inputs: - content: | #!/usr/bin/env bash # fail if any commands fails set -e # make pipelines' return status equal the last command to exit with a non-zero status, or zero if all commands exit successfully set -o pipefail # debug log set -x cd release-management-recipes UPLOAD_RESPONSE=$(PACKAGE_PATH=../update.zip \ AUTHORIZATION_TOKEN=$BITRISE_API_TOKEN \ CONNECTED_APP_ID=$ANDROID_CONNECTED_APP_ID \ DEPLOYMENT_ID=$ANDROID_PROD_DEPLOYMENT_ID \ APP_VERSION=$APP_VERSION /bin/bash ./api/upload_code_push_package.sh 2>&1) EXIT_CODE=$? if [ $EXIT_CODE -ne 0 ]; then echo "❌ upload_code_push_package.sh failed with exit code $EXIT_CODE" echo "$UPLOAD_RESPONSE" exit $EXIT_CODE fi # Take only the last line of the response (final/latest status JSON object) FINAL_RESPONSE=$(echo "$UPLOAD_RESPONSE" | tail -n1) # Check explicitly for ERR_INTERNAL or other internal error indicators if echo "$UPLOAD_RESPONSE" | grep -q "ERR_INTERNAL"; then ERROR_MESSAGE=$(echo "$FINAL_RESPONSE" | jq -r '.message' || echo "Unknown error") echo "❌ Server returned internal error: $ERROR_MESSAGE" exit 1 fi # Now safely parse 'status' and 'status_reason' from the final response line PACKAGE_STATUS=$(echo "$FINAL_RESPONSE" | jq -r '.status' || echo "null") STATUS_REASON=$(echo "$FINAL_RESPONSE" | jq -r '.status_reason' || echo "") if [ "$PACKAGE_STATUS" = "processed_valid" ]; then echo "✅ Package uploaded and processed successfully." else echo "⚠️ Package upload unexpected status: $PACKAGE_STATUS - Reason: $STATUS_REASON" exit 1 fi cd .. ``` ### Automating the CodePush update release After creating a Workflow to generate and upload your CodePush updates, you have two ways of running it: - [Run the Workflow manually](/bitrise-ci/run-and-analyze-builds/starting-builds/starting-builds-manually). - [Triggering a build automatically](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers) when a defined condition is met. For the available conditions, see [Supported trigger conditions](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers#supported-trigger-conditions). You can set up several different types of triggers to automate the process. Our example configuration uses a pull request trigger with a label: **Release a CodePush update when a pull request is opened to a specific branch** In this example, we're setting up a trigger where: - Bitrise looks for pull requests opened with `updates` as the target branch. - The `codepush_update_deploy` Workflow is triggered when a pull request to the branch receives the `release-update` label to the PR. 1. [Create the trigger](/bitrise-ci/run-and-analyze-builds/build-triggers/configuring-build-triggers#creating-build-triggers): set up a pull request trigger with two conditions, `target_branch` and `label`: - Set `target_branch` to `updates`. - Set `label` to `release-update`. :::tip[GUI config] You can set these up on the GUI of the Workflow Editor, too. Here we're showing you the YAML configuration. ::: ```yaml format_version: "13" default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git project_type: react-native workflows: codepush_update_deploy: status_report_name: 'Executing for ' description: | Uploads Update Bundle to Bitrise CodePush Server steps: [...] triggers: pull_request: - target_branch: updates label: release-update ``` 1. When you want to release CodePush updates, open a pull request to the `updates` branch. 1. After the PR has been reviewed and approved, add the `release-update` label to it. --- ## Configuring your mobile app for CodePush Configure the CodePush SDK in your React Native app to receive over-the-air updates. Both bare React Native and Expo projects are supported: see [Configuring CodePush for bare React Native projects](#configuring-codepush-for-bare-react-native-projects) and [Configuring CodePush for Expo apps](#configuring-codepush-for-expo-apps). The CodePush SDK [is open-source](https://github.com/bitrise-io/react-native-code-push) and [feedback is welcome](https://github.com/bitrise-io/react-native-code-push/issues/new). ### Configuring CodePush for Expo apps :::note[Continuous Native Generation] This guide is for projects which adopted Expo's [Continuous Native Generation](https://docs.expo.dev/workflow/continuous-native-generation/) feature. If you manually manage the native iOS and Android projects within your codebase (no Expo Prebuild), follow our [bare React Native setup](#configuring-codepush-for-bare-react-native-projects) instructions instead. ::: 1. Make sure your app's bundle ID and package name match the ones used while [creating the apps](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management) on Bitrise. In `app.json`, these are the `ios.bundleIdentifier` and `android.package` fields. 1. Install the CodePush app SDK: ```bash npm install @bitrise/code-push-sdk ``` 1. Add the Expo CodePush plugin to `app.json`: ```json { "plugins": [ // ...existing plugins [ "@bitrise/code-push-sdk/expo", { "ios": { "CodePushDeploymentKey": "...", "CodePushServerURL": "https://.codepush.bitrise.io" }, "android": { "CodePushDeploymentKey": "...", "CodePushServerURL": "https://.codepush.bitrise.io" } } ] ] } ``` **Deployment key**: Copy the value from the Bitrise CodePush deployments page. You get the deployment key when creating the [CodePush deployment on Bitrise](/release-management/codepush/creating-a-codepush-deployment). **Workspace slug**: The server URL requires your Bitrise workspace slug: [Identifying Workspaces and apps with their slugs](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs). :::note[Deployment keys are not secrets] These end up as plain string values in final app builds. They are not secrets, but they are unique to your workspace and your CodePush deployment setup. ::: 1. Verify configuration by running `npx expo prebuild`. You can manually verify the following generated files: - `ios//Info.plist`: contains `CodePushDeploymentKey` and `CodePushServerURL` entries. - `ios//AppDelegate.swift`: contains the `CodePush` import and `ReactNativeDelegate.bundleURL()` method override. - `android/app/src/main/res/values/strings.xml`: contains `CodePushDeploymentKey` and `CodePushServerURL` entries. - `android/app/src/main/java/.../MainApplication.kt`: `jsBundleFilePath` set to `CodePush.getJSBundleFile()`. 1. Initialize the update check in your app's root component: [Customizing the update lifecycle](#customizing-the-update-lifecycle). ### Configuring CodePush for bare React Native projects These instructions cover React Native's New Architecture. On older React Native versions, follow the SDK's [iOS setup](https://github.com/bitrise-io/react-native-code-push/blob/master/docs/setup-ios.md) and [Android setup](https://github.com/bitrise-io/react-native-code-push/blob/master/docs/setup-android.md) guides instead — then come back to this page for the deployment key and server URL values. 1. Add the CodePush SDK to the project: ```bash npm install @bitrise/code-push-sdk ``` 1. Set up the CodePush iOS SDK in your project: [iOS setup](#ios-setup). 1. Set up the CodePush Android SDK in your project: [Android setup](#android-setup). 1. Initialize the update check in your app's root component: [Customizing the update lifecycle](#customizing-the-update-lifecycle). #### iOS setup 1. Run `bundle exec pod install` from the `ios` folder to pick up the previously added CodePush SDK dependency. 1. Update `ios//AppDelegate.swift`: 1. Add an import statement for CodePush headers: ```swift import CodePush ``` 1. In `class ReactNativeDelegate`, find the line which returns the bundle URL for production builds and replace it with a call to the CodePush SDK: ```diff override func bundleURL() -> URL? { #if DEBUG RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index") #else - Bundle.main.url(forResource: "main", withExtension: "jsbundle") + CodePush.bundleURL() #endif } ``` Use CodePush to resolve the JS bundle location only in release builds. The `DEBUG` pre-processor macro switches between the Metro packager in debug builds and CodePush in release builds, so Chrome Dev Tools and live reload keep working while you debug. 1. Update `ios//Info.plist` with the CodePush deployment key and the CodePush server URL to let the CodePush runtime know which deployment it should query for updates against. ```xml CodePushDeploymentKey CodePushServerURL https://.codepush.bitrise.io ``` **Deployment key**: Copy the value from the Bitrise CodePush deployments page. You get the deployment key when creating the [CodePush deployment on Bitrise](/release-management/codepush/creating-a-codepush-deployment). **Workspace slug**: The server URL requires your Bitrise workspace slug: [Identifying Workspaces and apps with their slugs](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs). :::note[Deployment keys are not secrets] These end up as plain string values in final app builds. They are not secrets, but they are unique to your workspace and your CodePush deployment setup. ::: 1. Optional: If your iOS minimum deployment target is lower than 15.5, you need to bump it to at least `15.5`. In `ios/Podfile`, look for the line `platform :ios, min_ios_version_supported`. Change it to `platform :ios, '15.5'`. #### Android setup 1. Edit the app module's Gradle build script at `android/app/build.gradle`. Add this at the end of the file as an additional build task definition: ```groovy ... apply from: "../../node_modules/@bitrise/code-push-sdk/android/codepush.gradle" ... ``` 1. Update your Application class at `android/app/src/main/java/…/MainApplication.kt` to hook into the CodePush runtime. ```diff + import com.microsoft.codepush.react.CodePush class MainApplication : Application(), ReactApplication { override val reactHost: ReactHost by lazy { getDefaultReactHost( context = applicationContext, packageList = PackageList(this).packages.apply { // Packages that cannot be autolinked yet can be added manually here, for example: // add(MyReactNativePackage()) }, + // Set jsBundleFilePath to CodePush so CodePush resolves the JS bundle path + // at startup (OTA update if available, fallback to bundled JS otherwise). + jsBundleFilePath = CodePush.getJSBundleFile(), ) } } ``` 1. In `android/app/src/main/res/values/strings.xml`, add the CodePush deployment key and the CodePush server URL to let the CodePush runtime know which deployment it should query for updates against. ```xml ... https://.codepush.bitrise.io ``` **Deployment key**: Copy the value from the Bitrise CodePush deployments page. You get the deployment key when creating the [CodePush deployment on Bitrise](/release-management/codepush/creating-a-codepush-deployment). **Workspace slug**: The server URL requires your Bitrise workspace slug: [Identifying Workspaces and apps with their slugs](/bitrise-ci/api/identifying-workspaces-and-apps-with-their-slugs). :::note[Deployment keys are not secrets] These end up as plain string values in final app builds. They are not secrets, but they are unique to your workspace and your CodePush deployment setup. ::: ### Customizing the update lifecycle After you complete the configuration steps, CodePush hooks into the app's lifecycle and can load an updated bundle instead of the one packaged into the app. Customize when and how updates are installed by calling `codePush.sync()` from your app's root component. The SDK provides several options to customize the update experience. :::note[API reference] The [CodePush JS API reference](https://github.com/bitrise-io/react-native-code-push/blob/master/docs/api-js.md) lists all options and parameters. ::: You can set this up in several ways. #### Silent sync on app start The simplest, default behavior. Your app automatically downloads available updates and applies them the next time it restarts. This way, the entire update experience is silent to the end user, since they don't see any update dialog. ```javascript import { useEffect } from "react"; import codePush from "@bitrise/code-push-sdk"; function App() { useEffect(() => { // Fully silent update which keeps the app in // sync with the server, without ever // interrupting the end user codePush.sync(); }, []); return ; } ``` #### Silent sync every time the app resumes Same as the previous, except the app checks for updates, or applies an update if one exists every time the app returns to the foreground. ```javascript import { useEffect } from "react"; import { AppState } from "react-native"; import codePush from "@bitrise/code-push-sdk"; function App() { useEffect(() => { const syncOptions = { installMode: codePush.InstallMode.ON_NEXT_RESUME, }; codePush.sync(syncOptions); const subscription = AppState.addEventListener("change", (newState) => { if (newState === "active") { codePush.sync(syncOptions); } }); return () => subscription.remove(); }, []); return ; } ``` #### Interactive When an update is available, prompt the end user for permission before downloading it, and then immediately apply the update. If an update sets the `mandatory` flag, the end user is still notified about the update, but they don't have the choice to ignore it. ```javascript import { useEffect } from "react"; import codePush from "@bitrise/code-push-sdk"; function App() { useEffect(() => { // Active update, which lets the end user know // about each update, and displays it to them // immediately after downloading it codePush.sync({ updateDialog: true, installMode: codePush.InstallMode.IMMEDIATE }); }, []); return ; } ``` #### Log/display progress Pass the `syncStatusChangedCallback` and/or `downloadProgressCallback` arguments to `sync` to log the different stages of the process, or even display a progress bar to the user. ```javascript import { useEffect, useState } from "react"; import codePush from "@bitrise/code-push-sdk"; function App() { const [status, setStatus] = useState(null); useEffect(() => { codePush.sync( {}, (syncStatus) => setStatus(syncStatus), ({ receivedBytes, totalBytes }) => { console.log(`${receivedBytes} of ${totalBytes} received.`); } ); }, []); return ; } ``` --- ## Creating a CodePush deployment Create a CodePush deployment to get your deployment key. You need the deployment key to release CodePush updates to your apps. You can create a deployment either via the [API](/release-management/release-management-api) or on the Release Management GUI. **GUI** 1. For each React Native project, make sure you have [two apps](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management) in Release Management: one for iOS, one for Android. 1. 1. Open your app in Release Management. 1. On the left, select **Configuration**. ![20251216-configuration-rm.png](/img/_paligo/uuid-9e94e830-280a-4137-e869-f662722473df.png) 1. Select **Deployments**. 1. Click **New deployment**. 1. Enter a name. If you have multiple deployments, each must have a unique name. We recommend including the target of the deployment in the name (for example, Staging Deployment). 1. In the **Deployment key** field, you can paste an existing deployment key. If you leave it blank, Bitrise generates a secure deployment key for you. **API** 1. Make sure you have a [personal access token](/bitrise-platform/accounts/personal-access-tokens#creating-a-personal-access-token) or a [workspace API token](/bitrise-platform/workspaces/workspace-api-token#creating-a-workspace-api-token). A token is required for authorization with the [Release Management API](/release-management/release-management-api). 1. For each React Native project, make sure you have [two apps](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management) in Release Management: one for iOS, one for Android. 1. Get the app ID for each app. You can see it in the URL of the app page: https://app.bitrise.io/release-management/workspaces//connected-apps/. :::tip[ID from the API] You can [use the API to add apps](https://api.bitrise.io/release-management/api-docs/index.html#/Connected%20Apps/CreateConnectedApp). The response of the `/connected-apps` endpoint contains an `id` field: this is the app ID you need. ::: 1. Create a CodePush deployment for each app by calling the `/connected-apps/{connected_app_id}/code-push/deployments` endpoint. The request requires: - The connected app ID. - A token for authorization. - A name you will use for the deployment. In this example, we're using the name `prod`: ```bash curl -X 'POST' \ 'https://api.bitrise.io/release-management/v1/connected-apps//code-push/deployments' \ -H 'accept: application/json' \ -H 'authorization: ' \ -H 'Content-Type: application/json' \ -d '{ "name": "prod" }' ``` :::tip[Existing deploymentKey] If you already have a `deploymentKey` (for example, if you are migrating your setup from Microsoft App Center), you can use the `key` parameter in the API request: ```json { "name": "prod", "key": "" } ``` ::: 1. Copy the base64-encoded `key` returned in the response. This is the CodePush deployment key: you need this to [configure your app for CodePush](/release-management/codepush/configuring-your-app-for-codepush). --- ## Creating and releasing CodePush updates Create an update bundle and upload it to the Bitrise CodePush Server to push updates to your users' devices. :::important This guide describes the general process of releasing your CodePush updates. We recommend using Bitrise CI to automate the process: [CodePush updates with Bitrise CI](/release-management/codepush/codepush-updates-with-bitrise-ci). ::: ### Getting your CodePush credentials :::note[API only] If you use the GUI on bitrise.io to release your CodePush updates, you can skip this section. ::: You need the following deployment credentials to be able to release CodePush updates with the API: - A [deployment ID](/release-management/codepush/creating-a-codepush-deployment) from Bitrise CodePush. iOS and Android require separate deployment IDs. - An [app ID](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management) from Bitrise Release Management. iOS and Android require separate app IDs. - A deployment key. iOS and Android require separate deployment keys. - A Bitrise API token: it can be either a [personal access token](/bitrise-platform/accounts/personal-access-tokens) or a [workspace API token](/bitrise-platform/workspaces/workspace-api-token). You can save these credentials when creating the CodePush deployment. If you need to get them later, use the Release Management API: 1. Make sure you have a Bitrise API token: - [Creating a personal access token](/bitrise-platform/accounts/personal-access-tokens#creating-a-personal-access-token). - [Creating a Workspace API token](/bitrise-platform/workspaces/workspace-api-token#creating-a-workspace-api-token). 1. Get the app IDs from Release Management for both the iOS and the Android app: Open the app in Release Management, and copy the ID from the URL. It is the alphanumeric code at the end of the URL: https://app.bitrise.io/release-management/workspaces/4afb6c4bb001295/connected-apps/12a0cf2b-9cf1-401a-8904-393b18v449ca. 1. Get the deployment ID and the deployment key from the API: :::tip You can get both the ID and the key when creating the CodePush deployments. Read on if you didn't save them at the time. ::: For the deployment ID, call the `deployments` endpoint. It returns all deployments: ```yaml curl -X 'GET' \ 'https://api.bitrise.io/release-management/v1/connected-apps//code-push/deployments' \ -H 'accept: application/json' \ -H 'authorization: ' ``` The response contains the deployment ID (`id`) for each deployment which you need in order to get the deployment key (`key`. Call `deployments` with the `id` value: ```yaml curl -X 'GET' \ 'https://api.bitrise.io/release-management/v1/connected-apps//code-push/deployments/' \ -H 'accept: application/json' \ -H 'authorization: ' ``` With these credentials, you can proceed to release CodePush updates to your apps. ### Creating an update bundle **React Native** 1. Make the updates to your code. 1. Create an update bundle for both iOS and Android: - iOS: ```bash npx react-native bundle \ --platform ios \ --dev false \ --entry-file index.js \ --bundle-output ./build/main.jsbundle \ --assets-dest ./build ``` - Android: ```bash npx react-native bundle \ --platform android \ --dev false \ --entry-file index.js \ --bundle-output ./build/index.android.bundle \ --assets-dest ./build ``` 1. Zip the build folder: ```bash zip -r update.zip ./build ``` **Expo** 1. Make the updates to your code. 1. Create an update bundle for both iOS and Android: - iOS: ```bash npx expo export:embed \ --entry-file index.js \ --platform ios \ --dev false \ --reset-cache \ --bundle-output ./build/main.jsbundle \ --assets-dest ./build \ --minify false ``` - Android: ```bash npx expo export:embed \ --entry-file index.js \ --platform android \ --dev false \ --reset-cache \ --bundle-output ./build/index.android.bundle \ --assets-dest ./build \ --minify false ``` 1. Zip the build folder: ```bash zip -r update.zip ./build ``` ### Uploading the package to the Bitrise CodePush Server You can upload the package either via the Release Management GUI or the Release Management API. **GUI** 1. Open your app in Release Management. 1. Select **CodePush** on the left. 1. Select your deployment. ![20251217-rm-deployments.png](/img/_paligo/uuid-87908768-bac5-5e86-6412-826381a0b8a4.png) 1. Click **New update**. 1. In the **Target versions** field, add the version range of the update. You can use range expressions: [Target versions](#target-versions). 1. Optionally, add an update description. 1. Check **Enabled** to make sure users can download the update. ![20251217-new-codepush-update-dialog.png](/img/_paligo/uuid-8e971849-b560-9393-f308-ed2587195b2c.png) 1. Optionally, check **Mandatory** to prompt users to update immediately. 1. Drag and drop the update file to the drag-and-drop area or click the area and select a file. :::important[File requirements] - Upload a `.bundle`, `.jsbundle`, or `.zip` file. - The maximum file size is 50 MB. ::: 1. Set the percentage of users that will receive the update in the **Rollout percentage** field. You can increase the percentage value later. The default value is 100%. 1. Click **Release update**. **API** 1. Make sure your CodePush credentials are available: [Getting your CodePush credentials](#getting-your-codepush-credentials). 1. Clone the `release-management-recipes` repository from Bitrise. The repository contains a helper script that we will use to upload the update package. ```bash git clone https://github.com/bitrise-io/release-management-recipes ``` 1. Go in to the `release-management-recipes` folder: ```bash cd release-management-recipes ``` 1. Run the script to upload. The script requires the following input data: - The path of the `update.zip` file. - Your Bitrise API token: this can be either a [personal access token](/bitrise-platform/accounts/personal-access-tokens#creating-a-personal-access-token) or a [workspace API token](/bitrise-platform/workspaces/workspace-api-token). - The app ID of your Release Management app. - A deployment ID. - The version of your app. For more information, see [Target versions](/release-management/codepush/creating-and-releasing-codepush-updates#target-versions). The final command should look something like this: ```bash PACKAGE_PATH=../update.zip \ AUTHORIZATION_TOKEN= \ CONNECTED_APP_ID= \ DEPLOYMENT_ID= \ APP_VERSION= /bin/bash ./api/upload_code_push_package.sh ``` ### Target versions When creating an update for CodePush, you need to specify the app version when uploading the package to the CodePush server. This is a target version: users running the specified version of the app will receive the updates. You can use range expressions to specify the version: | Range expression | Who gets the update | | --- | --- | | 1.2.3 | Only devices running the specific binary app store version 1.2.3 of your app | | * | Any device configured to consume updates from your CodePush app | | 1.2.x | Devices running major version 1, minor version 2 and any patch version of your app | | 1.2.3 - 1.2.7 | Devices running any binary version between 1.2.3 (inclusive) and 1.2.7 (inclusive) | | >=1.2.3 <1.2.7 | Devices running any binary version between 1.2.3 (inclusive) and 1.2.7 (exclusive) | | 1.2 | Equivalent to >=1.2.0 <1.3.0 | | ~1.2.3 | Equivalent to >=1.2.3 <1.3.0 | | ^1.2.3 | Equivalent to >=1.2.3 <2.0.0 | --- ## Delta updates When you deliver an over-the-air update to a device, the time it takes to download and install the update matters for a smooth user experience. Updates deployed via CodePush typically only change a small portion of the app's code, so downloading and installing the entire bundle would be inefficient. CodePush computes delta updates between your package versions automatically, so only the changes are downloaded and installed. ### Delta update mechanisms A delta update package only contains the changes between the version already installed on the device and the version to install, rather than the full new version. ![Diagram comparing file-based diffing and binary diffing update packages](/img/codepush/file-vs-binary-diffing.png) **File-level diffing:** CodePush compares two releases file-by-file. The update package contains only newly added and changed files in full, plus a list of files to delete. Unchanged files are left out of the package. **Binary diffing:** A more efficient diffing mechanism. Like file-level diffing, unchanged files are left out of the package, and the package contains a list of files to delete. For a file that changed between the two versions, CodePush computes a byte-level patch between the old and new versions of that file, and ships the patch instead of the entire file. In most React Native updates, the JS bundle always changes between versions, so this technique avoids fetching the entire JS bundle file. ### Delta updates with CodePush CodePush computes delta updates between your package versions automatically. This is enabled by default, and results in smaller updates that the client SDK downloads and installs faster. It also reduces your data transfer costs. CodePush delta updates are computed on the server side, so you don't need to do anything special to enable them. The delta update mechanism is file-level diffing at the moment, with binary diffing support coming in Q4 2026 to the [Bitrise CodePush SDK](https://github.com/bitrise-io/react-native-code-push). --- ## About connected apps Apps are the basic building blocks in Release Management. To do anything, either distributing your installable artifacts to testers, or releasing them to app stores, you need a Release Management app. You can set up an app without setting up access to online services. But to take full advantage of everything Release Management offers, set up connections. You can [connect an app](/release-management/getting-started-with-release-management/connecting-an-app) from Apple's App Store or Google Play to a Bitrise project that has already been authenticated to access and manage data through the APIs of these services. Such an app is called a connected app. You need to have at least one connected app to use Release Management. Once an app is connected, you can: - [Create default release configurations for it called release presets](/release-management/releases/release-presets). - [View and modify its API access to online stores](/release-management/configuring-connected-apps/configuring-connected-app-integration). - [Set up team member permissions](/release-management/configuring-connected-apps/release-management-roles-and-permissions). - [Connect your LaunchDarkly account and select a project and environment to use its feature flags](/release-management/configuring-connected-apps/integrating-launchdarkly-feature-flags). Configurations of a connected app apply to all [releases added](/release-management/releases/adding-a-new-release) to that particular app. --- ## Changing connected app appearance All apps in Release Management have a title and app icon. You can edit the title and use your own custom icon. :::important[App icon requirements] The supported formats for the app icon are JPEG and PNG. It must have a non-transparent background. The maximum file size is 1 MB. ::: 1. 1. Log in to Bitrise, and from the left sidebar, select **Releases**. 1. Select your app from the list. 1. On the left, select **App settings**. Note that only **Project Admins** and **Workspace Owners** can access the **App settings** menu for an application. 1. In the **Appearance** section, you can: - Click **Edit title** to change the title. Set the new title in the dialog and then click **Save**. ![2025-08-08-rm-add-new-app-title.png](/img/_paligo/uuid-a8e8da8b-6759-e159-5aa4-6a97f83896dc.png) - Click **Change icon** to change the app icon. In the dialog, drag-and-drop a new icon. It must be a JPEG or a PNG with a non-transparent background, no bigger than 1 MB. ![2025-08-08-rm-change-app-icon.png](/img/_paligo/uuid-80fbbf58-d67b-34af-96aa-4b5124ef844e.png) :::note[App icons and our API] If you prefer, you can also change the app icon using our [API](https://api.bitrise.io/release-management/api-docs/index.html#/Connected%20Apps%20-%20Public%20Assets/GeneratePublicAssetUploadUrl). ::: --- ## Configuring connected app integration A connected app in Release Management uses a [Google Play Console service account](/bitrise-platform/integrations/connecting-a-google-service-account-to-bitrise) to connect to Google Play and an [App Store Connect account](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key) to connect to the App Store. When [connecting an app for the first time](/release-management/getting-started-with-release-management/connecting-an-app), you have to set up the store connections. You can modify these settings at any time. You can add multiple service accounts or API keys to your workspace. Each project and each connected app in Release Management can use different service accounts or API keys. An app in Release Management can either use: - The store connection of its project. - A store connection specific to the app. If, for example, you have multiple App Store Connect API keys set up in your Workspace, you can set one as your project's API key but use a different one for the connected app in Release Management. ### Using a project-level store connection :::important[Changing the connection] If you use a project-level store connection, changing the project's service account or API key will change the connected app's connection, too. This can break your releases! ::: **iOS** 1. [Set up an API key for your project](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key). 1. On the Release Management home page, select your app in the **Connected apps** list. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. On the left, select **Integrations**. 1. On the **Store** tab, find the **API key** card and click **Replace**. ![app-store-api-rm.png](/img/_paligo/uuid-e39aa886-e484-fe54-2563-8d5295796112.png) 1. In the dialog, select **Use project's API key**. 1. Click **Save changes**. **Android** 1. [Set up a service account for your project](/bitrise-platform/integrations/connecting-a-google-service-account-to-bitrise). 1. On the Release Management home page, select your app in the **Connected apps** list. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. On the left, select **Integrations**. 1. On the **Store** tab, find the **Service account** card and click **Replace**. ![service-account-rm.png](/img/_paligo/uuid-14a7856e-16ca-8a64-04fa-acf92ba93cc2.png) 1. In the dialog, select **Use project's service account**. 1. Click **Save changes**. ### Using an app-level store connection An app-level store connection means you set the service account or API key specifically for a given connected app. The app-level connection can be different from the project's configured connection. **iOS** 1. [Set up an API key for your project](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key). 1. On the Release Management home page, select your app in the **Connected apps** list. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. On the left, select **Integrations**. 1. On the **Store** tab, find the **API key** card and click **Replace**. ![app-store-api-rm.png](/img/_paligo/uuid-e39aa886-e484-fe54-2563-8d5295796112.png) 1. In the dialog, select **Set app-level API key**. 1. Select an API key from the **API key** dropdown menu. 1. Click **Save changes**. **Android** 1. [Set up a service account for your project](/bitrise-platform/integrations/connecting-a-google-service-account-to-bitrise). 1. On the Release Management home page, select your app in the **Connected apps** list. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. On the left, select **Integrations**. 1. On the **Store** tab, find the **Service account** card and click **Set service account**. 1. In the dialog, select **Set app-level service account**. ![service-account-rm.png](/img/_paligo/uuid-14a7856e-16ca-8a64-04fa-acf92ba93cc2.png) 1. Select the service account from the **Service account** dropdown menu. 1. Click **Save changes**. --- ## Deleting a connected app When you delete a connected app from Release Management, all data related to this app will be removed from Bitrise permanently. To delete a connected app: 1. Log in to Bitrise, and from the left sidebar, select **Releases**. 1. From the **Connected apps** list, select your app. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. On the left, select **App settings**. 1. On the bottom of the **Connected app settings** page, click **Delete app**. This opens the **Delete connected app** dialog. ![dialog-delete-app.png](/img/_paligo/uuid-c93bbd2a-6d87-97d3-11ee-ca32475064af.png) 1. Follow the instructions in the dialog to delete the app permanently. --- ## Integrating LaunchDarkly feature flags A feature flag in [LaunchDarkly](https://docs.launchdarkly.com/home) describes the different variations of a feature and the rules that allow different entities to access them. You can follow your application's feature flags through the integration between LaunchDarkly and Bitrise. To do so, you'll need to: 1. [Connect your LaunchDarkly account to Bitrise.](#connecting-your-launchdarkly-account-to-bitrise) 1. [Select a LaunchDarkly project and environment for the connected app in Release management](#selecting-your-launchdarkly-project-and-environment). ### Connecting your LaunchDarkly account to Bitrise 1. Make sure you are logged in to LaunchDarkly. 1. Open Bitrise. 1. 1. Log in to Bitrise and click the profile image in the upper right corner to open the dropdown menu. 1. Select the **Account settings** option. ![account-settings-page.png](/img/_paligo/uuid-b08c42b9-affd-b40d-3c6e-87410001d2fb.png) 1. On the left, select **Feature flags**. 1. In the **LaunchDarkly** section, click the **Connect** button. ![connect-launchdarkly.png](/img/_paligo/uuid-56915efe-d16d-4ab6-6535-f2b18d6ee6af.png) 1. You will be redirected to LaunchDarkly. Click **Authorize**. You now should have access to your LaunchDarkly project data in Release Management. ### Selecting your LaunchDarkly project and environment After you’ve [connected your LaunchDarkly account to Bitrise](#connecting-your-launchdarkly-account-to-bitrise), you will have access to your LaunchDarkly projects in Release Management. To select a LaunchDarkly project and environment for your connected app: 1. Log in to Bitrise, and from the left sidebar, select **Releases**. 1. From the **Connected apps** list, select your app. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. On the left sidebar, select **Feature flags**. 1. Click **Change** in the **Project and environment** section. It opens a dialog where you can edit the LaunchDarkly configuration for this connected app. ![launchdarkly.png](/img/_paligo/uuid-9d7fd7fc-e125-4f45-d011-f5ddcabe0106.png) 1. In the dialog window, select the LaunchDarkly project you wish to connect from the list and select the LaunchDarkly project environment you wish to use. 1. Select a LaunchDarkly project and environment. ![existing-launchdarkly-config.png](/img/_paligo/uuid-7902ae23-26f7-bcf3-ffee-11dd4e08a183.png) 1. Click **Save changes**. Once done, you should be able to see the feature flags of the LaunchDarkly project in each release of the app. --- ## Release Management roles and permissions To perform actions in Release Management , your account must have the required access. This access is controlled by permissions. A permission is the ability to perform a specific action, such as adding and connecting apps, creating releases, or changing connected app settings. ### Roles and permissions overview You can assign different roles to different team members. In Release Management, there are five different roles on three different levels: - **Workspace-level roles**: These roles aren't tied to a specific Release Management app, nor can you change them in Release Management. [They are fully tied to the Workspace](/bitrise-platform/workspaces/collaboration-and-permissions-in-workspaces/workspace-collaboration) that owns the Bitrise project that the connected app belongs to. There are two Workspace-level roles: - **Workspace owner**: Workspace owners have full administrative control over all aspects of an app in Release Management, without any limits or exceptions. - **Workspace manager**: The main purpose of workspace managers is to manage workspace collaboration. In Release Management, they can add a new app when creating a new project. They, however, can't add a new RM app under an already existing project. - **Contributor** and **Viewer**: These Workspace-level roles have no default access to Release Management apps. - **Project Admin**: The only [project-level role](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci) in Release Management. Adding a user to a project doesn't automatically give them any permissions in Release Management, with the exception of users with the Admin role. Project Admins have full administrative rights to apps, builds, Release Management, and app deployment with one exception: the Project Admin cannot add a new app with a new project to Release Management. When adding a new app to Release Management, they can only add it under the project of which they are admin. - **Release Management-level roles**: These are the roles you can configure within Release Management. - **Release manager**: The main purpose of Release Managers is to handle releases to online stores. They can't add new apps or access app settings. - **App tester**: The App tester role is meant for internal testers. They can access an app and its artifacts, and the [build distribution](urn:resource:component:92118) and [tester groups](/release-management/build-distribution/tester-groups) menu. They have no other access. ### Roles and permissions for Release Management apps | Actions | Workspace owner | Workspace manager | Project admin | Release manager | App tester | | --- | --- | --- | --- | --- | --- | | Access all apps of a project | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Access a specific app | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Access app settings and integrations | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Access release presets | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Access artifacts | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Access the list of release managers | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Access feature flags | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Add a new app to RM with a new project | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | | Add a new app to RM with an existing project | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Remove an app from RM | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Assign a license to an app | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Create, edit, and delete: - Feature flag configuration - Release preset | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Upload artifacts | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ### Roles and permissions for build distribution and releases | Action | Workspace owner | Workspace manager | Project admin | Release manager | App tester | | --- | --- | --- | --- | --- | --- | | Access the build distribution menu | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Access the tester groups | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | Access the list of testers | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Enable the public install page | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Create, modify, and notify tester groups | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Update, approve, and delete assigned tasks | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Create, modify, pause, and delete releases | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Create and edit instructions for testers in the What to test field | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Create and modify store version and localization | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Submit release for review | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ### Roles and permissions for Bitrise CodePush For more information on Bitrise CodePush click [here](/release-management/codepush/about-codepush). | Action | Workspace owner | Workspace manager | Project admin | Release manager | App tester | | --- | --- | --- | --- | --- | --- | | Read CodePush deploy | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Read CodePush packages | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Create CodePush deploy | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Delete CodePush deploy | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Update CodePush deploy | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | Upload CodePush packages | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Delete CodePush packages | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Update CodePush packages | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Promote CodePush packages | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Rollback CodePush packages | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | Request CodePush access | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | ![tick.svg](/img/_paligo/uuid-cff0066a-5a70-e7b4-5140-5dabde7188c2.svg) | | | | --- ## Adding a new app to Release Management To start using Release Management, you need to add at least one app. It doesn't require any store connection or a code repository. You will need to link the app to a [Bitrise project](/bitrise-platform/projects/projects-overview). If you don't have an existing Bitrise project, we'll automatically create one for you. To add an app: 1. Log in to Bitrise and select **Releases** from the left navigation menu. 1. If it's your first app, you will see the **Get started with Release Management** page. Start with adding your app. If it's not your first app, look for the **New app** button above the list of your apps. 1. Set a project for your app. - To link your app to an existing Bitrise project, select the **Existing project** option and choose a project from the dropdown menu. - To automatically create a new project, select the **New project** option. This project will be a Release Management project but you can add a CI configuration to it at any time. ![add-new-app-newproj.png](/img/_paligo/uuid-8821de29-e79d-0932-c3dd-f5deea8eba32.png) 1. On the next page, specify: - The app's title. - A mobile OS. - A package name or bundle ID, depending on the mobile OS. These are not validated at this point. We recommend using a package name or bundle ID that already exists in an online store but you can change it later anyway. ![adding-app.png](/img/_paligo/uuid-9073242e-afd9-262e-25cf-395ab1881ea6.png) 1. Click **Add app**. Once an app is added, you can start uploading installable artifacts and use our build distribution feature: [Distributing builds to testers](/release-management/build-distribution/distributing-builds-to-testers). To manage releases, you need to connect the app to an app store: [Connecting an app](/release-management/getting-started-with-release-management/connecting-an-app). --- ## Connecting an app After successfully adding a new app to Release Management, connect it to an app in either the App Store or Google Play to be able to create releases for the app. - For iOS, this means an app with a valid bundle ID on App Store Connect. - For Android, this means an app with a valid package name on Google Play. **iOS** 1. Make sure your iOS app is registered on the App Store. Later in the connecting process, you will have to enter the bundle ID of the app. 1. Make sure you have a Bitrise CI project. If you created your project when adding the app to Release Management, you can extend it with a CI configuration: [Adding a new project](/bitrise-ci/getting-started/adding-a-new-project). 1. Make sure you have at least one App Store Connect API key added to your workspace: [Connecting to an Apple service with API key](/bitrise-platform/integrations/apple-services-connection/connecting-to-an-apple-service-with-api-key). 1. Open your app in Release Management and select **Releases** in the left navigation. 1. Click **Connect app**. If you don't have a valid CI configuration, you will see **Add CI configuration** instead of the **Connect app** button. ![release-man-connect-app.png](/img/_paligo/uuid-58be0b4a-94fa-0a4b-1bac-91d7f81078a1.png) 1. Set an App Store Connect API key. You have two options in the dialog: **Use the project's API key**: This means connecting to the App Store with the API key set on the project level. Changing the API key of the project changes the API key for the Release Management app, too. **Set app-level API key**: You can select any of the API keys added to your workspace from the **API key** dropdown menu. With this option, it doesn't matter what API key is configured on the project level. 1. Enter the bundle ID and click **Validate**. The bundle ID must be an exact match of the bundle ID of an existing app on the App Store. If the validation is successful, the **Connect** button will be enabled. 1. Click **Connect**. **Android** 1. Make sure your Android app is registered on Google Play. 1. Make sure you have at least one Google service account added to your workspace: [Connecting a Google service account to Bitrise](/bitrise-platform/integrations/connecting-a-google-service-account-to-bitrise). 1. Make sure you have a Bitrise CI project. 1. Open your app in Release Management and select **Releases** in the left navigation. 1. Click **Connect app**. ![release-man-connect-app.png](/img/_paligo/uuid-58be0b4a-94fa-0a4b-1bac-91d7f81078a1.png) 1. Set a service account. You have two options in the dialog: **Use the project's service account**: This means connecting to Google Play with the service account set on the project level. Changing the service account of the project changes the service account for the Release Management app, too. **Set app-level service account**: You can select any of the service accounts added to your workspace from the **Service account** dropdown menu. With this option, it doesn't matter what API key is configured on the project level. 1. Enter the Google Play app's package name in the field and click **Validate**. - If the package name is found on Google Play, the **Connect** button will be enabled. - If the validation doesn't find a match, check if you typed the package name correctly and make sure your Google Play service account is working. 1. Click **Connect**. --- ## Connecting another CI service to Release Management You can use Release Management even if you don't use Bitrise CI. Upload your app's binary as a release candidate to access all Release Management features. For now, using Release Management still requires a Bitrise CI project as it's the only way to set up a [connected app](/release-management/getting-started-with-release-management/connecting-an-app). However, you don't have to run Bitrise CI builds: once the project is added, you can use Release Management without Bitrise CI. In the near future, Release Management will become a standalone solution. To connect your CI service to Release Management: 1. Sign up for Bitrise and [add a new Bitrise CI project](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache#adding-a-new-connection-to-the-build-cache). 1. [Connect an app](/release-management/getting-started-with-release-management/connecting-an-app) in Release Management. This includes setting up your project's connection to App Store Connect and/or Google Play. 1. [Use our API to upload an installable artifact](/release-management/installable-artifacts). 1. Select this artifact at the [release candidate stage](/release-management/releases/managing-the-release-process/selecting-a-release-candidate). --- ## Getting started with Release Management Bitrise Release Management simplifies distributing your iOS and Android apps to testers or directly to app stores. Release Management works by adding one or more Release Management apps to a Bitrise project. You upload installable artifacts (either IPA or APK/AAB files) to Release Management and then you can distribute the files to testers or release them to an online store. You can go to Release Management from the Dashboard or by selecting **Releases** from the left navigation sidebar. Both ways takes you to the **Release Management overview** screen where you will be able to see your apps in the future. To start using Release Management: 1. Learn about the [key concepts of Release Management](/release-management/getting-started-with-release-management/release-management-concepts). 1. Make sure you have at least one [Bitrise project](/bitrise-build-cache/getting-started-with-the-build-cache/getting-started-with-the-build-cache#adding-a-new-connection-to-the-build-cache). 1. [Add one or more new app(s)](/release-management/getting-started-with-release-management/adding-a-new-app-to-release-management). 1. Check out [build distribution for testing](/release-management/build-distribution/distributing-builds-to-testers): you can distribute installable artifacts to testers without involving Google Play or the App Store. 1. [Connect the app(s)](/release-management/getting-started-with-release-management/connecting-an-app): this requires setting up a connection to App Store Connect or Google Play. 1. Once you have a connected app, [add a new release](/release-management/releases/adding-a-new-release). 1. [Configure your release](/release-management/releases/configuring-a-release/configuring-auto-upload). 1. [Go through the stages of the release process](/release-management/releases/managing-the-release-process/about-the-release-process) to release the app. --- ## Managing licenses Release Management offers additional features beyond the basic functionalities of the free plan. A Standard license must be purchased and assigned to a connected app to enable the features of the Standard plan for that particular connected app. ### Licenses and current apps You can manage licenses on the Release Management overview page, from the Licences widget above the list of connected apps. For each license, you will see the following numbers: - **Current apps**: the number of apps you assigned the license to for the billing period. - **Apps in plan**: the total number of licenses available in your plan. ### Assigning licenses to connected apps You can start with a Basic license after connecting an app, and upgrade anytime to get access to the additional benefits of the Standard license. A license is non-transferable after it has been assigned to a connected app, it remains bound to that app for the duration of the license term (the billing cycle). To assign licenses to connected apps: 1. Open Release Management. 1. Find the **Licenses** widget above the **Connected apps** list and click **Manage**. 1. Select the license for each connected app. The **Change** column will display if the assigned license of an app will change, and when the change takes effect. 1. On the summary, review the total number of assigned licenses for the current and the next period. 1. Click **Confirm changes**. ### Exceeding your plan limit If the number of assigned licenses exceeds the plan limit, a notification will appear. You can go back to [change assigned licenses](#assigning-licenses-to-connected-apps) or change your plan to proceed with the selected configuration. To solve the issue: 1. Click the link in the notification to change your plan. It will open the **Change plan for Release Management** page in a new browser tab. 1. Increase or decrease the number of **Apps in plan** (the licenses you can assign to connected apps). If the number of **Current apps** exceeds the new **Apps in plan** limit, you will get a notification, but you can continue to checkout. Make sure to manage licenses before the changes take effect to keep using all features for new releases. :::caution When **Current apps** exceed the number of **Apps in plan** for Standard licenses, you will not have access to additional benefits of the Standard license for any connected apps in your Workspace. ::: --- ## Release Management concepts To successfully use Release Management, there are a few concepts you need to be aware of. ### Connected app You [connect your app](https://devcenter.bitrise.io/en/release-management/getting-started-with-release-management/connecting-an-app.html) from the App Store or Google Play to a Bitrise project. This is what we call a connected app. You need at least one connected app to be able to add and manage releases in Release Management. To use [build distribution](/release-management/build-distribution/distributing-builds-to-testers), you don't actually need to connect an app. ### Releases You [manage releases](/release-management/releases/adding-a-new-release) of a connected app: each release is a new version of an app. An iOS release has a version number, and an Android release has a version name. ### Release Manager A team member in Release Management with the [required permissions](https://devcenter.bitrise.io/en/release-management/configuring-connected-apps/release-management-roles-and-permissions.html) to manage releases. Project admins can [grant the Release Manager role](https://devcenter.bitrise.io/en/release-management/configuring-connected-apps/release-management-roles-and-permissions.html#granting-release-manager-rights) to [team members](https://devcenter.bitrise.io/en/release-management/configuring-connected-apps/release-management-roles-and-permissions.html#team-member-permissions). With this role, Release Managers are the only ones who can do any end-user-facing actions in Release Management: submit an iOS app for review or release an app to an app store. ### Release presets For each connected app, you can define [presets](/release-management/releases/release-presets), which are configuration values automatically applied in a new blank release. After the presets are applied, you can still edit these values during the release process. You can create a [release note preset](/release-management/releases/release-presets) as well. This means every release will be submitted to the App Store or Google Play with the same release notes. A release note preset can be identical in all localizations or you can manually edit it in the release stage. ### Release stages Once you added a new release to a connected app and configured it, you can go through the different release steps of the release process, called stages. You can only move to the next release stage after completing the current one, but you can return to a previous stage any time. iOS Android 1. [Release candidate](/release-management/releases/managing-the-release-process/selecting-a-release-candidate): In the **Release candidate** stage, specify the release branch and select the Workflow that generates an IPA file. 1. [TestFlight](/release-management/releases/managing-the-release-process/testflight-upload-stage#uploading-the-release-candidate-to-testflight): Upload the release candidate to TestFlight, and distribute it for testing. 1. [Approvals](/release-management/releases/managing-the-release-process/creating-tasks-for-the-approvals-stage): You can create tasks for any stakeholder or team member whose approval is needed to continue with the release to the App Store. 1. [App Store review](/release-management/releases/managing-the-release-process/sending-your-app-to-app-store-review): Submit your update to review in the App Store, and get information on the approval progress. 1. [Release on the App Store](/release-management/releases/managing-the-release-process/releasing-your-app-on-the-app-store): You can release your app to all users at the same time, or configure a phased release. 1. [Release candidate](/release-management/releases/managing-the-release-process/selecting-a-release-candidate): In the **Release candidate** stage, specify the release branch and select the Workflow that generates an AAB file. 1. [Google Play upload and testing](/release-management/releases/managing-the-release-process/google-play-upload-stage#uploading-the-release-candidate-to-google-play): Upload the release candidate to Google Play, and distribute it for testing. 1. [Approvals](/release-management/releases/managing-the-release-process/creating-tasks-for-the-approvals-stage): You can create tasks for any stakeholder or team member whose approval is needed to continue with the release to Google Play. 1. [Release on Google Play](/release-management/releases/managing-the-release-process/releasing-your-app-on-the-app-store): You can release your app to all users at the same time, or configure a staged rollout. ### Build distribution With Release Management [you can distribute the builds of your mobile apps](/release-management/build-distribution/distributing-builds-to-testers) to testers without having to engage with either TestFlight or Google Play. Once you have installable artifacts, Bitrise can generate both private and public install links that testers and other stakeholders can use to install the app on real devices via over-the-air installation. You can [define tester groups](https://devcenter.bitrise.io/en/release-management/build-distribution/tester-groups.html) that can receive notifications about installable artifacts and where those can be accessed. ### Approval task You can [create tasks](/release-management/releases/managing-the-release-process/creating-tasks-for-the-approvals-stage) for each stakeholder and/or team member whose approval is needed to continue with the release to the App Store Connect or Google Play. Optionally, you can assign an approval task to a team member or leave it unassigned. Only the assigned team member can approve the task. You can create and assign as many tasks as necessary. Once the tasks are ticked off, **Approvals** will be ticked off as well on the left navigation bar and you can proceed to App Store Review or releasing your app to Google Play. --- ## Release Management --- ## Installable artifacts :::important[IMPORTANT: Artifact retention policy] Artifacts, including [build logs](/bitrise-ci/run-and-analyze-builds/build-data-and-troubleshooting/build-logs), [build files](/bitrise-ci/run-and-analyze-builds/managing-build-files/build-artifacts-online), installable artifacts, or [CodePush](/release-management/codepush/about-codepush) packages, are only stored for a limited amount of time. For details, see [Artifact retention policy](/bitrise-ci/run-and-analyze-builds/managing-build-files/artifact-retention-policy). ::: There are two ways to upload installable artifacts to Release Management so they can be used as release candidates: - Generating them via a Bitrise build of a [connected app](/release-management/getting-started-with-release-management/connecting-an-app). - Using our API endpoint. This is particularly useful if you use a different CI service instead of Bitrise. - Use our [premade bash script](https://github.com/bitrise-io/release-management-recipes/blob/main/api/upload_installable_artifact.sh) to use the API endpoint. ### Using a Bitrise build If you use Bitrise CI, getting an installable artifact is only a matter of running a build that generates one: 1. Make sure you have a [connected app](/release-management/getting-started-with-release-management/connecting-an-app) in Release Management. 1. Make sure you have the [**Deploy to Bitrise.io**](https://github.com/bitrise-steplib/steps-deploy-to-bitrise-io) Step in the Bitrise Workflow that generates the installable artifact (IPA, APK or AAB). 1. Run a build. All installable artifacts from successful builds will be available on the **Artifacts** page and can be [selected as a release candidate](/release-management/releases/managing-the-release-process/selecting-a-release-candidate). ### Using the API The API requires two requests to upload an installable artifact: 1. The first request is to get the upload information. This request must contain: - Your API authentication token. [Workspace tokens](/bitrise-platform/workspaces/workspace-api-token) and [personal access tokens](/bitrise-platform/accounts/personal-access-tokens) are both accepted. - The slug of the connected app. This is automatically filled in if you get the request from the Release Management UI. - The file name and the file size in bytes. 1. The second request is to upload the file to the artifact storage. The request must be built using the response from the previous request's response. It returns: - The necessary HTTP headers. - The HTTP method for the upload. - The URL to send the request (containing all required information) to. 1. Optionally, you can use a third request to check the status of the upload. You can check the relevant endpoints in the [official API documentation](https://api.bitrise.io/release-management/api-docs/index.html#/Installable%20Artifacts%20-%20COMING%20SOON/GenerateInstallableArtifactUploadUrl). You can get the API requests from the **Release candidate** stage or the **Artifacts** page. **RC stage** 1. Make sure you have a [connected app](/release-management/getting-started-with-release-management/connecting-an-app) in Release Management. 1. Open your connected app. 1. Select your release and go to the **Release candidate** stage. 1. In the source card, click **Configure**. ![configure-source-rm.png](/img/_paligo/uuid-5e506f8a-6c68-cbef-ee53-8e97df232093.png) 1. In the dialog, select **Upload via API**. 1. Get the curl command for the upload URL and then the curl command for the upload file. Replace `[AUTH_TOKEN]`, `[FILE_NAME]`, `[FILE_SIZE]` and `[UPLOAD_URL]` placeholders with the actual values. ![upload-url.png](/img/_paligo/uuid-044617c9-e24c-068d-1978-df721db2a9f8.png) :::tip[Bash script available] You can also find [a link to a bash script](https://github.com/bitrise-io/release-management-recipes/blob/main/api/upload_installable_artifact.sh) that you can use to set up your API calls easily. ::: 1. Optionally, check **Automatically select after successful upload** to make sure that your binary is automatically selected as a release candidate once the upload is successful. If you do not check this, you can select your release candidate from a list of artifacts. 1. Click **Save changes**. 1. Use the API requests to upload your artifacts. **Build distribution page** 1. Make sure you have a [connected app](/release-management/getting-started-with-release-management/connecting-an-app) in Release Management. 1. Open your connected app. 1. Select **Build distribution** from the left navigation menu and select the **Builds** tab. 1. Click **Upload via API**. 1. Get the curl command for the upload URL and then the curl command for the upload file. Replace `[AUTH_TOKEN]`, `[FILE_NAME]`, `[FILE_SIZE]` and `[UPLOAD_URL]` placeholders with the actual values. :::tip[Bash script available] You can also find [a link to a bash script](https://github.com/bitrise-io/release-management-recipes/blob/main/api/upload_installable_artifact.sh) that you can use to set up your API calls easily. ::: 1. Click **OK, got it** when you are ready. 1. Use the API requests to upload your artifacts. **Artifacts page** 1. Make sure you have a [connected app](/release-management/getting-started-with-release-management/connecting-an-app) in Release Management. 1. Open your connected app. 1. Select **Artifacts** from the left navigation menu and go to the **Upload via API** tab. 1. Click **Configure**. ![installable-artifacts-api.png](/img/_paligo/uuid-33deefaf-a687-276f-ff84-cb0b6e45e885.png) 1. Get the curl command for the upload URL and then the curl command for the upload file. Replace `[AUTH_TOKEN]`, `[FILE_NAME]`, `[FILE_SIZE]` and `[UPLOAD_URL]` placeholders with the actual values. :::tip[Bash script available] You can also find [a link to a bash script](https://github.com/bitrise-io/release-management-recipes/blob/main/api/upload_installable_artifact.sh) that you can use to set up your API calls easily. ::: 1. Click **OK, got it** when you are ready. 1. Use the API requests to upload your artifacts. ### Using the bash script To make using the API more convenient, we've created a bash script that simplifies the upload process. It supports Linux distributions (alpine, arch, centos, debian, fedora, rhel, ubuntu) and macOS. The script checks your system and then attempts to upload installable artifacts to Release Management. To use the script: 1. Get the [script from GitHub](https://gist.github.com/miklosboros/4855a59213724f6eb5960579e15d285b). 1. Make sure you have `sudo` privileges on your system OR `jq` and `openssl` packages installed. 1. Set up the following Environment Variables in your system: - ARTIFACT_PATH: Local path of the artifact to be uploaded. - AUTHORIZATION_TOKEN: The access token for the Bitrise Release Management API. You can use a Bitrise [personal access token](/bitrise-platform/accounts/personal-access-tokens) or a [Workspace token](/bitrise-platform/workspaces/workspace-api-token). - CONNECTED_APP_ID: The app ID of the [connected app](/release-management/getting-started-with-release-management/connecting-an-app) the artifact will be uploaded to. You can get the ID from the URL of the app's page on bitrise.io: https://app.bitrise.io/release-management/workspaces/WORKSPACE_ID/connected-apps/CONNECTED_APP_ID. 1. Run the script. --- ## Adding a new release To release a connected app to the App Store or Google Play, you need to add a new release. Each app can have multiple releases. To add a new release to [a connected app](/release-management/getting-started-with-release-management/connecting-an-app): 1. 1. Log in to Bitrise, and from the left sidebar, select **Releases**. 1. Select your app from the list. 1. Go to **Releases** and click **+ New app version**. This opens the **New app version** page. 1. Enter a version number for iOS apps or a release name for Android apps. Optionally, you can also add a description. :::note[Release description is internal only] The release description is internal only, and it will not be included in the App Store review submission (metadata). ::: 1. Choose whether to **Apply a template** (pre-fill release settings) or **Start with a blank release** (no presets applied). If you choose **Apply a template**, select a template from the **Preset template** dropdown menu. You can configure templates in [Release presets](/release-management/releases/release-presets). 1. Click **Add app version**. After successfully adding a release, you can modify its configuration at any time: [Configuring a release](/release-management/releases/configuring-a-release/configuring-auto-upload). --- ## Configuring auto-upload You can automatically upload your release to [Google Play](/release-management/releases/managing-the-release-process/google-play-upload-stage) or [TestFlight](/release-management/releases/managing-the-release-process/testflight-upload-stage). When auto-upload is enabled, all successful builds are uploaded automatically. If auto-upload is disabled, builds will have to be uploaded manually. ### Configuring auto-upload for a release 1. 1. Open Release Management, and select your app from the list. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. Select **Releases** and then select the release you need. 1. Select **Configuration**. 1. Find the **Release process** section. 1. Find **Auto-upload** and toggle it on. ![2025-08-08-rm-auto-upload-toggle.png](/img/_paligo/uuid-f316a946-dc82-c3b9-9e73-a65f9f12349c.png) ### Configuring auto-upload as a release preset You can enable auto-upload as part of a release preset template. This will apply to all new releases that use the template. 1. Open Release Management and select your app from the list. 1. Select **Release presets** from the left navigation menu. ![20251216-rm-presets.png](/img/_paligo/uuid-bf243542-7a52-3b3e-e6d5-26d0248c3951.png) 1. Click the options menu (⋮) next to the template you need, and select **Change**. 1. Find **Auto-upload** and toggle it on. ![2025-08-08-rm-auto-upload-toggle.png](/img/_paligo/uuid-f316a946-dc82-c3b9-9e73-a65f9f12349c.png) --- ## Configuring Slack and Teams notifications You can enable Slack and Microsoft Teams notifications for Release Management events. You need to create an incoming webhook at your preferred service (or both), and add the webhook URL in Release Management. :::important[Standard plan only] Please note that this feature is only available on a [paid plan](https://bitrise.io/pricing). ::: ### Configuring notifications for a release You can configure notifications for each individual release: **Slack** 1. [Configure a Slack integration for your workspace](/bitrise-platform/workspaces/workspace-slack-integration). 1. 1. Open Release Management, and select your app from the list. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. Select **Releases** and then select the release you need. 1. Select **Configuration**. 1. Find the **Release process** section and the **Notifications** card. 1. Click **Show details**. 1. Click the options menu (⋮) next to **Slack**. ![2025-08-08-rm-slack-notification.png](/img/_paligo/uuid-40c38dac-74da-dcc2-0e07-64366c2732dc.png) 1. Click **Change configuration**. 1. In the dialog, select your previously configured Slack configuration. :::tip[Test notification] Click **Send test notification** to make sure your configuration works. ::: **Teams** 1. Configure [an incoming webhook for Teams](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=dotnet): 1. 1. Open Release Management, and select your app from the list. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. Select **Releases** and then select the release you need. 1. Select **Configuration**. 1. Find the **Release process** section and the **Notifications** card. 1. Click **Show details**. 1. Click the options menu (⋮) next to **Teams**. 1. Select **Edit webhook URL** ![2025-08-08-rm-configure-teams-notification.png](/img/_paligo/uuid-823c9a6f-187a-6778-36eb-130492487193.png) 1. In the dialog, copy and paste your webhook URL in the **URL** field and click **Save**. :::tip[Test notification] Click **Send test notification** to make sure your webhook works. ::: ### Configuring notifications as a release preset You can configure notifications as part of [a release preset template](/release-management/releases/release-presets). These notification settings will be applied to every new release that uses the template. **Slack** 1. [Configure a Slack integration for your workspace](/bitrise-platform/workspaces/workspace-slack-integration). 1. Open Release Management and select your app from the list. 1. Select **Release presets** from the left navigation menu. ![release-presets-notif.png](/img/_paligo/uuid-7c480e99-66d6-8197-a63a-e9275e127d78.png) 1. Click the options menu (⋮) next to the template you need, and select **Change**. 1. In the **Notifications** section, find Slack, and click the ellipsis next to its name. ![slack-int-rm.png](/img/_paligo/uuid-0876f906-f150-c883-a882-3d1da1ae42dc.png) 1. Click **Change configuration**. 1. Select your previously configured integration in the dialog. :::tip[Test notification] Click **Send test notification** to make sure your configuration works. ::: **Teams** 1. Configure [an incoming webhook at Teams](https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=dotnet). 1. Open Release Management and select your app from the list. 1. Select **Release presets** from the left navigation menu. ![release-presets-notif.png](/img/_paligo/uuid-7c480e99-66d6-8197-a63a-e9275e127d78.png) 1. Click the options menu (⋮) next to the template you need, and select **Change**. 1. In the **Notifications** section, find Teams, and click the ellipsis next to it. 1. Click **Edit webhook URL**. 1. In the dialog, copy and paste the webhook URL in the **URL** field and click **Save**. :::tip[Test notification] Click **Send test notification** to make sure your webhook works. ::: ### Notification events | Stage | Event | Event description | | --- | --- | --- | | Release candidate | Release candidate set | This event is triggered each time there is a new release candidate is selected in the Release candidate stage. This can happen automatically (a new build generated a new IPA) or manually (the release manager locks a specific artifact on the Release candidate stage). | | TestFlight upload | Upload and processing finished | This event is triggered when TestFlight processing is finished for an uploaded IPA. First we upload the IPA to TestFlight, then the TestFlight processing starts. When the processing finishes, we trigger the event. | | | Approved by TestFlight App Review | This event is triggered when Apple approves the beta app review that is required for sharing the app with external beta testers. | | | Rejected by TestFlight App Review | This event is triggered when Apple rejects the beta app review that is required for sharing the app with external beta testers. | | Approvals | Release approved | This event is triggered when all tasks are approved at the Approval stage. It will not be triggered for each approval, only when all tasks are done. If there are no approval tasks set, the event will trigger immediately after the previous event. | | App Store review | Release sent for review | This event happens when the store review submission starts. (Release Manager clicks on the submit button, and Apple accepts it) | | | Status of review submission changed | This event is triggered each time there is a change in the status of the review submission. (Approved, rejected, canceled) | | Release | Release started | This event is triggered after the submission was accepted, and the release rollout started (so the new version becomes available in App Store Connect) | | | Release finished | This event is triggered when the release gets a completed status in Release Management (which means the release is fully rolled out to Google Play or the App Store.) | | Stage | Event | Event description | | --- | --- | --- | | Release candidate | Release candidate set | This event is triggered each time there is a new release candidate is selected in the Release Candidate stage. This can happen automatically (a new build generated a new AAB) or manually (the release manager locks a specific artifact on the Release candidate stage). | | Google Play upload | Upload and processing finished | This event is triggered after the AAB is uploaded to Google Play console and is available in the App bundle explorer. | | | Release on testing track | This event is triggered after the release candidate is released on a Google Play testing track. | | Approvals | Release approved | This event is triggered when all tasks are approved at the Approval stage. It will not be triggered for each approval, only when all tasks are done. | | Release | Release started | This event is triggered when a release is started. It can be a full release or a staged rollout. For a staged rollout, it only happens once, at the first rollout. | | | Release finished | This event is triggered when release is completed in Release Management. | | | Rollout percentage changed | This event is triggered if the rollout percentage changes from any percentage other than 0%. For example, if the rollout percentage goes from 10% to 20%. It is NOT triggered when the first rollout happens. | --- ## Deleting a release :::warning[Deleting a release is permanent!] Deleting a release is irreversible and you will lose all data of the release in Release Management. Your data in TestFlight, App Store Connect, or Google Play will not be lost, and ongoing processes in the App Store or the Google Play Store will not be affected. App Store review will not be canceled. App Store phased releases will be automatically finished. Google Play staged rollouts will be stopped but you can finish the process manually on Google Play. ::: To delete a release: 1. 1. Open Release Management, and select your app from the list. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. Select **Releases** and then select the release you need. 1. Select **Configuration**. 1. Scroll down to the **Delete release** section, and click **Remove release**. 1. In the dialog, click **Remove** to confirm. --- ## Editing the description of a release You can enter a release description when you add a new release. This helps identifying the release later. You can change the description at any time in the release configuration: :::tip[Release description is internal only] The release description is internal only, and it will not be included in the submission. ::: 1. 1. Open Release Management, and select your app from the list. ![2025-08-07-rm-your-apps-list.png](/img/_paligo/uuid-c446a6a9-f922-2641-53ad-49099a7921fe.png) 1. Select **Releases** and then select the release you need. 1. Select **Configuration**. 1. On the release information card, click **Edit**. ![2025-08-08-rm-editing-release-description.png](/img/_paligo/uuid-54d3257f-0147-d101-0dde-c0296dcb798a.png) 1. In the **Edit Release details** dialog, update the description and click **Save**. --- ## Outgoing webhooks in Release Management Outgoing Webhooks are automated messages sent from Bitrise to a specified URL when a particular event occurs. For Release Management, these webhooks allow you to integrate Bitrise with external services and tools, enabling seamless communication and automation across your development pipeline. :::note[Standard plan only] You can add outgoing Webhooks to a Workspace, but connecting them in a [Release Management](/release-management) project is only possible for projects with [standard license](https://bitrise.io/pricing#release-management). ::: ### Adding an outgoing webhook to a release You can add outgoing webhooks to a release in two ways: - Add the webhook to an individual release. - Add the webhook to a release preset template. All releases using that template will use the configured webhook. **Individual release** 1. Make sure your external service is ready to receive and process the webhook requests. This typically involves: - Creating a publicly accessible URL to receive the HTTP POST requests from Bitrise. - Handling the JSON payload: parse the JSON data and extract the relevant information. - Defining the actions your service should take based on the received event. 1. [Create an outgoing webhook](/bitrise-platform/integrations/webhooks/adding-outgoing-webhooks) on Bitrise. 1. Open Release Management. 1. Select your app. 1. Select a release that hasn't finished. ![2025-10-29-releases.png](/img/_paligo/uuid-77ae83b9-c3d4-60a7-9997-ad0a27832d58.png) 1. Go to **Configuration**. 1. Find the **Outgoing webhooks** card and click **Show details**. ![2025-10-29-outgoing-webhooks-rm.png](/img/_paligo/uuid-28b052ba-a18f-12ee-7a9a-04720bb6fdd1.png) 1. Click **Add webhook**. 1. Select a webhook from the **Webhook configuration** menu. ![2025-10-29-rm-add-outgoing-webhook.png](/img/_paligo/uuid-f9d557bf-8cd0-2856-4555-61352d73ca56.png) 1. Select the events that will trigger the webhook. See the full list of events and their payload information: [Webhook events](/release-management/releases/configuring-a-release/outgoing-webhooks-in-release-management#webhook-events). **Release preset** 1. Make sure your external service is ready to receive and process the webhook requests. This typically involves: - Creating a publicly accessible URL to receive the HTTP POST requests from Bitrise. - Handling the JSON payload: parse the JSON data and extract the relevant information. - Defining the actions your service should take based on the received event. 1. [Create an outgoing webhook](/bitrise-platform/integrations/webhooks/adding-outgoing-webhooks) on Bitrise. 1. Open Release Management. 1. Select your app. 1. Go to **Release presets**. ![2025-10-29-release-presets.png](/img/_paligo/uuid-05179598-b31c-84ba-3b1d-03720f842acc.png) 1. [Create a new template](/release-management/releases/release-presets) or modify an existing one. 1. On the template page, find the **Outgoing webhooks** card and click **Show details**. 1. Click **Add webhook**. 1. Select a webhook from the **Webhook configuration** menu. ![2025-10-29-rm-add-outgoing-webhook.png](/img/_paligo/uuid-f9d557bf-8cd0-2856-4555-61352d73ca56.png) 1. Select the events that will trigger the webhook. See the full list of events and their payload information: [Webhook events](/release-management/releases/configuring-a-release/outgoing-webhooks-in-release-management#webhook-events). ### Removing an outgoing webhook from a release You can remove an outgoing webhook from an individual release or from a release preset template. **Individual release** 1. Open Release Management. 1. Select your app. 1. Select a release that hasn't finished. ![2025-10-29-releases.png](/img/_paligo/uuid-77ae83b9-c3d4-60a7-9997-ad0a27832d58.png) 1. Go to **Configuration**. 1. Find the **Outgoing webhooks** card and click **Show details**. 1. Click the remove configuration icon. ![2025-10-29-remove-webhooks-rm.png](/img/_paligo/uuid-32cdcf4a-27ea-2a5c-a439-3828a31fec7c.png) **Release preset** 1. Open Release Management. 1. Select your app. 1. Select **Release presets** on the left. ![2025-10-29-release-presets.png](/img/_paligo/uuid-05179598-b31c-84ba-3b1d-03720f842acc.png) 1. Find the release preset template you need and click the options menu (⋮), then select **Change**. 1. Find the **Outgoing webhooks** card and click **Show details**. 1. Click the remove configuration icon. ### Webhook events Multiple release automation events can trigger a webhook. All webhooks contain the following fields: | `Field name` | `Format` | | --- | --- | | `app_id` | | | `project_id` | | | `release_candidate_artifact_id` | | | `release_id` | | | `sent_at` | Nanosecond precision UNIX timestamp | | `store_app_id` | | | `triggered_at` | Nanosecond precision UNIX timestamp | | `triggered_by` | Either a user slug or one of: `Automation`, `Apple App Store`, `Google Play Store` | | `trigger_event` | | | `webhook_config_id` | | | `webhook_event_unique_id` | `WEBHOOK_ID@TRIGGER_TIMESTAMP_NANO` | | `workspace_id` | | The following webhook events are available. The **Fields** column contains the additional fields that the triggering event adds to the webhook payload. | Webhook name | Trigger event | Fields | | --- | --- | --- | | App version added | `app_version_added` | - `description` - `preset_template_id` | | Release description changed | `release_description_changed` | - `description` | | Auto-upload enabled | `auto-upload_enabled` | | | Auto-upload disabled | `auto-upload_disabled` | | | Slack connection changed | `slack_connection_changed` | | | Microsoft Teams connection changed | `microsoft_teams_connection_changed` | | | Automation added | `automation_added` | - `event_name` - `pipeline_name` - `workflow_name` | | Automation removed | `automation_removed` | - `event_name` - `pipeline_name` - `workflow_name` | | Outgoing webhook added | `outgoing_webhook_added` | - `all_events` Available values: `true/false` - `events`: Listed only if `all_events` are false. - `webhook_configuration_id` | | Outgoing webhook updated | `outgoing_webhook_updated` | - `all_events` true/false - `events`: Listed only if `all_events` are false - `webhook_configuration_id` | | Outgoing webhook deleted | `outgoing_webhook_deleted` | - `all_events` Available values: `true/false` - `events` Listed only if `all_events` are false - `webhook_configuration_id` | | Stopped managing release | `stopped_managing_release` | - `reason_for_stopping` Available values: `abandoned/completed externally` | | Release candidate source changed | `release_candidate_source_changed` | - `from_source` Available values: `ci/api/empty string` - `to_source` Available values: `ci/api` - `from_branch`: Only if the value of `from_source` is `ci` - `from_workflow`: Only if the value of `from_source` is `ci`. - `to_branch`: Only if the value of `to_source` is `ci`. - `to_workflow`: Only if the value of `to_source` is `ci`. | | Release candidate auto select latest build disabled | `release_candidate_auto_select_latest_build_disabled` | | | Release candidate auto select latest build enabled | `release_candidate_auto_select_latest_build_enabled` | | | Release candidate build selected | `release_candidate_build_selected` | - `file_name` - `version` - `version_code` | | TestFlight upload started | `testflight_upload_started` | - `file_name` - `version` - `version_code` | | TestFlight upload failed | `testflight_upload_failed` | - `file_name` - `version` - `version_code` | | TestFlight upload completed | `testflight_upload_completed` | - `file_name` - `version` - `version_code` | | TestFlight processing failed | `testflight_processing_failed` | - `file_name` - `version` - `version_code` | | TestFlight processing completed | `testflight_processing_completed` | - `file_name` - `version` - `version_code` | | TestFlight what to test added | `testflight_what_to_test_added` | - `language` - `what_to_test` | | TestFlight what to test changed | `testflight_what_to_test_changed` | - `language` - `what_to_test` | | TestFlight what to test deleted | `testflight_what_to_test_deleted` | - `language` | | TestFlight app review submitted | `testflight_app_review_submitted` | - `testflight_beta_build_id` | | TestFlight app review approved | `testflight_app_review_approved` | - `testflight_beta_build_id` | | TestFlight app review rejected | `testflight_app_review_rejected` | - `testflight_beta_build_id` | | TestFlight distribution started | `testflight_distribution_started` | - `group_id` - `testflight_beta_build_id` | | TestFlight distribution start failed | `testflight_distribution_start_failed` | - `group_id` - `testflight_beta_build_id` | | TestFlight distribution stopped | `testflight_distribution_stopped` | - `group_id` - `testflight_beta_build_id` | | Google Play upload started | `google_play_upload_started` | - `file_name` - `version` - `version_code` | | Google Play upload completed | `google_play_upload_completed` | - `file_name` - `version` - `version_code` | | Google Play upload failed | `google_play_upload_failed` | - `file_name` - `version` - `version_code` | | Google Play testing track release completed | `google_play_testing_track_release_completed` | - `file_name` - `track_name` - `version` - `version_code` | | Google Play testing track release failed | `google_play_testing_track_release_failed` | - `file_name` - `track_name` - `version` - `version_code` | | Approval tasks completed | `approval_tasks_completed` | - `approval_task_ids` - `skipped_with_zero_tasks (boolean)` | | Approval task added | `approval_task_added` | - `approval_id` - `assigned_to` - `created_by` - `description` - `due_date` - `title` | | Approval task changed | `approval_task_changed` | - `approval_id` - `assigned_to` - `created_by` - `description` - `due_date` - `title` | | Approval task completed | `approval_task_completed` | - `approval_id` - `assigned_to` - `created_by` - `description` - `due_date` - `title` | | Approval task deleted | `approval_task_deleted` | - `approval_id` - `assigned_to` - `created_by` - `description` - `due_date` - `title` | | Approval task reopened | `approval_task_reopened` | - `approval_id` - `assigned_to` - `created_by` - `description` - `due_date` - `title` | | App store version created | `app_store_version_created` | - `version` | | App store version updated | `app_store_version_updated` | - `version` | | Metadata localization added | `metadata_localization_added` | - `language` - `added_values` | | Metadata localization changed | `metadata_localization_changed` | - `language` - `changed_values` | | Metadata localization removed | `metadata_localization_removed` | - `language` | | Release settings changed | `release_settings_changed` | - `earliest_release_date` - `phased_release` - `release_type` - `version_string` | | Phased release enabled | `phased_release_enabled` | | | Phased release disabled | `phased_release_disabled` | | | App store review submitted | `app_store_review_submitted` | - `file_name` - `version` - `version_code` | | App store review cancelled | `app_store_review_cancelled` | - `file_name` - `version` - `version_code` | | App store review rejected | `app_store_review_rejected` | - `file_name` - `reason` - `version` - `version_code` | | App store review approved | `app_store_review_approved` | - `file_name` - `version` - `version_code` | | App store release cancelled | `app_store_release_cancelled` | - `file_name` - `version` - `version_code` | | Phased release paused | `phased_release_paused` | - `percentage_of_users` | | Phased release resumed | `phased_release_resumed` | - `percentage_of_users` | | App store release started | `app_store_release_started` | | | App store release completed | `app_store_release_completed` | | | Google Play release notes localization added | `google_play_release_notes_localization_added` | - `language` - `release_notes` | | Google Play release notes localization changed | `google_play_release_notes_localization_changed` | - `language` - `release_notes` | | Google Play release notes localization removed | `google_play_release_notes_localization_removed` | - `language` - `release_notes` | | Google Play release started | `google_play_release_started` | - `release_method` - `staged_release` | | Google Play rollout percentage changed | `google_play_rollout_percentage_changed` | - `release_method` - `rollout_percentage_from` - `rollout_percentage_to` | | Google Play automated rollout configured | `google_play_automated_rollout_configured` | - `rollout_start_time` | | Google Play automated rollout paused | `google_play_automated_rollout_paused` | - `rollout_percentage` | | Google Play automated rollout resumed | `google_play_automated_rollout_resumed` | - `rollout_percentage` | | Google Play automated rollout cancelled | `google_play_automated_rollout_cancelled` | | | Google Play release completed | `google_play_release_completed` | | --- ## Release automation You can specify events in the release management process that triggers a selected Workflow or Pipeline. For example, you can create an automation that triggers a Workflow whenever an App Store review is cancelled. :::important[Standard plan only] Please note that this feature is only available on a [paid plan](https://bitrise.io/pricing). ::: :::note[Env Vars from Release Management] Release Management passes over certain Environment Variables to your builds at the Release candidate stage and later at the Release stage: [Available environment variables](/bitrise-ci/references/available-environment-variables). You can use these Env Vars in your builds triggered by automations. ::: To configure a release automation: ### Configuring automations for a release You can configure automations separately for each individual release: 1. 1. Log in to Bitrise, and from the left sidebar, select **Releases**. 1. Select your app from the list. 1. Select **Releases** and then select your release. 1. Select **Configuration** on the left navigation bar. 1. In the **Release process** section, find **Automation**. 1. Click **Show details** and then click **Add automation**. ![2025-08-08-rm-add-automation.png](/img/_paligo/uuid-7225cae0-64cd-a1cf-b878-270a054e58da.png) 1. Under the **Event** field, select a release management event that will trigger the Workflow or Pipeline. ![2025-08-08-rm-add-automation-dialog.png](/img/_paligo/uuid-5e41d5a0-b686-edc7-44a5-42c09bf1b12b.png) 1. Set the automation type to either **Workflow** or **Pipeline**. 1. Click **Add automation**. ### Configuring automations as a release preset You can configure automations as [a release preset](/release-management/releases/release-presets). These automation settings will be applied to every new release afterwards. 1. Open Release Management and select your app. 1. Select **Release presets** from the left navigation menu. ![release-presets-notif.png](/img/_paligo/uuid-7c480e99-66d6-8197-a63a-e9275e127d78.png) 1. Click the options menu (⋮) next to the name of your preset template and select **Change**. 1. In the **Release process** section, find **Automation**. 1. Click **Show details** and then click **Add automation**. 1. Under the **Event** field, select a release management event that will trigger the Workflow or Pipeline. ![2025-08-08-rm-add-release-automation-preset-dialog.png](/img/_paligo/uuid-28812c0e-a307-6879-8d90-d0d516765519.png) 1. Set the automation type to either **Workflow** or **Pipeline**. 1. Click **Add automation**. ### Automation events Here you can find all of the events which can trigger Bitrise CI Workflows. Release automations will have an Environment Variable (Env Var), called $RM_EVENT_ID, which identifies the trigger. You can find more [Release Management Env Vars](/bitrise-ci/references/available-environment-variables#release-management-env-vars) in [Available Environment Variables](/bitrise-ci/references/available-environment-variables). | Stage | Event | Event description | | --- | --- | --- | | Release candidate | Release candidate setEvent ID: `release_candidate_set` | This event is triggered each time there is a new release candidate is selected in the Release candidate stage. This can happen automatically (a new build generated a new IPA) or manually (the release manager locks a specific artifact on the Release candidate stage). | | TestFlight upload | Upload and processing finishedEvent ID: `testflight_upload_finished` | This event is triggered when TestFlight processing is finished for an uploaded IPA. First we upload the IPA to TestFlight, then the TestFlight processing starts. When the processing finishes, we trigger the event. | | TestFlight upload | Approved by TestFlight App ReviewEvent ID: `beta_review_approved` | This event is triggered when Apple approves the beta app review that is required for sharing the app with external beta testers. | | TestFlight upload | Rejected by TestFlight App ReviewEvent ID: `beta_review_rejected` | This event is triggered when Apple rejects the beta app review that is required for sharing the app with external beta testers. | | TestFlight upload | Released to TestFlight/App Store testing groupEvent ID: `release_for_apple_app_store_testing_group` | This event is triggered when an uploaded build gets released to a TestFlight testing group. | | Approvals | Release approvedEvent ID: `approvals_completed` | This event is triggered when all tasks are approved at the Approval stage. It will not be triggered for each approval, only when all tasks are done. If there are no approval tasks set, the event will trigger immediately after the previous event. | | App Store review | Release sent for reviewEvent ID: `submitted_for_review` | This event happens when the store review submission starts. (Release Manager clicks on the submit button, and Apple accepts it) | | App Store review | Status of review submission changedEvent ID: `review_status_changed` `review_cancelled` | This event is triggered each time there is a change in the status of the review submission. (Approved, rejected, canceled) | | Release | Release startedEvent ID: `release_started` | This event is triggered after the submission was accepted, and the release rollout started (so the new version becomes available in App Store Connect) | | Release | Release finishedEvent ID: `release_completed` | This event is triggered when the release gets a completed status in Release Management (which means the release is fully rolled out to Google Play or the App Store.) | | Stage | Event | Event description | | --- | --- | --- | | Release candidate | Release candidate setEvent ID: `release_candidate_set` | This event is triggered each time there is a new release candidate is selected in the Release Candidate stage. This can happen automatically (a new build generated a new AAB) or manually (the release manager locks a specific artifact on the Release candidate stage). | | Google Play upload | Upload and processing finishedEvent ID: `google_play_store_upload_finished` | This event is triggered after the AAB is uploaded to Google Play console and is available in the App bundle explorer. | | Google Play upload | Release on testing trackEvent ID: `release_on_google_play_store_testing_track` | This event is triggered after the release candidate is released on a Google Play testing track. | | Approvals | Release approvedEvent ID: `approvals_completed` | This event is triggered when all tasks are approved at the Approval stage. It will not be triggered for each approval, only when all tasks are done. | | Release | Release startedEvent ID: `release_started` | This event is triggered when a release is started. It can be a full release or a staged rollout. For a staged rollout, it only happens once, at the first rollout. | | Release | Release finishedEvent ID: `release_completed` | This event is triggered when release is completed in Release Management. | | Release | Rollout percentage changedEvent ID: `release_percentage_changed` | This event is triggered if the rollout percentage changes from any percentage other than 0%. For example, if the rollout percentage goes from 10% to 20%. It is NOT triggered when the first rollout happens. | --- ## About the release process Once you added a new release to a connected app and successfully configured it, you can go through the different release stages of the release process. You can only move to the next release stage after completing the current one, but you can return to a previous stage any time. If you make changes to a previous stage, you must start the process over from that stage. **iOS** 1. [Release candidate](/release-management/releases/managing-the-release-process/selecting-a-release-candidate): In the **Release candidate** stage, specify the release branch and select the Workflow that generates an IPA file. :::note[Env Vars from Release Management] Release Management passes over certain Environment Variables to pipelines and workflows triggered by a [release automation](/release-management/releases/configuring-a-release/release-automation): [Available environment variables](/bitrise-ci/references/available-environment-variables). ::: 1. [TestFlight](/release-management/releases/managing-the-release-process/testflight-upload-stage#uploading-the-release-candidate-to-testflight): Upload the release candidate to TestFlight, and distribute it for testing. 1. [Approvals](/release-management/releases/managing-the-release-process/creating-tasks-for-the-approvals-stage): You can create tasks for any stakeholder or team member whose approval is needed to continue with the release to the App Store. 1. [App Store review](/release-management/releases/managing-the-release-process/sending-your-app-to-app-store-review): Submit your update to review in the App Store, and get information on the approval progress. 1. [Release](/release-management/releases/managing-the-release-process/releasing-your-app-on-the-app-store): You can release your app to all users at the same time, or configure a phased release. **Android** 1. [Release candidate](/release-management/releases/managing-the-release-process/selecting-a-release-candidate): In the **Release candidate** stage, specify the release branch and select the Workflow that generates an AAB file. 1. [Google Play upload and testing](/release-management/releases/managing-the-release-process/google-play-upload-stage#uploading-the-release-candidate-to-google-play): Upload the release candidate to Google Play, and distribute it for testing. 1. [Approvals](/release-management/releases/managing-the-release-process/creating-tasks-for-the-approvals-stage): You can create tasks for any stakeholder or team member whose approval is needed to continue with the release to Google Play. 1. [Release](/release-management/releases/managing-the-release-process/releasing-your-app-on-the-app-store): You can release your app to all users at the same time, or configure a staged rollout. --- ## Creating tasks for the approvals stage In the **Approvals** stage, you can create tasks for each stakeholder and/or team member whose approval is needed to continue with the release to the App Store Connect or Google Play. Optionally, you can assign an approval task to a team member. Only the assigned team member can approve the task. 1. Open your release. 1. Select **Approvals** on the left navigation bar. 1. Click the **New task** button. 1. Fill out the necessary fields: ![add_approval_task.png](/img/_paligo/uuid-97e3fccd-f3f6-fdc8-5f55-75f85a525e95.png) - **Title**: Identifies the task. This is required. - **Description**: A short summary of the task. This is optional. - **Assign to**: Select a team member to assign the task to. Only that team member will be able to approve the task. This is optional. Leave it on **(not assigned)** if you want anyone on the team to be able to approve the task. - **Due date**: Select a due date for the task's approval. This is optional. You can create as many tasks as you want. After finishing a task in the approvals stage, you can tick it off using the checkbox next to the task. When all tasks have been ticked off, **Approvals** will be ticked off as well on the left navigation bar. When done, you can proceed to: - [The App Store Review stage](/release-management/releases/managing-the-release-process/sending-your-app-to-app-store-review) for iOS apps. - [Releasing your app on Google Play](/release-management/releases/managing-the-release-process/releasing-your-app-on-google-play) for Android apps. ### Assigning an approval task to a team member with the REST API You can assign an approval task to a team member with the help of our [Release Management API](/release-management/release-management-api). For more information on our API endpoint, check out our [API docs](https://api-docs.bitrise.io/). :::note[Limited access] Note that you need a Personal Access Token or a Workspace token to [authenticate your API calls](/bitrise-ci/api/authenticating-with-the-bitrise-api). Only a [Workspace owner, a Project Admin and a Release Manager](/release-management/configuring-connected-apps/release-management-roles-and-permissions) has the right to assign approval tasks to team members. ::: You can create an approval task with the `POST /releases/{release_id}/approvals` endpoint by providing the user slug, due date, summary and a description. You can update an approval task with the `PATCH /releases/{release_id}/approvals/{task_id}`endpoint. --- ## Google Play upload stage After selecting a release candidate and creating tasks for approvals, the release process of an Android app reaches the stage where it must access Google Play: 1. [Google Play upload](/release-management/releases/managing-the-release-process/google-play-upload-stage#uploading-the-release-candidate-to-google-play): Upload the release candidate to Google Play. 1. [Distribute for testing](#distributing-android-release-candidates-for-testing): You can distribute the release candidate to Google Play testing tracks. ### Uploading the release candidate to Google Play Once you [selected a release candidate](/release-management/releases/managing-the-release-process/selecting-a-release-candidate) in Bitrise Release Management, you can continue with uploading your app to Google Play. :::note[Automatic upload] If you set up [auto-upload](/release-management/releases/configuring-a-release/configuring-auto-upload) during the release configuration or as a [release preset](/release-management/releases/release-presets), this stage will be completed automatically. ::: To upload the [selected release candidate](/release-management/releases/managing-the-release-process/selecting-a-release-candidate) to Google Play manually: 1. Open your release. 1. Select **Google Play** on the left navigation bar. 1. If you selected a valid release candidate, you should see **Ready to upload** under **Google Play**. Click **Upload version**. ![google-play-ready-to-upload.png](/img/_paligo/uuid-76fec79f-6b16-d420-3d74-53967ecf4d31.png) 1. Wait for the upload to finish. ### Distributing Android release candidates for testing After [uploading a release candidate to Google Play](/release-management/releases/managing-the-release-process/google-play-upload-stage#uploading-the-release-candidate-to-google-play), you can distribute it to Google Play testing tracks: 1. Open your release and go to the **Beta testing in Google Play** section. ![beta-testing-google-play.png](/img/_paligo/uuid-0022d0d2-8794-bad9-bf5d-a7413b7bb473.png) 1. Choose a testing track. Release Management supports open, internal, and closed testing. For more information about Google Play testing, check out the [Google Play Console documentation](https://support.google.com/googleplay/android-developer/answer/9845334). :::important[Newer builds] If there is a newer build (a build with a higher `version_code` number) on the testing track, you can’t replace that build with your release candidate and the **Start** button will not be available. If there is an older build on the testing track, your release candidate will replace it. ![testing-google-play-cant-replace.png](/img/_paligo/uuid-66a9dd86-282a-8695-d1c9-aa89bb61ef49.png) ::: 1. Click the **Start** button next to the name of your track to start the distribution. If all goes well, the **Status** of the build should change to **Testing**. --- ## Releasing your app on Google Play After your app has gone through all previous stages, it is ready for release. You can release your app to all users at the same time, or configure staged rollout for Google Play. ### Configuring staged rollout for Google Play You can release your app to Google Play in staged rollouts. With staged rollout, you release your apps in several different stages, with only a certain percentage of users getting the new version with each stage. Users aren't notified that they are in a staged release. Automating the process means you don't have to manually release the app at each stage to a different segment of users: Release Management takes care of that automatically. #### Enabling staged rollout for Google Play If you choose this option, your version update will be released over a seven-day period to a percentage of your users. Users aren’t notified that they're in a staged release of your app. :::note[Failed rollout] If the rollout stage fails for any reason, we’ll try it again later, until it succeeds, or you cancel or pause the automation.We try the failed rollout three times in an hour until it succeeds. After the rollout succeeds the rollout time for the stage will show the real rollout time, and not the planned time. ::: 1. On the **Release** stage, click Manage release. ![manage-release-button.png](/img/_paligo/uuid-bff97bcb-df0b-c062-3f8b-e446d171d6e9.png) 1. Select the **Automatically change rollout percentage over a 7-day period** option. 1. Select the rollout start time and date. The rollout must start at least ten minutes after the current time. 1. Click **Save changes**. #### Clearing the automated staged rollout schedule You can clear the schedule before the first stage of the scheduled rollout is completed. If the first stage fails, you can still clear the rollout schedule, but after it is completed you can only [pause the automation](#clearing-the-automated-staged-rollout-schedule), or [cancel it](#cancelling-an-automated-staged-rollout). ![release-scheduled.png](/img/_paligo/uuid-7b4d08a4-23ee-c089-5e7a-a8f2ea99abda.png) 1. Open your release. 1. Go to the **Release** stage. 1. Find the **Release summary** section. 1. Click the **Clear schedule** button. #### Cancelling an automated staged rollout You can cancel the automated rollout at any time after the first stage of the rollout is completed. However, once the automation is cancelled, you can't resume it and you can only update it manually in Release Management. 1. Open your release. 1. Go to the **Release** stage. 1. Find the **Release summary** section. 1. Click the **Cancel automation** button. ![phased-rollout-cancel.png](/img/_paligo/uuid-29b1db0e-2fa8-8f7e-ba48-da85ed4db64b.png) #### Pausing automated staged rollout You can pause and resume the automated rollout at any time after the first stage of the rollout is completed. There’s no limit to the number of pauses or the duration of the pause. 1. Open your release. 1. Go to the **Release** stage. 1. Go to **Staged rollout**. 1. Click **Pause automation**. ![phased-rollout.png](/img/_paligo/uuid-fd923003-5828-07e5-376b-b1d9e05c9652.png) #### Resuming automated staged rollout You can pause and resume the automated rollout at any time after the first stage of the rollout is completed. There’s no limit to the number of pauses or the duration of the pause. 1. Open your release. 1. Go to the **Release** stage. 1. Find the **Release summary** section. 1. Click the **Resume automation** button. ![resume-rollout.png](/img/_paligo/uuid-2da28206-9def-429e-3b2f-d3d769b15c3b.png) 1. Select the resume time and date. :::important[Minimum time] The time and date must be at least ten minutes after the current time. ::: ### Releasing your app Once everything is configured, you can release your app. Depending on your settings, you can either release the app to all your users at the same time, or do a staged rollout. 1. Open your release. 1. Select **Release** on the left navigation bar. 1. Click **Release app**. It either releases your app to all users or starts a staged rollout, depending on your settings. ### Editing the release note of an Android app If you wish to release an app with a different release note than [what's already set in Release presets](/release-management/releases/configuring-a-release/release-automation), you can manually edit the note before rolling out a new app version. This change will not override the default configuration of the **Release presets**, it only affects the current release. :::note[Release Managers only] Please note that only [Release Managers](https://devcenter.bitrise.io/en/release-management/getting-started-with-release-management/release-management-concepts.html) can edit release notes. ::: To modify the release note of an Android app during the release process: 1. Go through the **Release candidate**, **Google Play**, and **Approvals** stages, then click **Release** on the left. 1. Scroll down to **Release note** and click **Edit**. You can see the default release note content in the text box. 1. Make your changes to the text. This new content will apply for the localization under **Language**. 1. You can copy the new content to additional localizations by clicking **Copy to** and selecting other localizations. --- ## Releasing your app on the App Store After your app has gone through all previous stages, it is ready for release. You can release your app to all users at the same time, or configure phased release for the Apple Store. ### Configuring phased releases for the Apple Store You can release your app to the Apple Store in phases. With a phased release, you release your apps in several different stages, with only a certain percentage of users getting the new version with each stage. Users aren't notified that they are in a staged release. Automating the process means you don't have to manually release the app at each stage to a different segment of users: Release Management takes care of that automatically. :::note[Terminology] Google calls this feature a staged rollout while Apple calls it a phased release. ::: #### Enabling phased releases for the Apple Store If you choose this option, your version update will be released over a seven-day period to a percentage of your users (selected at random by their Apple ID) who has automatic updates turned on. Users aren’t notified that they're in a phased release of your app. You can enable phased release before the App Store review stage or during the release stage after a successful App Store review. **Before App Store review** 1. On the **App Store review** stage, find **App Store release settings**. 1. On the right of the **Phased release for automatic updates** card, click **Change**. 1. Select the **Release update over 7-day period using phased release** option. ![phased-release-7-day.png](/img/_paligo/uuid-05ba3ed0-0f1c-c4be-e46f-cc500b21041c.png) 1. Click **Save changes**. **After App Store review** 1. On the **App Store review** stage or the **Release** stage, find the **Version release** card and click **Change**. 1. In the dialog, choose one of three options: - **Manually release this version** - **Automatically release this version** - **Automatically release this version after App Review, no earlier than** and set a date. ![release-version.png](/img/_paligo/uuid-4f7e400b-3a64-eb42-5b85-c51a3f41da03.png) 1. On the **Release** stage, find the **Phased release for automatic updates** card, and click **Change**. 1. Select the **Release update over 7-day period using phased release** option. #### Pausing a phased release While your app is in phased release, you can choose to pause the release for a total of 30 days. There’s no limit to the number of pauses. 1. On the **Release** stage, click the **Pause** button. 1. To continue the phased release, click the **Continue** button. ### Releasing your app Once everything is configured, you can release your app. Depending on your settings, you can either release the app to all your users at the same time, or do a staged rollout. 1. Open your release. 1. Select **Release** on the left navigation bar. 1. Click **Release version**. It either releases your app to all users or starts a phased release, depending on your settings. You can change the settings in the **App Store release settings** section. ![app-store-release.png](/img/_paligo/uuid-fafa8157-e6f0-6495-1da6-7112515830d8.png) :::note[Changing the date of an automatic release] For iOS apps, you can change the date on the **Release** page if you selected **Automatically release this version after App Review, no earlier than** in the App Store review stage. ::: --- ## Selecting a release candidate In the release candidate stage you select an installable artifact that will be used during the release process. You have two possible sources of installable artifacts: - A Bitrise CI build. If you use this source, you select a branch and a Workflow and then select an artifact generated by a build using those. By default, the artifact of the latest build is used but you can change this. - [Upload an installable artifact via API](/bitrise-ci/api/managing-build-artifacts). This is particularly useful if you use a different CI service instead of Bitrise. :::important[Signed artifacts only] The installable artifact must be a SIGNED artifact (IPA or AAB). Check out our code signing guides: - [iOS code signing](/bitrise-ci/code-signing/ios-code-signing/creating-a-signed-ipa-for-xcode-projects) - [Android code signing](/bitrise-ci/code-signing/android-code-signing/android-code-signing-using-the-android-sign-step) ::: To select a release candidate: 1. Open your release. 1. Select **Release candidate** on the left navigation bar. 1. Configure the source of the build artifact: click **Configure**. This will open up the **Build artifact source** dialog. ![build-artifact-source.png](/img/_paligo/uuid-ca5383f8-2b6e-a07a-1876-35ad58894b5f.png) 1. Select from one of two options: - **Use Bitrise CI builds**: Select a branch and a Workflow to use artifacts generated by a Bitrise CI build. - **Upload via API**: To be able to select an artifact from this source, [upload one using the API](/bitrise-ci/api/managing-build-artifacts). 1. Check the **Automatically select latest successful build** checkbox (labeled **Automatically select after successful upload** if you're using the API source) to use either the latest generated artifact or the latest file uploaded via the API. Either way, the artifact must be a signed artifact. 1. Click **Save changes**. 1. If you didn't check automatic selection, go to the **Build artifact** section and click **Select artifact**. You will only be able to select from signed artifacts. ![select-artifact.png](/img/_paligo/uuid-9502548e-c9ec-985e-7224-7e06aa0dfbda.png) 1. Select a build artifact in the dialog and click **Select artifact**. Once you selected a release candidate, you will see the details of the artifact that will be used under **Build artifact**: ![locked-artifact.png](/img/_paligo/uuid-4d8bea06-abe3-0ad5-9a37-d840ad2c0875.png) You can proceed to: - [The TestFlight upload stage](/release-management/releases/managing-the-release-process/testflight-upload-stage) for iOS apps. - [The Google Play upload stage](/release-management/releases/managing-the-release-process/google-play-upload-stage#uploading-the-release-candidate-to-google-play) for Android apps. --- ## Sending your app to App Store review :::important[Role requirement] To send your app to App Store review, you need to have the Release Manager role for your connected app. ::: After you’ve uploaded your release candidate to TestFlight and the build processing is finished, you can submit it for App Store review, where Apple will review your release: 1. Open your release. 1. Select **App Store review** on the left navigation bar. 1. Review the **App Store release settings** section. ![app-store-review.png](/img/_paligo/uuid-0356f699-7e6f-0169-7fb3-82576e470b62.png) 1. Configure phased release by clicking **Change** on **Phased release for automatic updates**. If you opt for a phased release, at first, only some of your users will have access to the contents of your release. Gradually, over a 7-day period, all of your users will get access. 1. Configure version release by clicking **Change** on **Version release**. You can: - Release the app manually. - Release the app automatically: the app will be released as soon as Apple finishes the review. - Release the app automatically after App Store review but no earlier than a specified date. 1. Review the metadata at the **App Store metadata** section. 1. When done, click **Submit version** on the top right part of the page. :::tip[Canceling App Store review] If you want to modify the release while it's under App Store review, you first need to remove it from review. Click **Remove from review** on the **To modify this release, remove it from review first** note, then confirm in the dialog. ::: You can monitor the release status on the **Release** page. You can proceed to [Releasing your app on the App Store](/release-management/releases/managing-the-release-process/releasing-your-app-on-the-app-store) for manual releases. ### Editing the release note of an iOS app If you wish to release an app with a different release note than what's [already set in release presets](/release-management/releases/configuring-a-release/release-automation), you can manually edit the note before rolling out a new app version. This change will not override the default configuration of the **Release presets**, it only affects the current release. :::note[Release Managers only] Please note that only [Release Managers](https://devcenter.bitrise.io/en/release-management/getting-started-with-release-management/release-management-concepts.html) can edit release notes. ::: To modify the release note of an iOS app during the release process: 1. Go through the **Release candidate**, **TestFlight**, and **Approvals** stages, then click **App store review** on the left. 1. Scroll down to **App Store Metadata**. 1. Click **What's new in this version**, then **Edit metadata**. Here you can change the release note. It will only apply to the selected localization shown under **Language**. 1. Optionally, you can copy the new content to all localizations by ticking **Use same content for all localizations**. 1. You can copy the new content to additional localizations by clicking **Copy to** and selecting the localizations of your choice. --- ## Stop managing a release If you have started a release on Bitrise but decided to abandon it or complete it externally, you can stop managing that in-progress release regardless of the stage you are at on Bitrise. When stopped, the release becomes read-only and cannot be restarted. :::note[Feature access] Only [Release Managers](/release-management/configuring-connected-apps/release-management-roles-and-permissions), [Project Admins](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci), and [workspace owners](/bitrise-platform/projects/roles-and-permissions-for-bitrise-ci#owners) have access to this feature. ::: To stop managing a release: 1. Open your app in Release Management and select **Releases**. 1. Select a release from the list and click the arrow next to its name. 1. Select **Configuration** on the left. 1. Scroll down and click **Stop managing release**. This brings up a dialog. ![2025-08-08-rm-stop-managing-release.png](/img/_paligo/uuid-187924e0-afdb-8c78-53fe-809168944982.png) 1. In the **Update status and stop managing release** dialog, choose a new **Release status**: - **Completed (App Store)** / **Completed (Google Play)**: The release will be completed outside of Bitrise, on App Store Connect or Google Play Console respectively. - **Abandoned**: The release is stopped on this stage and will not be completed. In both cases, the release turns to a read-only status on Bitrise. 1. Click **Confirm status change**. After you confirm the changes, you can see a breakdown of all completed and not completed release stages. If you go back to the **Releases** page, you will see the stopped release with the status **Abandoned** or **Completed (App Store)** / **Completed (Google Play)**, matching the status you set before. --- ## TestFlight upload stage After selecting a release candidate, the release process of the iOS app reaches the stages where it must access the App Store: 1. [TestFlight](/release-management/releases/managing-the-release-process/testflight-upload-stage#uploading-the-release-candidate-to-testflight): Upload the release candidate to TestFlight. 1. [Distribute for testing](/release-management/build-distribution/distributing-builds-to-testers): Distribute the release candidate to TestFlight testing groups. ### Uploading the release candidate to TestFlight Once you [selected a release candidate](/release-management/releases/managing-the-release-process/selecting-a-release-candidate) in Bitrise Release Management, you can continue with uploading your app to Testflight. 1. Open your release. 1. Select **TestFlight** on the left navigation bar. 1. If you selected a valid release candidate, you should see **Ready to upload** under TestFlight. Click **Upload version** to start the upload. You can see the exact build artifact that will be uploaded. ![testflight-upload.png](/img/_paligo/uuid-1cc790d0-1d08-d98c-7fdf-2cafa999984d.png) 1. Wait for the upload to finish. You can create additional tasks at the **Approvals** stage. ### Distributing iOS release candidates for testing After [uploading a release candidate to TestFlight,](/release-management/releases/managing-the-release-process/testflight-upload-stage#uploading-the-release-candidate-to-testflight) you can distribute it to TestFlight testing groups: 1. Open your release and go to the **Beta testing in TestFlight** section. 1. Optionally, you can fill out the **What to test** section for your testers. To do so, click the **Edit** button. The information will be visible on TestFlight and in the TestFlight apps. You can also localize the information: choose a language from the menu on the right to provide information for that localization. ![beta-testing-testflight.png](/img/_paligo/uuid-0247679e-247c-dd61-77eb-340600f634c9.png) 1. Choose testing groups, either in the **Internal testing** or the **External testing** section. - Internal testing groups with automatic distribution enabled will automatically have access to the release candidate. You can enable automatic distribution when creating the group in App Store Connect. If automatic distribution is not enabled, toggle **Distribution** for the group on to make the release candidate available. - For external testing groups, you must submit the release candidate for beta review: click **Submit to review**, and in the dialog, click **Save**. External testing groups will not have access to the release candidate automatically: after the beta review submission, toggle **Distribution** for the group on to make the release candidate available. Optionally, you can check **Automatically notify testers** in the dialog: this option means external testers get an email when a new build is ready for testing. ![testflight-testing-int-ext.png](/img/_paligo/uuid-ee309b75-e71d-aaea-5b0f-2477d3c77231.png) --- ## Release presets Release presets are default values and configurations for new releases of [a connected app](/release-management/getting-started-with-release-management/connecting-an-app). To set a preset for a release, you need a preset template. A preset template is a combination of various preset options. You can apply a template to a release when [adding a new release](/release-management/releases/adding-a-new-release). You can configure presets for: - [The initial release configuration](#release-preset-options). - [The release candidate stage](/release-management/releases/managing-the-release-process/selecting-a-release-candidate). ### Creating a preset template 1. 1. Log in to Bitrise, and from the left sidebar, select **Releases**. 1. Select your app from the list. 1. On the left, select **Release presets**. ![20251216-rm-presets.png](/img/_paligo/uuid-bf243542-7a52-3b3e-e6d5-26d0248c3951.png) 1. Click **+ New template**. 1. Add a name and click **Create**. 1. Click the options menu (⋮) next to the name of your template and select **Change**. 1. Select and configure the available [release preset options](#release-preset-options): - In the **Configuration** section, configure preset options for the initial release configuration. - In the **Release candidate** section, create a build configuration for the release candidate stage. - **Release rollout/App Store release settings** allow you to configure phased release for Android and iOS apps, respectively. By default, updates are released immediately to all users. - **Release notes/App Store metadata** allow you to add release notes to your release. ### Release preset options - **Auto-upload**: Enable or disable automatic upload with the toggle switch. Read more: [Configuring auto-upload](/release-management/releases/configuring-a-release/configuring-auto-upload). - **Approvals**: Create default approval tasks for new releases. Read more: [Creating tasks for the approvals stage](/release-management/releases/managing-the-release-process/creating-tasks-for-the-approvals-stage). - **Notifications**: Enable Slack and Teams notifications for all new releases with the same settings. Read more: [Configuring Slack and Teams notifications](/release-management/releases/configuring-a-release/configuring-slack-and-teams-notifications). - **Automation**: Configure default automation events with their triggered Workflow or Pipeline. Read more: [Release automation](/release-management/releases/configuring-a-release/release-automation). - **Outgoing webhooks**: Select release events that should send a JSON payload to a service of your choice. Read more: [Outgoing webhooks in Release Management](/release-management/releases/configuring-a-release/outgoing-webhooks-in-release-management). Preset options for the release candidate stage: - **Build configuration**: You can select the release branch for the app and the Workflow that generates the build with a signed IPA or AAB file. Preset options for the review and release stage: - **Release note**: You can create a release note preset for Android apps. - **App Store metadata**: You can create a release note preset for iOS apps. For details, read [Release note preset](#release-note-preset). ### Release note preset You can create a release note preset. This means every release will be submitted to the App Store or Google Play with the same release notes. A release note preset can be identical in all localizations. :::note[Manual edit] You can edit a release note in the release stage, before submitting your app to an online store. A manual edit will override the release note preset. ::: #### Editing a release note preset To create and save a release note preset: **iOS** 1. Open your app in Release Management. 1. On the left, select **Release presets**. ![20251216-rm-presets.png](/img/_paligo/uuid-bf243542-7a52-3b3e-e6d5-26d0248c3951.png) 1. Click the options menu (⋮) next to the name of your preset template and select **Change**. 1. Find **App Store metadata**. 1. From the dropdown menu, select a localization. ![2025-08-07-app-store-metadata.png](/img/_paligo/uuid-e5531ad0-351f-de58-e68e-320c039ab434.png) 1. Click **What's new in this version** and then **Edit metadata**. 1. Add your release note in the **What's in your release** field. 1. Click **Save changes**. **Android** 1. Open your app in Release Management. 1. On the left, select **Release presets**. ![20251216-rm-presets.png](/img/_paligo/uuid-bf243542-7a52-3b3e-e6d5-26d0248c3951.png) 1. Click the options menu (⋮) next to the name of your template and select **Change**. 1. Find **Release notes**. 1. From the dropdown menu, select a localization. ![release-notes-menu.png](/img/_paligo/uuid-04f62e3f-a98e-7b0f-4b1f-7d592e42db65.png) 1. Click **Edit**. This opens the **Edit release notes** dialog. 1. Add your release note in the **What's in your release** field. Optionally, you can check **Use same content for all localizations** to include the same text for all languages. ![release-note-preset.png](/img/_paligo/uuid-588d950a-8b3c-1984-18f6-d251651222a2.png) 1. Click **Save changes**. #### Copying a release note preset to other localizations If you don't want to automatically use the same preset for all localizations, you can copy your preset to specific localizations. **iOS** 1. Open your app in Release Management. 1. On the left, select **Release presets**. ![20251216-rm-presets.png](/img/_paligo/uuid-bf243542-7a52-3b3e-e6d5-26d0248c3951.png) 1. Click the options menu (⋮) next to the name of your template and select **Change**. 1. Find **App Store metadata**. 1. Click into **What's new in this verseion**, and then click **Copy to**. This opens the **Copy metadata dialog**. ![copy-metadat.png](/img/_paligo/uuid-55c4990e-7f00-98a4-fa17-c3a9d0e3ba76.png) 1. Open the **Copy to** dropdown menu, and select all localizations you want to copy to. 1. Click **Copy**. **Android** 1. Open your app in Release Management. 1. On the left, select **Release presets**. ![20251216-rm-presets.png](/img/_paligo/uuid-bf243542-7a52-3b3e-e6d5-26d0248c3951.png) 1. Click the options menu (⋮) next to the name of your template and select **Change**. 1. Find **Release notes**. 1. Click **Copy to**. This opens the **Copy release notes** dialog. ![copy-metadat.png](/img/_paligo/uuid-55c4990e-7f00-98a4-fa17-c3a9d0e3ba76.png) 1. Open the **Copy to** dropdown menu, and select all localizations you want to copy to. 1. Click **Copy**.