← Flutter Reference

What are Build Flavors in Flutter?

Build & Release · Intermediate

By Abdelrahman Saed — Senior Mobile Engineer. Last updated: 2026-08-10.

Build flavors in Flutter allow you to create multiple variants of your app from a single codebase, each with its own bundle identifier, app name, icons, and configuration. Flavors let you run development, staging, and production environments side by side on the same device without conflicts.

How it works

Flavors work by defining per-variant build configurations in both the native iOS (Xcode schemes) and Android (Gradle product flavors) layers, then selecting the right configuration from Dart.

Android (in android/app/build.gradle):

flavorDimensions "default"
productFlavors {
  dev {
    applicationIdSuffix ".dev"
    versionNameSuffix "-dev"
  }
  staging {
    applicationIdSuffix ".staging"
  }
  production {}
}

iOS (Xcode schemes per flavor, with matching build configurations).

Dart entry points — one per flavor:

// lib/main_dev.dart
void main() {
  runApp(MyApp(config: DevConfig()));
}

// lib/main_production.dart
void main() {
  runApp(MyApp(config: ProductionConfig()));
}

Run with flutter run --flavor dev -t lib/main_dev.dart.

At iStoria, three flavors (dev, staging, production) let engineers test on real devices with the dev variant while QA tests the staging variant against the staging backend — all without uninstalling the production app.

When to use it

Use build flavors when:

  • You have multiple environments (dev, staging, production) with different backends or configuration.
  • You need to run multiple variants on the same device simultaneously.
  • You want different app names, icons, or bundle IDs per environment.

Skip flavors when:

  • You only have one environment — a single build configuration is simpler.
  • Your team is small and environment switching is done via environment variables or dart-define.

Strengths

  • Multiple environments from one codebase — no code duplication
  • Side-by-side installation — dev and production apps coexist on one device
  • Per-flavor configuration — different bundle IDs, icons, app names, and backends
  • Enables safe testing — QA can test against staging without affecting production

Tradeoffs

  • Setup complexity — native configuration on both iOS and Android is non-trivial
  • CI/CD must build each flavor separately — three builds instead of one
  • Xcode scheme management is manual and error-prone
  • Every new developer needs to understand the flavor system before their first build

Comparisons

Related articles

Related case studies

FAQ

What is the difference between build flavors and dart-define?

Build flavors change the native build configuration (bundle ID, app name, icons). dart-define passes compile-time values to Dart code without changing the native build. Use flavors when you need different bundle IDs or native configuration; use dart-define when you only need to swap Dart-level values like API URLs.

How many flavors should I have?

Three is standard: development (for local coding), staging (for QA against a staging backend), and production (the app store build). Some teams add a fourth (beta) for TestFlight distribution, but that usually overlaps with staging.


Available for hire. Abdelrahman Saed is a Senior Mobile Engineer (Flutter) — open to full-time, fractional, contract, or advisory work. Hire me →

Book a 20-minute call · Download the CV (PDF) · See how I work