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:

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:

See also