-
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.
What Are Flavors?
-
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).
Step-by-Step Setup
1. Define Your App Flavors in Flutter Code
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
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
Steps:
-
Runner-dev
-
Runner-staging
- Runner-prod
4. Run with Flavors
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
Bonus: Firebase Config per Flavor
-
android/app/src/dev/google-services.json
-
android/app/src/prod/google-services.json
- ios/Runner/GoogleService-Info-dev.plist
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
-
You will reduce mistakes during deployment.
-
You will make environmental testing easier.
- You will speed up releases because configs are already isolated.
Let's collaborate with us
-
Production-ready
-
Secure
- Optimized across environments
Mohit Kokane
A highly skilled Flutter Developer. Committed to delivering efficient, high-quality solutions by simplifying complex projects with technical expertise and innovative thinking.
Reply