Environment Sync
The env command manages environment variables across flavors in the shared/app_config package. It integrates with envied for type-safe, code-generated environment access.
Subcommands
env init
Initializes the environment configuration structure in shared/app_config:
dart run monorepo_toolkit env init
# Specify initial variables (defaults to API_BASE_URL and AES_KEY)
dart run monorepo_toolkit env init --var API_BASE_URL --var AES_KEY --var SECRETThis creates:
- Per-flavor envied classes (e.g.,
DevelopmentEnv,StagingEnv,ProductionEnv) .envtemplate files per flavor (.env.development,.env.staging,.env.production)- The main
Envclass that delegates to the active flavor's envied class - Updates to the
FlavorStatusenum
env add
Adds a new environment variable to all flavor .env files and envied classes:
dart run monorepo_toolkit env add API_SECRETVariable names must start with an uppercase letter and contain only uppercase letters, numbers, and underscores (e.g., API_KEY, DATABASE_URL, SECRET_123).
This:
- Appends the variable to each flavor's
.envfile - Adds the corresponding
@EnviedFieldannotation to each flavor's envied class - Updates the main
Envclass
You then fill in the actual values per flavor:
# .env.development
API_SECRET=dev_secret_key
# .env.staging
API_SECRET=staging_secret_key
# .env.production
API_SECRET=production_secret_keyenv sync
Synchronizes the FlavorStatus enum and envied classes with the flavors defined in flavors.yaml:
dart run monorepo_toolkit env syncThis regenerates the FlavorStatus enum, per-flavor envied classes, and the main Env class to match the current flavor list. Run this after adding or removing a flavor in flavors.yaml.
Integration with envied
The app_config package uses envied to generate type-safe access to environment variables. After running env add and filling in values, run code generation:
melos run build:app_config
# or
dart run build_runner build --delete-conflicting-outputsThis generates a class with compile-time environment access:
@Envied(path: '.env.development')
abstract class DevelopmentEnv {
@EnviedField(varName: 'API_BASE_URL')
static const String apiBaseUrl = _DevelopmentEnv.apiBaseUrl;
}Flavor-specific .env files
Each flavor has its own .env file:
shared/app_config/
.env.development
.env.staging
.env.productionThe active flavor is set at app startup via Flavor.status in bootstrap.dart, which determines which envied class is used at compile time.
Workflow
- Define flavors in
flavors.yamlat the workspace root - Run
dart run monorepo_toolkit env initto create.envfiles and envied classes - Run
dart run monorepo_toolkit env add <VAR_NAME>for each new variable - Fill in values per flavor in the
.env.*files - Run
dart run monorepo_toolkit env syncafter changing flavors inflavors.yaml - Run code generation to produce the envied classes
Melos shortcuts
melos run env:init # Initialize env config
melos run env:add # Add env variable (pass var name after --)
melos run env:sync # Sync flavor enum and envied classes
melos run env:generate # Generate envied code