What is the difference between CommandLineRunner and ApplicationRunner?
answer
- same lifecycle, different arg type
- CommandLineRunner = raw String...
- ApplicationRunner = parsed ApplicationArguments
- options vs non-options
- ordered together, not per-type
basics
~10 sBoth run once at startup. CommandLineRunner.run receives the raw String[] arguments. ApplicationRunner.run receives an ApplicationArguments object that has already parsed those strings into --option flags and plain (non-option) arguments.
solid answer
~40 sThey are functionally identical in lifecycle — both are startup callbacks invoked by SpringApplication after the context is ready, and both can be ordered together with @Order. The only real difference is the run() signature. CommandLineRunner.run(String... args) hands you the raw, unparsed command-line strings, so you interpret them yourself. ApplicationRunner.run(ApplicationArguments args) hands you a richer abstraction that has already split the arguments into 'option' arguments (those in --name or --name=value form) and 'non-option' arguments (everything else), exposing methods like getOptionNames(), getOptionValues(name), containsOption(name), and getNonOptionArgs(). Prefer ApplicationRunner when your startup logic needs to branch on named flags, because you avoid hand-rolling argument parsing. Choose CommandLineRunner for the simplest cases where you just want the raw tokens or don't care about arguments at all.
code
java · 19 lines// ApplicationRunner: parsed access to flags
@Component
class ImportRunner implements ApplicationRunner {
public void run(ApplicationArguments args) {
if (args.containsOption("import")) {
List<String> files = args.getOptionValues("import"); // --import=a.csv --import=b.csv
files.forEach(this::load);
}
}
void load(String f) { /* ... */ }
}
// CommandLineRunner: raw tokens
@Component
class RawRunner implements CommandLineRunner {
public void run(String... args) {
for (String a : args) System.out.println(a);
}
}go deeper
State that the only difference is the argument type: raw strings vs a parsed object.
List the ApplicationArguments accessor methods and note they are ordered together across both types.
Advise which to pick based on whether you branch on named flags, and clarify there is no built-in ordering between the two interfaces.
Discuss designing CLI-style Spring Boot apps where option flags drive startup behavior and how ordering interacts with data-dependency between runners.
## The one meaningful difference: the argument type Both interfaces are startup callbacks with identical timing and semantics. What differs is what their `run()` method receives: - `CommandLineRunner.run(String... args)` — the **raw** array of command-line tokens, exactly as they appeared after the main class. Nothing is parsed. If the app was launched with `--server.port=9000 import /data/file.csv`, you get the array `["--server.port=9000", "import", "/data/file.csv"]` and must parse it yourself. - `ApplicationRunner.run(ApplicationArguments args)` — a Spring abstraction (`org.springframework.boot.ApplicationArguments`) that has **already parsed** those same tokens into two categories: - **Option arguments**: tokens in `--name` or `--name=value` form. Accessible via `getOptionNames()` (a `Set<String>`), `getOptionValues(String name)` (a `List<String>`, or `null` if the option is absent), and `containsOption(String name)`. - **Non-option arguments**: everything that does not start with `--`. Accessible via `getNonOptionArgs()` (a `List<String>`). - The original raw array is still available via `getSourceArgs()`. ## They share everything else - Same lifecycle position (after context refresh, before `ApplicationReadyEvent`). - Same one-shot, synchronous, main-thread execution. - Same failure semantics (a thrown exception aborts startup). - **Crucially, they are ordered together.** Spring collects all `ApplicationRunner` and `CommandLineRunner` beans into one list and sorts by `@Order`/`Ordered`, so ordering is across both types, not per-type. ## Which to choose - Use **`ApplicationRunner`** when your startup work depends on named flags — e.g. `--seed`, `--reindex`, `--tenant=acme` — because you get parsing for free and clearer code. - Use **`CommandLineRunner`** when you either ignore arguments entirely or genuinely want the raw strings (e.g. passing them straight to another library's parser). ## Common misconception Candidates sometimes claim one runs before the other by design. There is no such rule; relative order between an `ApplicationRunner` and a `CommandLineRunner` is determined solely by their `@Order` values (default order is `Ordered.LOWEST_PRECEDENCE`).
- If you declare both a CommandLineRunner and an ApplicationRunner, which runs first?Neither by default — both default to LOWEST_PRECEDENCE. Spring merges both interface types into one list and sorts by @Order/Ordered, so you control relative order explicitly regardless of type.
- Can a single bean implement both interfaces?Yes, but it is unusual; both run() methods would each be invoked once. It is clearer to implement just the one whose argument type you need.
saying these in an interview costs you the question
- Saying ApplicationRunner always runs before CommandLineRunner (or vice versa)
- Claiming CommandLineRunner also parses --options for you
- Believing the two interfaces have different lifecycle timing