Flutter Env Gen
A type-safe environment configuration generator for Flutter. Generate strongly-typed Dart code from .env files.
Features
- Type-safe - Automatically detects types (String, int, double, bool, List)
- Compile-time constants - Better performance than runtime parsing
- Multiple environments - Support for dev, staging, production configs
- Sensitive data protection - Obfuscate secrets in generated code
- Customizable - Configure field naming, validation, and more
- IDE support - Full autocomplete and type checking
Comparison with flutter_dotenv
| Feature | flutter_dotenv | flutter_env_gen |
|---|---|---|
| Loading | Runtime | Compile-time |
| Type Safety | String only | Auto-detect types |
| Performance | Parse at runtime | Const values |
| Code Completion | No | Full IDE support |
| Validation | Runtime errors | Build-time errors |
| File in APK/IPA | Yes (security risk) | No (compiled) |
Installation
Add to your pubspec.yaml:
dev_dependencies:
build_runner: ^2.4.8
flutter_env_gen: ^1.0.0
Quick Start
1. Create your .env files
.env.dev:
API_BASE_URL=https://dev-api.example.com
ENABLE_LOGS=true
CACHE_TIMEOUT=3600
MAX_RETRY_ATTEMPTS=3
SUPPORTED_LOCALES=en,vi,zh
.env.production:
API_BASE_URL=https://api.example.com
ENABLE_LOGS=false
CACHE_TIMEOUT=86400
MAX_RETRY_ATTEMPTS=3
SUPPORTED_LOCALES=en,vi,zh,ja,ko,fr,de
2. Configure (Optional)
Create build.yaml in your project root:
targets:
$default:
builders:
flutter_env_gen:env_generator:
options:
env_files:
- ".env.dev"
- ".env.staging"
- ".env.production"
output_path: "lib/config/env.g.dart"
class_name: "AppConfig"
field_rename: snake_to_camel
sensitive_keys:
- "KEY"
- "SECRET"
- "TOKEN"
required_keys:
- "API_BASE_URL"
3. Generate code
# Generate once
dart run build_runner build
# Watch for changes
dart run build_runner watch -d
# Clean and rebuild
dart run build_runner clean
dart run build_runner build --delete-conflicting-outputs
4. Use in your code
import 'config/env.g.dart';
void main() {
// Access type-safe config
print(AppConfig.apiBaseUrl); // String
print(AppConfig.enableLogs); // bool
print(AppConfig.cacheTimeout); // int
print(AppConfig.supportedLocales); // List<String>
// Get current environment
print(AppConfig.currentEnvironment); // 'dev', 'staging', or 'production'
runApp(MyApp());
}
Configuration Options
Field Naming
Control how environment variable names are transformed:
| Option | Example Input | Example Output |
|---|---|---|
none |
API_BASE_URL |
API_BASE_URL |
snake_to_camel |
API_BASE_URL |
apiBaseUrl |
snake_to_pascal |
API_BASE_URL |
ApiBaseUrl |
kebab_to_camel |
api-base-url |
apiBaseUrl |
Sensitive Keys
Keys containing these strings will be obfuscated in the generated code:
sensitive_keys:
- "KEY"
- "SECRET"
- "TOKEN"
- "PASSWORD"
Required Keys
Build will fail if these keys are missing from your .env files:
required_keys:
- "API_BASE_URL"
- "APP_NAME"
Type Detection
The generator automatically detects types based on values:
# String
APP_NAME=MyApp
# Boolean (true/false, yes/no, 1/0)
ENABLE_LOGS=true
# Integer
CACHE_TIMEOUT=3600
# Double
APP_VERSION=1.0.5
# List (comma-separated)
SUPPORTED_LOCALES=en,vi,zh
Multi-Environment Setup
Using with Flutter flavors
# Development
flutter run --flavor dev --dart-define=ENVIRONMENT=dev
# Staging
flutter run --flavor staging --dart-define=ENVIRONMENT=staging
# Production
flutter run --flavor prod --dart-define=ENVIRONMENT=production
Generated code uses compile-time environment
class AppConfig {
static const String apiBaseUrl = String.fromEnvironment(
'API_BASE_URL',
defaultValue: 'https://dev-api.example.com',
);
static const bool enableLogs = bool.fromEnvironment(
'ENABLE_LOGS',
defaultValue: true,
);
static String get currentEnvironment =>
const String.fromEnvironment('ENVIRONMENT', defaultValue: 'dev');
}
Advanced Usage
Using Annotations
import 'package:flutter_env_gen/flutter_env_gen.dart';
@EnvGen(
envFiles: ['.env.dev', '.env.prod'],
className: 'Config',
fieldRename: FieldRename.snakeToCamel,
sensitiveKeys: ['API_KEY', 'SECRET'],
requiredKeys: ['API_URL'],
)
class EnvConfig {}
Custom Output Path
# build.yaml
targets:
$default:
builders:
flutter_env_gen:env_generator:
options:
output_path: "lib/core/config/environment.g.dart"
Validation
The generator validates:
- Required keys exist in all env files
- Type consistency across environments
- File format and syntax
Troubleshooting
Generated file not updating
dart run build_runner clean
dart run build_runner build --delete-conflicting-outputs
Can't find .env files
Ensure your .env files are in the project root (same level as pubspec.yaml).
Type conflicts
If the same key has different types across env files, it defaults to String.
Best Practices
- Never commit sensitive .env files - Add to
.gitignore - Use different files for environments -
.env.dev,.env.staging,.env.prod - Keep production secrets secure - Use CI/CD secret management
- Validate required keys - Catch missing config at build time
- Use descriptive key names -
API_BASE_URLinstead ofURL
Example Project
See the example directory for a complete Flutter application demonstrating:
- Multiple environment files
- Custom configuration
- Type-safe access
- Sensitive data handling
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see the LICENSE file for details.
Migration from flutter_dotenv
If you're currently using flutter_dotenv, here's how to migrate:
Before (flutter_dotenv)
// main.dart
await dotenv.load(fileName: ".env");
String apiUrl = dotenv.env['API_URL'] ?? '';
bool enableAds = dotenv.env['ENABLE_ADS'] == 'true';
After (flutter_env_gen)
// main.dart
import 'config/env.g.dart';
String apiUrl = AppConfig.apiBaseUrl; // Strongly typed!
bool enableAds = AppConfig.enableAds; // Already a boolean!
Platform Support
This package generates pure Dart code and works with:
- Flutter (iOS, Android, Web, Desktop)
- Dart (Server, CLI applications)
Performance Comparison
| Metric | flutter_dotenv | flutter_env_gen |
|---|---|---|
| Startup time | ~50-100ms (parsing) | 0ms (compile-time) |
| Memory usage | Higher (stores all values) | Lower (const values) |
| Type safety | Manual parsing | Automatic |
| Error detection | Runtime | Build-time |
Security Best Practices
- Never commit sensitive .env files to version control
- Use .gitignore to exclude .env files
- Store production secrets in CI/CD secret management
- Use different values for each environment
- Enable obfuscation for sensitive keys
Author
Created by Bach Ngoc Hoai
Support
If you find this package useful, please give it a star on GitHub!