How I am Managing Multiple Development Environments and Data Migration.
Learn how to configure Firebase for multiple environments in Flutter, manage environment-specific settings, and migrate your authentication…
Learn how to configure Firebase for multiple environments in Flutter, manage environment-specific settings, and migrate your authentication and Firestore data from test to production with best practices.
Introduction
When building a Flutter app with Firebase, it’s essential to manage different environments, such as testing and production, to ensure your app’s stability and security.
By the end of this article, you’ll have a robust setup to maintain clear separation between your test and production environments.
1. Test Mode and Security in Firebase
- Question: Can you use the same Firebase project for test and production environments while maintaining security?
- Response: Although it’s possible to use the same project, it’s strongly recommended to create separate projects for test and production environments to ensure data isolation, security, and easier management.
Best Practices:
1. Environment Parity: Ensure that your test and production environments are as similar as possible to avoid discrepancies when moving to production.
2. Data Handling: Use sanitized or mock data in your test environment to prevent exposure of real user data.
3. Access Control: Restrict access to sensitive data and resources, limiting who can access production data.
4. API Keys: Use separate API keys and credentials for test and production environments to prevent unauthorized access.
5. Logging and Monitoring: Implement logging and monitoring to detect any unauthorized access or anomalies in both environments.
2. Separate Firebase Projects for Test and Production
- Question: Should you continue using test mode or create a separate Firebase project for production?
- Response: It’s best to create separate Firebase projects for test and production environments. This approach ensures clear separation of data, security, and environment-specific configurations.
Steps to Implement:
1. Create New Firebase Projects: Set up separate Firebase projects for your testing (myapp-test) and production (myapp-production) environments.
2. Organize Configuration Files: Download and store the google-services.json (Android) and GoogleService-Info.plist (iOS) for each environment.
3. Set Up Access Controls: Ensure that only authorized users have access to the production environment, and use different credentials for test and production.
4. Use CI/CD Pipelines: Automate deployment processes to manage environment-specific configurations efficiently, using tools like GitHub Actions, GitLab CI/CD, or Bitbucket Pipelines.
5. Environment-specific Setup: Set environment-specific variables and settings in your CI/CD pipelines or build scripts to automatically configure the correct Firebase project during deployment.
3. Configuring Firebase for Multiple Environments in Flutter
To manage multiple Firebase configurations in Flutter, follow these steps:
- Create Separate Firebase Projects: Set up distinct Firebase projects for testing and production environments. Download the configuration files (
google-services.jsonfor Android,GoogleService-Info.plistfor iOS) for each environment. - Organize Firebase Configuration Files:
Production Files: Create a separate directory structure for your dev environment and place the files there
.android/app/google-services.json
.ios/Runner/GoogleService-Info.plist
Dev Files: Create a separate directory structure for your dev environment:. android/app/src/test/google-services.json
. ios/Runner/test/GoogleService-Info.plist
Note: You can also config default configuration for production and special confuguration for dev environment so in that case you don’t have to create a separate firebase package for those environments.
In our case your android structure will look something like this:
android/
src/
dev/
google-services.json
production/
google-services.json3. Generate Firebase Options Files:
- Use the
flutterfire_clito generate environment-specific options files for each Firebase project: - For production:
flutterfire configure --project=<production-project-id> --out=lib/firebase_options_production.dart - For test:
flutterfire configure --project=<test-project-id> --out=lib/firebase_options_test.dart
4. Set Up Build Flavors in Android:
- Modify the
android/app/build.gradlefile to define product flavors:
android {
...
flavorDimensions "env"
productFlavors {
production {
dimension "env"
// you can comment out below line if you want to use default package
// and dont want to create separate firebase package for production
applicationIdSuffix ".production"
}
// Do not use test for Flavors as Gradle not support it
dev{
dimension "env"
applicationIdSuffix ".dev"
}
}
}
// Add this to apply the correct google-services.json file
// At the end of the file outside `android` block in this file
android.applicationVariants.all { variant ->
def flavorName = variant.productFlavors.get(0).name
def googleServicesFile = flavorName == 'dev'
? file("src/dev/google-services.json")
: file("src/production/google-services.json")
if (googleServicesFile.exists()) {
apply plugin: 'com.google.gms.google-services'
}
}5. Set Up Build Flavors in iOS:
- In Xcode, create separate schemes for
ProductionandTestenvironments: - Duplicate your current scheme and rename it accordingly.
- Assign the correct
GoogleService-Info.plistfile to each scheme by adjusting theBuild Settingsin Xcode.
6. Conditional Firebase Initialization in Flutter:
- Modify your
main.dartto conditionally initialize Firebase based on the environment:
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options_production.dart' as prod;
import 'firebase_options_test.dart' as dev;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
const bool isProduction = bool.fromEnvironment('dart.vm.product');
await Firebase.initializeApp(
options: isProduction ? prod.DefaultFirebaseOptions.currentPlatform : dev.DefaultFirebaseOptions.currentPlatform,
);
runApp(MyApp());
}7. Build and Run with the Correct Flavor:
- Use the
--flavorparameter to specify the environment when building or running your app: - For production:
flutter run --flavor prod --dart define=dart.vm.product=true - For test:
flutter run --flavor dev --dart-define=dart.vm.product=false
Note: You may encounter this errorNo matching client found for package name ‘com.your_package_name.dev’ this is the errorand to resolve this:
Ensure Firebase Project Setup:
Make sure you have correctly added an Android app in your Firebase development project with the package name com.your_package_name.dev.Download the correspondinggoogle-services.jsonfile and place it in the correct directory (android/app/src/dev).
Similar is the case other environment like production if so.
9. To build app bundles and APKs:
- Production app bundle:
flutter build appbundle --flavor prod --dart-define=dart.vm.product=true - Production APK:
flutter build apk --flavor prod --dart-define=dart.vm.product=true - Development app bundle:
flutter build appbundle --flavor dev --dart-define=dart.vm.product=false - Development APK:
flutter build apk --flavor dev --dart-define=dart.vm.product=false
4. Migrating Authentication and Firestore Data to Production
- Question: How do you migrate Firebase Authentication and Firestore data from test to production?
- Response: Migrating data involves several steps using Firebase Admin SDK, Google Cloud Platform (GCP) tools, or custom scripts.
Steps for Authentication Data Migration:
- Export Users from Test Project: Use Firebase Admin SDK to export user data (UID, email, etc.) from the test project.
- Import Users into Production Project: Use Firebase Admin SDK to import the exported users into the production project.
Steps for Firestore Data Migration:
- Export Data from Test Project: Use the Firebase Console or
gcloud firestore exportcommand to export Firestore data to a Google Cloud Storage bucket. - Grant Access to Production Project: Ensure that the production Firebase project has the necessary permissions to access the Google Cloud Storage bucket containing the exported data.
- Import Data into Production Project: Use the Firebase Console or
gcloud firestore importcommand to import the data into your production Firestore.
5. Migrating Data Using GCP Tools
- Question: Are there other methods using GCP tools for data migration?
- Response: Yes, GCP offers several tools for migrating Firebase Authentication and Firestore data between projects.
Steps for Authentication Data Migration Using Identity Platform:
- Enable Identity Platform: Activate Identity Platform in both test and production projects via Google Cloud Console.
- Export Users from Test Project:
In Identity Platform, export users to a Google Cloud Storage bucket. - Import Users into Production Project:
Use Identity Platform to import users into the production project from the storage bucket.
Steps for Firestore Data Migration Using GCP Tools:
- Firestore Export/Import: Use Firestore’s export and import features through the GCP Console or
gcloudCLI for data migration. - BigQuery Data Transfer: Link your Firestore data to BigQuery, transfer the data between datasets, and re-import it into Firestore if needed.
- Dataflow for Advanced Migration: Set up a Dataflow pipeline for complex data transformation and migration between Firestore instances in different projects.
Resources:
Firebase Docs: https://firebase.google.com/docs/firestore/manage-data/move-data
YouTube Video: https://www.youtube.com/watch?v=bKDdZKlnJGk&t=62s
Credit: JonnyBCodes
Conclusion
This guide outlines the necessary steps to manage multiple Firebase environments in Flutter and effectively migrate data between test and production environments. By following these best practices and leveraging GCP tools, you can maintain a robust and secure development workflow while ensuring smooth transitions from testing to production.
Disclaimer : This guide provides a general approach for managing configurations in Flutter and Firebase projects. The implementation details and configurations may vary based on your project’s specific requirements and setup. In this case, we discuss using default configurations for production and custom setups for development flavors, including the use of separate environment folders for different build flavors. However, your project’s needs might differ, and you may need to adapt these practices accordingly. Always ensure to tailor the setup to fit your unique project structure and requirements.
Proceed with your own due diligence, and happy coding!