Quick answer
Treat configuration as versioned operational input with an owner, schema, source, precedence, validation rule, safe observability story, and rollout plan. In Spring Boot, bind related settings to a typed @ConfigurationProperties class, validate them at startup, and inject that type into the service that owns the decision. Profiles select environment-specific behavior or sources; they are not a secret store. Secrets arrive from an approved delivery mechanism, are least-privilege credentials, and must never become committed YAML, diagnostic output, exception text, metric labels, or casual logs.
Property precedence is power. A value in an external source, environment variable, command-line argument, test property, or deployment platform can override a packaged default according to Spring Boot’s configured property-source order. That helps operators set a safe production database endpoint without rebuilding an artifact, but it also means a forgotten environment value can silently defeat a reviewed file. Record effective non-secret configuration identity and deployment version, validate invariants at startup, and investigate configuration drift with evidence rather than guessing which file was edited.
This course documents Spring Boot 4.1 and Java 17 as the mainline. Spring Boot 3.5 services can apply the same ownership, typed binding, validation, and secret-boundary principles, but must verify their exact external-configuration, Actuator, and deployment integration behavior. Do not expose an actuator endpoint or copy a precedence list from another version as a substitute for inspecting the running application’s approved configuration.
Shared order-service incident stage
In the shared flash-sale incident, validation and authorization are functioning, but pool wait grows and order p99 latency rises. The order service must reserve inventory in a short transaction; the JPA layer must reveal which SQL and lock behavior consume the pool. Configuration decides the constraints around both: database endpoint and TLS settings, pool limits, connection and statement timeouts, maximum request size, admission/concurrency limits, payment endpoint, feature flags, and observability sampling. A misplaced or overridden setting can transform a manageable surge into a system-wide queue.
Responders should first collect safe drift evidence: release identifier, configuration schema version, active profile names, deployment timestamp, source category for non-secret settings, effective pool limit, timeout values, and recent rollout changes. They should not dump all environment variables, show secret values in an incident channel, or enable a public endpoint that reveals credentials. A pool limit that differs from the reviewed manifest is useful evidence; a password, authorization token, or full JDBC URL with embedded credentials is not required to diagnose it.
For example, a production pod may receive a platform environment variable that overrides a packaged application.yml timeout. A longer timeout retains connections during a slow inventory query, increasing pool wait and customer retries. The repair is not merely to edit a local profile. Identify the winning property source, correct the approved deployment configuration, validate it in a canary, and compare pool wait, transaction duration, query latency, and user latency after rollout. The same incident timeline remains intact because configuration explains the operating envelope rather than replacing application correctness.
Core mechanism and evidence boundary
Externalized configuration separates deployable code from environment-specific values. Spring Boot assembles property sources and resolves a key according to its precedence rules. Typical inputs include packaged or external configuration files, environment variables, system properties, command-line arguments, test properties, and platform integrations. Exact ordering and available sources should be verified for the selected Spring Boot release and launch mode. The operational rule is simpler: know which sources are allowed to set each key, make overrides intentional, and make the effective non-secret result auditable.
@ConfigurationProperties binds a prefix into a cohesive typed object. It is preferable to scattering @Value strings through controllers because it gives related settings one home, supports relaxed binding, makes validation visible, and prevents a misspelled key from becoming a hidden null or fallback. Use constructor binding through a Java 17 record or immutable class where appropriate, add Bean Validation constraints for local shape and relationships, and fail startup when a required endpoint, duration, range, or invariant is invalid. Startup validation catches configuration that cannot ever be safe; it does not prove a remote database is reachable or that a capacity number is correct under load.
Profiles are selectors for environment- or role-specific configuration. A dev profile may enable safe local stubs, a test profile may use test resources, and a production deployment may select the production operational baseline. Avoid making profiles a maze of hidden inheritance or allowing unreviewed profile names supplied by a request. Profiles do not contain authority by themselves and profiles are not a secret store. A secret manager, platform workload identity, encrypted volume, or injected environment variable might deliver a secret, but the profile only helps choose how an application reads approved settings.
Secrets deserve a separate lifecycle. A database credential, payment API key, signing key, or third-party token has an owner, scope, rotation cadence, access policy, audit trail, and revocation procedure. The application should read the minimum credential at runtime from an approved injection path, restrict who can see it, and avoid copying it into derived configuration. Prefer short-lived or workload-identity credentials when the platform supports them. A secret in a repository, image layer, ticket, shell history, crash dump, or wide diagnostic endpoint must be treated as exposed and rotated, not merely deleted from the latest file.
Configuration drift is a difference between intended and effective operating input. It can come from an old deployment, emergency command-line override, platform default, wrong active profile, stale secret version, manual console edit, or code/config schema mismatch. Detect it through declared configuration versions, artifact hashes, deployment metadata, an allowlisted effective-config fingerprint that excludes secret values, and reconciled infrastructure records. Do not create a raw hash of secret material if it can become an oracle or reveal change timing unnecessarily; instead track a secret reference version or rotation event through protected systems.
Actuator can aid diagnosis, but it is an operational control surface. Health, metrics, environment, configuration properties, loggers, heap dumps, mappings, and shutdown-related facilities have different sensitivity. Expose only the endpoints required for the environment, protect them with network and application authorization, sanitize keys and values, and avoid assuming a management port makes data safe. An /env-style response or configuration-properties output can reveal endpoints, usernames, feature flags, paths, and sometimes poorly named secrets. Endpoint exposure must be reviewed separately from whether the service starts.
Minimal reproducible Spring example
This Java 17 configuration record binds safe order-service operating limits and validates them before traffic is accepted. It illustrates Spring Boot 4.1 style, while Spring Boot 3.5 users should check their selected validation and configuration scanning setup.
package com.example.orders;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import java.net.URI;
import java.time.Duration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
@Validated
@ConfigurationProperties("orders")
public record OrderServiceProperties(
@NotNull URI paymentBaseUri,
@NotNull Duration databaseAcquireTimeout,
@NotNull Duration reservationTimeout,
@Min(1) @Max(256) int maxInFlightCommands,
boolean quoteReadsEnabled) {
public OrderServiceProperties {
if (databaseAcquireTimeout != null
&& reservationTimeout != null
&& reservationTimeout.compareTo(databaseAcquireTimeout) < 0) {
throw new IllegalArgumentException("reservation timeout must include acquisition budget");
}
}
}
The compact constructor null-guards the cross-field comparison so a missing duration reaches Bean Validation and produces the intended @NotNull startup violation instead of an incidental NullPointerException. Once both values exist, the relationship check enforces the acquisition-budget invariant.
The application can enable configuration-properties scanning or register this type explicitly, then inject OrderServiceProperties into the admission or payment adapter. The record contains no password or token. A datasource credential can be supplied separately by the platform or secret manager to the datasource configuration, with access governed outside the Java source. The safe configuration file may contain only references and non-sensitive defaults:
orders:
payment-base-uri: https://payments.internal.example
database-acquire-timeout: 250ms
reservation-timeout: 2s
max-in-flight-commands: 64
quote-reads-enabled: true
Do not treat these values as universally correct. The acquisition timeout must fit within the overall request deadline, leaving time for query, commit, and response work. The command limit must be derived from database capacity, transaction duration, and safety headroom, then tested under load. An environment variable or deployment value may legitimately override the YAML; the release process must make that override reviewable. Typed validation prevents malformed values from reaching traffic, not a dangerous but syntactically valid limit of 256.
Failure modes and dangerous misconceptions
“The file in the image is the configuration.” It is one possible property source. A platform environment variable, command-line option, external file, or test source can win according to precedence. When a service behaves unexpectedly, inspect an approved effective-source report and deployment metadata rather than editing a lower-precedence file and hoping it takes effect.
“@Value everywhere is equivalent to a typed properties class.” It scatters ownership, weakens cross-field validation, and makes the supported schema hard to discover. A cohesive typed configuration object is easier to review, test, document, and inject. It still needs careful defaults, explicit source permissions, and an owner who understands the operational consequence.
“Startup validation proves production safety.” It can prove a required duration parses and a local range is valid. It cannot prove that the payment endpoint is authorized, the database has capacity, a timeout fits all downstream budgets, or a secret is accepted by its provider. Combine startup checks with canary probes, controlled load tests, and runbook evidence.
“Profiles keep secrets safe.” A profile selects behavior or configuration inputs; it does not encrypt, rotate, authorize, or audit a secret. A production profile file committed with a password is still an exposed password. Use a secret delivery system, least privilege, rotation, and sanitation independent of profile naming.
“Actuator is internal, so expose everything.” Internal networks, misrouted ingress, compromised workloads, support access, and diagnostic screenshots all expand exposure. Environment and configuration endpoints can disclose operational topology and sensitive values. Use a minimal allowlist, strong authorization, sanitized output, and a separate review for every management endpoint.
Security, privacy, transaction, capacity, and cost implications
Configuration is a control plane and must follow least privilege. Separate who may deploy code, change non-secret runtime settings, read secrets, rotate secrets, and invoke operational endpoints. An order-service process should have only the database and payment permissions it needs for its role. A developer who can set an arbitrary payment base URI or log level may create a security and cost impact even without direct database access, so changes need review and audit.
Never place secrets in client-visible configuration, browser bundles, error responses, metrics, traces, or support links. Sanitize common key names and also review custom names that hold tokens or connection strings. Avoid writing a secret to verify injection; verify a protected secret reference version, successful authenticated dependency probe, or rotation event instead. If a secret is suspected in logs or source control, revoke and rotate it, restrict access to the affected artifacts, and investigate propagation.
Timeouts, pool limits, retry budgets, circuit breakers, and concurrency limits are configuration with transaction consequences. A reservation transaction should have room to acquire a connection, perform its conditional update, commit, and return before the request deadline. Remote payment budgets should be outside that local transaction. Setting retry counts without an idempotency contract can multiply side effects and spend; setting a high pool maximum can make lock contention and database bills worse.
Configuration also shapes observability cost. Sampling rates, log levels, trace exporters, metric cardinality limits, and retention determine what an incident reveals and what it leaks. Tie changes to a configuration version and expiration plan, especially emergency diagnostics. A temporary debug flag that silently survives after the flash sale can create both recurring telemetry costs and privacy exposure.
Testing and production validation
Write configuration binding tests that load the properties class with valid values, missing required values, invalid durations, out-of-range limits, and cross-field violations. Assert startup fails clearly for invalid local configuration and that a valid configuration reaches the owning component. Test profile selection only through the intended deployment paths; do not use a profile as a substitute for proving secret permissions. Confirm that test fixtures do not use production-like credentials or inadvertently mask a missing required property.
Add integration checks for the running application’s safe management surface. Verify the exact Actuator endpoints that are exposed, their authentication and network restrictions, and that sanitized output does not reveal secret keys or values. Test secret rotation with the approved platform mechanism in a non-production environment: determine whether the application needs restart, reload, or credential refresh, and prove the old credential is no longer accepted. A mocked environment map does not establish a real platform’s secret mount or identity behavior.
For the flash-sale rollout, capture the canary’s release identifier, active profiles, allowed effective setting fingerprint, pool and timeout settings, protected dependency health, query latency, pool wait, transaction duration, and user outcome metrics. Change one reviewed setting at a time where possible, wait for representative traffic, and compare evidence to the baseline. If drift is found, stop uncontrolled overrides, identify the winning source, correct the declared configuration, and verify the effective value after deployment.
Operations checklist
- Give each operational setting an owner, typed schema, default, allowed source, and rollout plan.
- Use
@ConfigurationPropertieswith startup validation for cohesive service settings. - Verify property precedence for the selected Spring Boot release and launch environment.
- Keep profiles simple and treat them as behavior selectors, not secret management.
- Deliver secrets through an approved least-privilege injection path with rotation and revocation.
- Never emit secrets, raw environment dumps, or sensitive configuration in public diagnostics.
- Record deployment, profile, schema, and safe effective-configuration drift evidence.
- Protect and minimize Actuator endpoints; management ports do not remove authorization requirements.
- Fit acquisition, transaction, remote-call, retry, and response timeouts into one end-to-end budget.
- Validate config changes with a canary and compare pool wait, query evidence, and user latency.
Official sources
- Spring Boot externalized configuration — accessed 2026-08-05.
- Spring Boot configuration properties — accessed 2026-08-05.
- Spring Boot production-ready features — accessed 2026-08-05.
- Spring Boot Actuator endpoint exposure — accessed 2026-08-05.
Continue the learning path
Use Spring Service Layers and Transaction Boundaries Explained to apply timeout and side-effect settings to one local commit, and use Spring Data JPA Query Performance Explained to interpret pool wait and query evidence. Continue with the Spring Backend course, browse Topics, and return to Spring Backend Engineering for the complete incident path.