Profiles
A profile is a name for a situation the application runs in, such as dev, test, prod or eu; activating it reads its config files and registers its beans.
Why
Environments often differ by more than one or two values: another database, a fake payment service in development, other URLs per region. Profiles keep the shared setup in one place and put only the differences in profile files and profile beans. There is no if in main.
Activating profiles
| Key | Meaning |
|---|---|
spring.profiles.active |
The active profiles, a comma list or a YAML list. The first source that has the key wins, so the command line beats a file. |
spring.profiles.include |
Profiles added to the active ones, from every source. |
spring.profiles.default |
The profiles used while none is active. default when not set. |
spring.profiles.group.<name> |
Activating <name> activates these too. Groups can contain groups. |
spring.profiles.validate |
true (the default) checks the names: letters, digits and -_.+@, starting and ending with a letter or digit. |
Profiles are usually chosen at launch:
dart run bin/main.dart --spring.profiles.active=prod
SPRING_PROFILES_ACTIVE=prod dart run bin/main.dart
flutter run --dart-define=SPRING_PROFILES_ACTIVE=prod
In code: SpringApplication(additionalProfiles: [...]), run(args, additionalProfiles: [...]), or environment.addActiveProfile(...) in an EnvironmentPostProcessor.
In Flutter apps, the platform and the build are profiles too, with no setup:
android,ios,web,macos,windowsorlinux;mobile(Android, iOS) ordesktop(macOS, Windows, Linux);release,profileordebug.
Profile files
For each active profile, application-<profile>.properties, .yml or .yaml is read after the plain file, so its values win. The last active profile wins over the earlier ones.
lib/resources/
application.yml # always read
application-dev.yml # with dev
application-prod.yml # with prod
The profiles are decided before the profile files are read. So a profile file may not set spring.profiles.active, .include or .default; the start fails if it does. Its spring.profiles.group.* is ignored.
Documents for some profiles
One file can hold several documents: YAML separates them with ---, .properties with a line #---. spring.config.activate.on-profile limits a document to a profile expression. A later document overrides an earlier one.
# lib/resources/application.yml
spring:
profiles:
active: dev
group:
prod: [eu, monitoring]
shop:
url: http://localhost:8080
---
spring:
config:
activate:
on-profile: "prod & !us"
shop:
url: https://eu.neon.books
# lib/resources/application.properties: the same
spring.profiles.active=dev
spring.profiles.group.prod=eu,monitoring
shop.url=http://localhost:8080
#---
spring.config.activate.on-profile=prod & !us
shop.url=https://eu.neon.books
spring.config.activate.on-cloud-platform limits a document to a cloud platform instead: kubernetes, heroku, cloud-foundry, azure-app-service, amazon-ecs, nomad, sap or none.
Profile expressions
The same expressions work in on-profile, @Profile and Environment.matchesProfiles.
| Expression | Matches when |
|---|---|
prod |
prod is active |
!prod |
prod is not active |
prod & eu |
both are active |
dev | test |
either is active |
prod & (eu | us) |
combinations, with parentheses |
& and | cannot be mixed without parentheses. A list (@Profile(['dev', 'test']), or a comma list in on-profile) matches when any entry matches. While no profile is active, the default profiles count: @Profile(['default']) and application-default.yml apply to a run without profiles.
Beans for some profiles
import 'package:spring_core_dart/spring_core_dart.dart';
abstract interface class Payments {
Future<void> charge(int cents);
}
@Service()
@Profile(['prod'])
class StripePayments implements Payments {
@override
Future<void> charge(int cents) async {
// call the payment provider
}
}
@Service()
@Profile(['!prod'])
class FakePayments implements Payments {
@override
Future<void> charge(int cents) async {}
}
@Service()
class Diagnostics {
Diagnostics(this.env);
final Environment env;
bool get verbose => env.matchesProfiles(['dev & !test']);
}
On a configuration class, @Profile applies to all its @Bean methods and to its @PropertySource files. See @Profile.
In Spring (Java)
@Service
@Profile("prod")
class StripePayments implements Payments { ... }
The keys, files and expressions are Spring Boot's. Differences that matter:
@Profiletakes a list:@Profile(['dev', 'test']).- Flutter apps get the platform and build profiles (
ios,web,release...) by themselves. - A document limited to a profile in
application.ymlmay not set thespring.profiles.*activation keys; the start fails when the document applies.