Spring Boot
Command Line Arguments
Spring Boot treats command-line arguments as the highest-priority property source — they override application.yml, environment variables, and everything else. Arguments prefixed with -- are added to the Spring Environment as properties; -D flags set JVM system properties. Both are essential tools for overriding configuration at launch time without rebuilding.
Two Kinds of Arguments
Spring Boot recognizes two distinct types of launch arguments, and they work differently:
--key=value (application arguments): prefixed with double-dash. Spring Boot adds these directly to the Environment as properties with the highest priority — they override application.yml, profile files, environment variables, and system properties. This is the correct way to override Spring Boot configuration at launch time.
-Dkey=value (JVM system properties): set before the JVM starts. Available via System.getProperty() and also read by Spring Boot's Environment, but at lower priority than -- arguments. Used for JVM tuning flags and libraries that read system properties directly (logging frameworks, JDBC drivers).
Shell
# ── Application arguments (--) — highest priority in Spring Environment:
java -jar myapp.jar --server.port=9090 --spring.profiles.active=prod
# ── JVM system properties (-D) — lower priority than --args:
java -Dserver.port=9090 -Dspring.profiles.active=prod -jar myapp.jar
# ── Both together — --args override -D for the same key:
java -Dserver.port=8080 -jar myapp.jar --server.port=9090
# Result: server.port = 9090 (-- wins)
# ── JVM memory and tuning flags (not Spring properties):
java -Xms512m -Xmx2g -XX:+UseG1GC -jar myapp.jar
# ── Full production launch command combining both:
java \
-Xms512m -Xmx2g \
-XX:+UseG1GC \
-Dfile.encoding=UTF-8 \
-jar myapp.jar \
--spring.profiles.active=prod \
--server.port=8080 \
--spring.datasource.url=jdbc:mysql://db:3306/mydbOverriding Any Property from the Command Line
Because -- arguments are the highest-priority property source, they can override any key from application.yml or environment variables. This makes them ideal for one-off overrides during debugging, canary deployments, or CI pipelines.
Shell
# Override server port:
java -jar myapp.jar --server.port=9090
# Override datasource URL (useful for pointing at a different DB):
java -jar myapp.jar --spring.datasource.url=jdbc:mysql://localhost:3306/testdb
# Activate a profile:
java -jar myapp.jar --spring.profiles.active=prod
# Activate multiple profiles:
java -jar myapp.jar --spring.profiles.active=prod,metrics
# Override log level:
java -jar myapp.jar --logging.level.com.example=DEBUG
# Override any app.* custom property:
java -jar myapp.jar --app.jwt.expiration=3600 --app.features.payments=true
# Override Flyway migration behavior:
java -jar myapp.jar --spring.flyway.enabled=false
# Change context path:
java -jar myapp.jar --server.servlet.context-path=/v2
# Combine with env vars — --args still win:
export SERVER_PORT=8080
java -jar myapp.jar --server.port=9090 # 9090 winsAccessing Arguments with ApplicationArguments
Inject ApplicationArguments to inspect and use the raw command-line arguments passed to the application. It distinguishes between option arguments (--key=value) and non-option arguments (bare values with no -- prefix).
Java
@Component
@RequiredArgsConstructor
public class ArgInspector implements ApplicationRunner {
private final ApplicationArguments args;
@Override
public void run(ApplicationArguments arguments) {
// All raw args as passed on the command line:
String[] raw = arguments.getSourceArgs();
// e.g. ["--server.port=9090", "--debug", "import", "users.csv"]
// Option args — those prefixed with --:
Set<String> optionNames = arguments.getOptionNames();
// e.g. ["server.port", "debug"]
boolean hasDebug = arguments.containsOption("debug");
// Get values for a specific option (returns List<String>):
List<String> ports = arguments.getOptionValues("server.port");
// e.g. ["9090"]
// Non-option args — bare values without --:
List<String> nonOption = arguments.getNonOptionArgs();
// e.g. ["import", "users.csv"]
log.info("Option args: {}", optionNames);
log.info("Non-option args: {}", nonOption);
}
}
// NOTE: ApplicationArguments only sees the original --args.
// Properties overridden via --args are also in the Environment —
// inject Environment or @Value to read them as regular properties.CommandLineRunner and ApplicationRunner
Both interfaces let you run code after the application context is fully loaded. CommandLineRunner receives raw String args; ApplicationRunner receives the richer ApplicationArguments object. Use them for startup tasks, data imports, or validation.
Java
// ── CommandLineRunner — receives raw String[] args ────────────────────
@Component
@RequiredArgsConstructor
public class DataImportRunner implements CommandLineRunner {
private final UserImportService importService;
@Override
public void run(String... args) throws Exception {
// args = raw command-line strings, e.g. ["--mode=full", "users.csv"]
for (String arg : args) {
log.info("Arg: {}", arg);
}
importService.runStartupCheck();
}
}
// ── ApplicationRunner — receives ApplicationArguments ────────────────
@Component
@RequiredArgsConstructor
public class MigrationRunner implements ApplicationRunner {
private final MigrationService migrationService;
@Override
public void run(ApplicationArguments args) throws Exception {
if (args.containsOption("migrate")) {
List<String> targets = args.getOptionValues("migrate");
// java -jar myapp.jar --migrate=v2 --migrate=v3
targets.forEach(migrationService::run);
}
}
}
// ── Ordering multiple runners with @Order ─────────────────────────────
@Component
@Order(1) // runs first
public class SchemaValidationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
log.info("Validating schema...");
}
}
@Component
@Order(2) // runs second
public class SeedDataRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
log.info("Seeding reference data...");
}
}Disabling Command-Line Property Override
In rare cases — such as security-sensitive deployments where operators should not be able to override config via launch flags — you can disable command-line argument processing entirely.
Java
// Disable -- argument processing (they will no longer override properties):
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApplication.class);
app.setAddCommandLineProperties(false); // -- args ignored as properties
app.run(args);
}
}
// ApplicationArguments and CommandLineRunner still receive the raw args —
// only the auto-injection into the Spring Environment is disabled.
// Use this when you want to process args manually without allowing
// arbitrary property overrides from the command line.Command-Line Arguments in IDE and Docker
How to pass command-line arguments in the most common development and deployment contexts.
Shell
# ── IntelliJ IDEA ─────────────────────────────────────────────────────
# Run/Debug Configurations → Modify options → Program arguments:
--spring.profiles.active=dev --server.port=9090 --app.features.payments=true
# VM options (for -D flags):
-Xmx512m -Dfile.encoding=UTF-8
# ── Maven ─────────────────────────────────────────────────────────────
mvn spring-boot:run -Dspring-boot.run.arguments="--server.port=9090 --spring.profiles.active=dev"
# Or with the spring-boot-maven-plugin in pom.xml:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<arguments>
<argument>--server.port=9090</argument>
<argument>--spring.profiles.active=dev</argument>
</arguments>
</configuration>
</plugin>
# ── Gradle ────────────────────────────────────────────────────────────
./gradlew bootRun --args='--server.port=9090 --spring.profiles.active=dev'
# ── Docker — ENTRYPOINT vs CMD for passing arguments ──────────────────
# Using CMD (arguments can be overridden at docker run):
FROM eclipse-temurin:21-jre
COPY target/myapp.jar app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
CMD ["--spring.profiles.active=prod"]
# Override at runtime:
docker run myapp:latest --spring.profiles.active=dev --server.port=9090
# Using env vars instead (more idiomatic for containers):
docker run \
-e SPRING_PROFILES_ACTIVE=prod \
-e SERVER_PORT=8080 \
myapp:latest