Flutter Flavors: How to Set Up Dev, Staging, and Production Environments the Right Way

Flutter Flavors: How to Set Up Dev, Staging, and Production Environments the Right Way

FlutterPulse

This article was translated specially for the channel FlutterPulseYou'll find lots of interesting things related to Flutter on this channel. Don't hesitate to subscribe!🚀

When building a professional Flutter app, you often need different environments — one for testing, one for QA, and one for users. For…

When building a professional Flutter app, you often need different environments — one for testing, one for QA, and one for users. For example:

  • Development (Dev): Used during active coding and debugging.
  • Staging: For internal testing and client review.
  • Production: The live version used by end-users.

Flutter supports this via Flavors, which let you easily manage separate configurations, API URLs, app names, and icons for each environment — all within one codebase.

Not a member ??

🏷️The Core Concept: What Are Flavors?

In Flutter, Flavors (or Product Flavors on Android, Schemes on iOS) are custom configurations that define an app variant. They allow you to:

  • Isolate Configurations: Keep API URLs, secret keys, and environment-specific settings separate.
  • Unique Identities: Give each environment a distinct App Name, Package Name/Bundle ID, and icon, allowing them to be installed simultaneously on the same device.
  • Safer Deployments: Prevent development or test code from accidentally making it into the Production build.

In this guide, you'll learn step-by-step how to set up and manage flavors in Flutter for Dev, Staging, and Production.

🔧 Step 1: Create the Project Structure

Let's start with a clean Flutter app.

flutter create flavor_app
cd flavor_app

Inside your Flutter project, create a folder to store your environment configuration files:

lib/
main_dev.dart
main_staging.dart
main_prod.dart

Each file will represent a different flavor entry point.

⚙️ Step 2: Configure main.dart for Each Flavor

Example setup for Dev flavor:

import 'package:flutter/material.dart';
import 'app.dart';

void main() {
const String env = 'DEV';
runApp(MyApp(environment: env));
}

For Staging:

import 'package:flutter/material.dart';
import 'app.dart';

void main() {
const String env = 'STAGING';
runApp(MyApp(environment: env));
}

For Production:

import 'package:flutter/material.dart';
import 'app.dart';

void main() {
const String env = 'PROD';
runApp(MyApp(environment: env));
}

Now, in your app.dart:

import 'package:flutter/material.dart';

class MyApp extends StatelessWidget {
final String environment;
const MyApp({required this.environment, super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Flavor App ($environment)',
home: Scaffold(
appBar: AppBar(title: Text('Environment: $environment')),
body: Center(
child: Text('Running in $environment mode'),
),
),
);
}
}

🧩 Step 3: Configure Android Flavors

Open android/app/build.gradle and find the android {} block.
Add the following productFlavors section:

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

This gives you separate app packages like:

  • com.example.flavor_app.dev
  • com.example.flavor_app.staging
  • com.example.flavor_app

🍎 Step 4: Configure iOS Flavors

Open your ios/Runner.xcodeproj in Xcode → Product → Scheme → Manage Schemes.
Duplicate the existing Runner scheme and rename them as:

  • Runner (Dev)
  • Runner (Staging)
  • Runner (Production)

Now, open your ios/Runner/Info.plist and add identifiers for each build configuration, for example:

<key>CFBundleDisplayName</key>
<string>FlavorApp Dev</string>

Do the same for Staging and Production.

💬 Step 5: Build Commands for Each Flavor

You can now build or run any environment like this:

🖥️ Run on Android

flutter run --flavor dev -t lib/main_dev.dart
flutter run --flavor staging -t lib/main_staging.dart
flutter run --flavor production -t lib/main_prod.dart

📦 Build APK

flutter build apk --flavor dev -t lib/main_dev.dart
flutter build apk --flavor staging -t lib/main_staging.dart
flutter build apk --flavor production -t lib/main_prod.dart

🍏 Build iOS

flutter build ios --flavor dev -t lib/main_dev.dart
flutter build ios --flavor staging -t lib/main_staging.dart
flutter build ios --flavor production -t lib/main_prod.dart

🌍 Step 6: Use Environment Variables (Optional)

You can define environment-specific constants, such as API URLs:

class AppConfig {
static const devBaseUrl = 'https://api-dev.example.com';
static const stagingBaseUrl = 'https://api-staging.example.com';
static const prodBaseUrl = 'https://api.example.com';
}

Then, in your MyAppYou can switch based on the environment:

String baseUrl;
switch (environment) {
case 'DEV':
baseUrl = AppConfig.devBaseUrl;
break;
case 'STAGING':
baseUrl = AppConfig.stagingBaseUrl;
break;
default:
baseUrl = AppConfig.prodBaseUrl;
}

🧠 Best Practices

✅ Keep API keys, base URLs, and sensitive data out of your code — use .env files or secure storage.
✅ Maintain consistent flavor names across Android and iOS.
✅ Add different app icons for each environment to avoid confusion during testing.
✅ Automate builds using CI/CD pipelines (GitHub Actions, Codemagic, etc.).

📦 Bonus: Different App Icons per Flavor

You can use the flutter_launcher_icons package to generate separate icons for each flavor.

Example config in pubspec.yaml:

flutter_launcher_icons:
flavors:
dev:
image_path: "assets/icons/dev_icon.png"
staging:
image_path: "assets/icons/staging_icon.png"
production:
image_path: "assets/icons/prod_icon.png"

Run:

flutter pub run flutter_launcher_icons:main

🎯 Conclusion

By setting up Flavors in Flutter, you can easily manage multiple environments like Development, Staging, and Production — all from the same codebase.
It improves testing, deployment, and collaboration within your team.

Whether you're a solo developer or part of a large team, mastering Flutter flavors is a must for professional app development.

Report Page