Skip to content

Application properties

Fluxzero provides a static utility, ApplicationProperties, for resolving configuration values across environments, tests, and production. It supports:

  • Layered resolution from environment variables, system properties, and .properties files
  • Placeholder substitution (e.g. ${my.env})
  • Encrypted values with automatic decryption
  • Typed access: getBooleanProperty, getIntegerProperty, etc.

Properties are resolved in the following order of precedence:

  1. EnvironmentVariablesSource – e.g. export MY_SETTING=value
  2. SystemPropertiesSource – e.g. -Dmy.setting=value
  3. FluxzeroAdditionalPropertiesSource – locations configured with FLUXZERO_CONFIG_LOCATIONS
  4. ApplicationEnvironmentPropertiesSource – e.g. application-dev.properties
  5. ApplicationPropertiesSource – base fallback (application.properties)
  6. FluxzeroPropertiesSource – SDK defaults (fluxzero.properties or fluxzero.json)
  7. (Optional): Spring’s Environment is added as a fallback source if Spring is active

ApplicationPropertiesSource merges every application.properties resource visible on the application classpath. A shared module can therefore own common defaults once; each executable that depends on that module inherits them. Do not repeat the same key with different values across modules: the SDK logs a warning because class-loader ordering would make that value ambiguous. Put intentional overrides in an environment variable, system property, environment-specific file, or another higher-priority source. Spring Boot nested JARs remain separate classpath resources and are discovered automatically. A custom uber-JAR build that collapses equal resource names must merge overlapping application.properties files in its own packaging configuration.

To specify the environment (dev, prod, etc.), define:

Terminal window
export ENVIRONMENT=dev

This allows application-dev.properties to override base properties.

SDK-loaded property files accept both regular property names and their conventional environment-variable aliases. For example, FLUXZERO_AUTH_OIDC_LOGIN_STATE_SECRET can be resolved with ApplicationProperties.getProperty("fluxzero.auth.oidc.login-state-secret"). When both forms occur in the same source, the exact property name takes priority.


Use fluxzero.serialization.typeAliases to map legacy serialized type names to their current names during deserialization. Separate multiple entries with commas, semicolons, or newlines. Exact aliases use source=target; package aliases require a trailing .* on both sides:

fluxzero.serialization.typeAliases=host.example.LegacyCommand=io.example.CurrentCommand,host.example.events.*=io.example.events.*

For deployment configuration, set the conventional environment variable. Quote its value so the shell leaves package wildcards unchanged:

Terminal window
export FLUXZERO_SERIALIZATION_TYPE_ALIASES='host.example.LegacyCommand=io.example.CurrentCommand,host.example.events.*=io.example.events.*'

FLUXZERO_SERIALIZATION_TYPEALIASES is accepted as a compact alternative. Following the normal property resolution order, the environment variable takes precedence over system properties and application*.properties. The selected property source supplies the complete alias list; entries are not merged across property sources.

Exact aliases take precedence over package aliases, and the longest matching package prefix wins. An alias configured through FluxzeroBuilder.addTypeAlias(...) or addPackageAlias(...) overrides a property alias with the same source. Aliases run after revision upcasters and also apply to polymorphic @class values at any depth in JSON, JSON-encoded message metadata read as an object, and root @class values in JSON test fixtures. See Upcasting and downcasting for the complete behavior.


String name = ApplicationProperties.getProperty("app.name", "DefaultApp");
boolean enabled = ApplicationProperties.getBooleanProperty("feature.toggle", true);
int maxItems = ApplicationProperties.getIntegerProperty("limit.items", 100);

fluxzero.defaults.version lets new applications opt into newer SDK defaults while existing applications keep compatibility behavior when the property is absent. Use yyyy.MM.dd values. Each version includes the defaults from earlier versions, and each behavior can still be overridden with its dedicated property.

Defaults versionEquivalent propertyWhat changes
>= 2026.05.20fluxzero.tracking.unconfiguredHandlerConsumerMode = perHandlerHandlers without an explicit @Consumer or matching custom ConsumerConfiguration get their own generated default consumer per handler class, instead of sharing one application default consumer per message type. This isolates tracking positions and handler failures for unconfigured handlers.
>= 2026.05.21fluxzero.scheduling.periodic.useDefaultInitialDelay = true@Periodic annotations that omit initialDelay use the schedule’s natural first deadline: fixed-delay schedules first run after delay, and cron schedules first run at the next cron match. Set initialDelay = 0 to request an immediate first run.
>= 2026.09.09fluxzero.websocket.reconnectBackoff.enabled = trueWebSocket reconnect attempts use equal jitter over a capped exponential delay instead of a fixed one-second interval. Set the dedicated property to false to retain fixed retries.
>= 2026.09.10fluxzero.eventsourcing.maxFetchBytes = 104857600Aggregate-history pages request at most 100 MiB of serialized event payload. Set the dedicated property to 0 to retain count-only pages.

For example:

fluxzero.defaults.version=2026.05.21

This enables both the per-handler consumer default and the newer periodic initial-delay default. To choose one behavior explicitly without changing the defaults version, set the dedicated property directly. Existing applications that omit fluxzero.defaults.version keep compatibility behavior: unconfigured handlers share the application default consumer, implicit @Periodic(initialDelay = -1) is treated as an immediate first run, WebSocket reconnects use a fixed one-second interval, and aggregate-history pages are count-bounded only.


Fluxzero supports secure storage of secrets using its built-in encryption utility. To use encryption:

  1. Generate a new key with:

    String key = DefaultEncryption.generateNewEncryptionKey();
    System.out.println(key);
    // => ChaCha20|KJh832h1f7shDFb... -> Save and use as ENCRYPTION_KEY
  2. Set the encryption key via an environment variable or system property:

    Terminal window
    export ENCRYPTION_KEY=ChaCha20|KJh832h1f7shDFb...
  3. Encrypt values at build/deploy time:

    String encrypted = ApplicationProperties.encryptValue("secret-google-key");
    System.out.println(encrypted);
    // => encrypted|ChaCha20|mm8yeY8TXtNpdrwO:REdej56zvFXc:b7oQdmnpQpUzagKtma9JLQ==
  4. Add encrypted values to your config:

    google.apikey=encrypted|ChaCha20|mm8yeY8TXtNpdrwO:REdej56zvFXc:b7oQdmnpQpUzagKtma9JLQ==
  5. Resolve them normally in code:

    String apiKey = ApplicationProperties.getProperty("google.apikey");
    // -> "secret-google-key"

Decryption is transparent. Fluxzero detects encrypted values and decrypts them automatically.


Properties can be defined in your test/resources/application.properties or overridden via system properties:

Terminal window
-Dmy.test.override=true

Or dynamically inject mock values:

TestFixture.create(MyHandler.class)
.withProperty("my.test.value", "stub")
.whenCommand("/users/create-job.json")
.expectSchedules(ScheduledJob.class);

© 2026 Fluxzero