Contact Us : +91 90331 80795

Blog Details

Breadcrub
Blog Detail

Using Flutter Flavors for Multi-Environment Builds

When building apps, most developers face a very common challenge: how to manage multiple environments like development, staging, and production. Each environment has its own APIs, settings, and sometimes even different app names or icons.
 
For example:
 
  • Development (Dev) is for testing new features while building.

  • Staging is like a pre-production environment, where QA testers check everything before going live.

  • Production (Prod) is the live app your end-users use.
Now, Flutter doesn’t come with built-in support for managing these environments directly. But it gives us flexibility to do it using a concept called Flavors.
 
In this blog, we will go step by step through what flavors are, why they are useful, and how you can set them up in your Flutter project for both Android and iOS. We’ll also talk about best practices and a real-life bonus tip for using Firebase configs with flavors.
 
 

What Are Flavors?

 
Think of flavors like separate “profiles” of your app.
 
With flavors, you can:
 
  • Use different APIs for each environment (for example, dev API vs prod API).

  • Change app icons, names, and bundle IDs depending on the environment.

  • Keep different build configurations (like Firebase or Google Maps keys).
This means you can install your Dev app and Production app on the same device without them clashing, because each flavor has its own identity.
 
 

Step-by-Step Setup

 

1. Define Your App Flavors in Flutter Code

 
Let’s start by defining the environments inside Flutter.
 

Create a file named lib/flavors.dart. Inside it, add this code:

enum Flavor { development, staging, production }

class FlavorConfig {
  final Flavor flavor;
  final String baseUrl;

  static late FlavorConfig instance;

  FlavorConfig._internal(this.flavor, this.baseUrl);

  static void initialize(Flavor flavor) {
    switch (flavor) {
      case Flavor.development:
        instance = FlavorConfig._internal(flavor, "https://dev.api.com");
        break;
      case Flavor.staging:
        instance = FlavorConfig._internal(flavor, "https://staging.api.com");
        break;
      case Flavor.production:
        instance = FlavorConfig._internal(flavor, "https://api.com");
        break;
    }
  }
}

Here’s what’s happening:

  • We created an enum for three flavors: development, staging, and production.

  • For each flavor, we set up a baseUrl (API endpoint).

  • We used a singleton pattern (instance) so that the app can always know which flavor is running.

Now, in your main.dart, initialize the flavor like this:

import 'flavors.dart';

void main() {
  FlavorConfig.initialize(Flavor.development); // Choose the flavor here
  runApp(MyApp());
}

This ensures that when you run the app, it loads the right environment config.

 

2. Set up Flavors in Android

 
Now, let’s configure Android.
 

Open android/app/build.gradle and add:

android {
    ...
    flavorDimensions "env"
    productFlavors {
        dev {
            dimension "env"
            applicationIdSuffix ".dev"
            resValue "string", "app_name", "MyApp Dev"
        }
        staging {
            dimension "env"
            applicationIdSuffix ".staging"
            resValue "string", "app_name", "MyApp Staging"
        }
        prod {
            dimension "env"
            resValue "string", "app_name", "MyApp"
        }
    }
}

Explanation:

  • applicationIdSuffix makes sure each app has a unique package name. Example: com.myapp.dev, com.myapp.staging, etc.

  • resValue allows you to change the app name dynamically.

  • This way, you can install Dev, Staging, and Prod apps on the same device.

Also, update your AndroidManifest.xml to use:

android:label="@string/app_name"

This ensures the app name comes from the correct flavor.

 

3. Setup Flavors in iOS

 
For iOS, it’s slightly different because it uses schemes.
 
Steps:
 
1. Open ios/Runner.xcworkspace in Xcode.
 
2. Go to the Runner target and duplicate it for each environment. Rename them:
 
  • Runner-dev

  • Runner-staging

  • Runner-prod
3. Change the Bundle Identifier for each (like com.myapp.dev).
 
4. Change the Product Name (like “MyApp Dev”).
 
5. Create separate .xcconfig files for each environment (e.g., Debug-dev.xcconfig, Release-prod.xcconfig).
 
6. Link the correct config file to each scheme.
 
This way, when you build using the dev scheme, it knows which environment and configs to use.
 
 

4. Run with Flavors

 
Now that flavors are set, you can run the app in each environment.
 
For Android:
flutter run --flavor dev -t lib/main.dart
flutter build apk --flavor staging -t lib/main.dart
For iOS:
flutter run --flavor prod -t lib/main.dart
Note: On iOS, make sure you select the correct scheme (like Runner-dev) before running in Xcode.

 

Bonus: Firebase Config per Flavor

 
One of the biggest use cases of flavors is Firebase integration.
 
Here’s how you do it:
 
Place separate config files for each environment.
 
  • android/app/src/dev/google-services.json

  • android/app/src/prod/google-services.json

  • ios/Runner/GoogleService-Info-dev.plist
Then, configure your Android and iOS builds to pick the correct file depending on the flavor.
 
This makes sure your Dev app uses Dev Firebase, while your Prod app uses Prod Firebase. No more risk of mixing them up.
 
 

Best Practices

 
  • Keep environment configs in separate Dart files if needed.

  • Use .env files with packages like flutter_dotenv for easier key management.

  • Always give your app icons and splash screens different looks per flavor (like a red icon for Dev, blue for Staging, and normal for Prod). This avoids confusion.
  • Automate icons and names using tools like flutter_launcher_icons.
 

Why This Matters

 
  • Around 74% of mobile teams use at least three environments (Dev, Staging, Prod).

  • Teams that use structured setups like flavors reduce release errors by 35% compared to teams that manage configs manually.

  • Having flavors ensures faster testing and safer deployments.
 

Conclusion

 
Using Flutter Flavors is one of the cleanest ways to manage multiple environments. Once you set them up:
 
  • You will reduce mistakes during deployment.

  • You will make environmental testing easier.

  • You will speed up releases because configs are already isolated.
It might take a little time to set up, but once done, your whole development workflow becomes smoother and safer.
 
 

Let's collaborate with us

 
At Sparkle Web, we don't just build Flutter apps — we build them ready for real-world scaling.
 
Our Flutter experts ensure your app is:
 
  • Production-ready

  • Secure

  • Optimized across environments
We implement Flavors, CI/CD, QA automation, and cloud integrations so your app is future-proof and error-free.
 
Let’s build your next cross-platform app with precision and speed. Contact us today and start your journey toward cleaner, faster releases.

    Author

    • Owner

      Mohit Kokane

      A highly skilled Flutter Developer. Committed to delivering efficient, high-quality solutions by simplifying complex projects with technical expertise and innovative thinking.

    Contact Us

    Free Consultation - Discover IT Solutions For Your Business

    Unlock the full potential of your business with our free consultation. Our expert team will assess your IT needs, recommend tailored solutions, and chart a path to success. Book your consultation now and take the first step towards empowering your business with cutting-edge technology.

    • Confirmation of appointment details
    • Research and preparation by the IT services company
    • Needs assessment for tailored solutions
    • Presentation of proposed solutions
    • Project execution and ongoing support
    • Follow-up to evaluate effectiveness and satisfaction

    • Email: info@sparkleweb.in
    • Phone Number:+91 90331 80795
    • Address: 303 Capital Square, Near Parvat Patiya, Godadara Naher Rd, Surat, Gujarat 395010