---
title: "Apps with flavors"
description: "Release and patch each flavor of a Flutter app on Android, iOS and macOS, by hand or from CI"
---

If your app has flavors (Android product flavors, or Xcode schemes on iOS and macOS), each flavor gets its own Shorebird app, with its own releases and patches. You pass `--flavor` to every `shorebird release` and `shorebird patch`, plus `--target` when the flavor has its own entry point.

Flavors work on Android, iOS and macOS. On Windows and Linux, `shorebird release` and `shorebird patch` don’t take `--flavor`: passing it stops with `Flavors are not supported on this platform.`, and without it they use `app_id`.

This page uses two flavors, `development` and `production`. To test a patch before your users get it, you don’t need a separate flavor: publish it to a [staging track](/code-push/guides/staging-patches/) and promote it once it works. If you use a flavor per customer brand, see [White Labeling](/code-push/guides/white-labeling/).

## Set up the flavors

### Android

Add the flavors to `android/app/build.gradle.kts` (or `build.gradle`):

* Kotlin DSL

  android/app/build.gradle.kts

  ```
  android {
      // ...
      flavorDimensions += "environment"
      productFlavors {
          create("development") {
              dimension = "environment"
              applicationIdSuffix = ".dev"
              manifestPlaceholders["applicationLabel"] = "[Dev] My App"
          }
          create("production") {
              dimension = "environment"
              manifestPlaceholders["applicationLabel"] = "My App"
          }
      }
  }
  ```

* Groovy DSL

  android/app/build.gradle

  ```
  android {
      // ...
      flavorDimensions "environment"
      productFlavors {
          development {
              dimension "environment"
              applicationIdSuffix ".dev"
              manifestPlaceholders = [applicationLabel: "[Dev] My App"]
          }
          production {
              dimension "environment"
              manifestPlaceholders = [applicationLabel: "My App"]
          }
      }
  }
  ```

`applicationIdSuffix` gives each flavor its own package name, so both can be installed side by side. Leave it out if a service you use, such as Firebase, expects one package name. To show each flavor’s label, set `android:label="${applicationLabel}"` on the `<application>` element in `android/app/src/main/AndroidManifest.xml`. Flutter’s [Android flavors guide](https://docs.flutter.dev/deployment/flavors) covers the rest.

### iOS and macOS

Create an Xcode scheme for each flavor, with build configurations for it, as Flutter’s [iOS and macOS flavors guide](https://docs.flutter.dev/deployment/flavors-ios) describes. Each flavor needs an Xcode scheme of the same name. Shorebird 1.6.135 and newer check this before building, and stop with an error like this one if a scheme is missing:

```
The iOS project has no Xcode scheme for flavor "development", so it cannot be built with --flavor=development. Add a scheme named "development" (see https://docs.shorebird.dev/code-push/guides/flavors/ios/), or pass one of: production.
```

Use the same flavor names on every platform. Shorebird keeps one list of flavors for the project, so a flavor named `production` on Android and iOS is one Shorebird app with an Android and an iOS release, while `prod` on Android and `production` on iOS would be two apps.

## Add Shorebird to the flavors

Run `shorebird init` in your project:

```
shorebird init
```

It detects your flavors, creates a Shorebird app for each one, and lists them under `flavors:` in `shorebird.yaml`. What `app_id` holds depends on the project:

* In a new project where Android and iOS both have flavors, `app_id` is the first flavor’s app.
* In a new project where Android or iOS has no flavors, `app_id` is a separate app for builds without a flavor.
* In a project that already has a `shorebird.yaml`, `shorebird init` adds an app for each flavor that isn’t listed yet and keeps your existing `app_id`.

For an existing project, `shorebird.yaml` then looks something like:

```
app_id: 6d4f1a2b-9c3e-4b7a-8f21-3e5d7c9a0b14
flavors:
  development: ee322dc4-3dc2-4324-90a9-04c40a62ae76
  production: 904bd3d5-3526-4c1c-a832-7ac23c95302d
```

A build with `--flavor` checks for patches with that flavor’s app ID. A build without `--flavor` uses `app_id`, and `shorebird release` and `shorebird patch` warn about it:

```
The project has flavors development, production, but no --flavor argument was provided.
The default app id 6d4f1a2b-9c3e-4b7a-8f21-3e5d7c9a0b14 will be used. Pass --flavor=<name> to target a flavor.
```

To add a flavor later, set it up as above and run `shorebird init` again. It prints `New flavors detected:` with the new flavor’s name and adds it to `shorebird.yaml`. It rewrites the file and [drops your other settings](/code-push/initialize/), so check the diff before you commit.

Caution

Don’t run `shorebird init --force` on a project you’ve already released. `--force` creates new apps and rewrites `app_id`, so releases and patches you make afterwards go to apps your shipped builds don’t check for patches.

## Release each flavor

Release each flavor you ship, with its `--flavor`. If the flavor has its own entry point, pass it with `--target`; without it, Flutter builds `lib/main.dart`.

```
shorebird release android --flavor production --target lib/main_production.dart
shorebird release ios --flavor production --target lib/main_production.dart
```

Upload each flavor’s build to that flavor’s store listing. On Android, the app bundle is at `build/app/outputs/bundle/productionRelease/app-production-release.aab`; on iOS, the IPA is in `build/ios/ipa`.

To try a release on a device, pass the flavor to `shorebird preview`:

```
shorebird preview --flavor development --release-version 1.0.0+1
```

## Patch a flavor

Build the patch with the same `--flavor`, `--target`, `--dart-define` and `--dart-define-from-file` values as the release it patches:

```
shorebird patch android --flavor production --target lib/main_production.dart \
  --release-version 1.0.0+1 --track=stable
```

`--flavor` picks which Shorebird app gets the patch. `--target` and the Dart defines are compiled into your Dart code, so a patch built without them runs a different entry point or configuration from the release.

Each flavor is its own app, so a fix that every flavor needs is a patch for each flavor, built from the same code. To check a patch before users get it, publish it to a staging track and promote it; see [Staging patches](/code-push/guides/staging-patches/).

## Flavors in CI

In CI, run the release or patch once per flavor. A shell loop works on any CI system that has `SHOREBIRD_TOKEN` set (see the [CI guides](/code-push/ci/generic/)):

```
#!/usr/bin/env bash
set -euo pipefail
for flavor in development production; do
  shorebird patch android --flavor "$flavor" --target "lib/main_$flavor.dart" \
    --release-version=latest --track=stable
done
```

`--release-version=latest` patches each flavor’s most recently updated release. If a newer release might still be in store review, pass the version your users have instead; see [Patching](/code-push/patch/).

In GitHub Actions, a matrix runs a job per flavor, and the action’s `args` input passes the flavor and target:

```
jobs:
  patch:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        flavor: [development, production]
    env:
      SHOREBIRD_TOKEN: ${{ secrets.SHOREBIRD_TOKEN }}
    steps:
      - uses: actions/checkout@v7
      - uses: shorebirdtech/setup-shorebird@v1
        with:
          cache: true
      - uses: actions/setup-java@v6
        with:
          distribution: 'temurin'
          java-version: '17'
      - uses: shorebirdtech/shorebird-patch@v1
        with:
          platform: android
          release-version: latest
          track: stable
          args:
            --flavor ${{ matrix.flavor }} --target lib/main_${{ matrix.flavor
            }}.dart
```

See [GitHub Integration](/code-push/ci/github/#pass-more-arguments-flavors-and-monorepos) for the action’s inputs.

## Examples

* The [flavors](https://github.com/shorebirdtech/samples/tree/main/flavors) sample is an app with two flavors on Android, iOS and macOS.
* The [multi\_dimensional\_flavors](https://github.com/shorebirdtech/samples/tree/main/multi_dimensional_flavors) sample uses more than one flavor dimension.
