skip to content

How do you control the execution order of multiple runners, and what is the ordering scope?

level: seniorimportance: should knowfreq 40%

answer

  1. @Order / Ordered, lower = first
  2. default LOWEST_PRECEDENCE
  3. both interfaces sorted TOGETHER
  4. sequential, single thread
  5. earlier throw stops the chain

basics

~10 s

Annotate each runner with @Order(n) or implement Ordered. Lower numbers run first. Spring puts all ApplicationRunner and CommandLineRunner beans into one combined list and sorts by that value, so ordering spans both interface types.

solid answer

~50 s

When you have several runners whose startup work must happen in sequence, give each a priority with @Order(value) or by implementing the Ordered interface. Lower values run earlier; the default is Ordered.LOWEST_PRECEDENCE, so unannotated runners run last and in an unspecified relative order. The crucial nuance is scope: Spring Boot's callRunners collects every ApplicationRunner and every CommandLineRunner bean into a single list and sorts them together with AnnotationAwareOrderComparator. So @Order(1) on an ApplicationRunner and @Order(2) on a CommandLineRunner will run the ApplicationRunner first even though they are different interface types. Runners execute sequentially on the main thread, so an exception in an earlier runner prevents later ones from running and aborts startup. If two runners have a genuine data dependency, prefer making that explicit with @Order rather than relying on bean-definition or classpath order, which is not guaranteed.

code

java · 13 lines
java
@Component
@Order(10)                 // runs first
class SeedReferenceData implements ApplicationRunner {
    public void run(ApplicationArguments args) { /* insert base data */ }
}

@Component
@Order(20)                 // runs after, even though different interface type
class BuildSearchIndex implements CommandLineRunner {
    public void run(String... args) { /* index the seeded data */ }
}
// Spring merges both into one list and sorts by @Order:
// SeedReferenceData (10) -> BuildSearchIndex (20)

go deeper

for a junior

Know @Order controls sequence and lower runs first.

for a middle

Add that the default is lowest precedence and runners execute sequentially.

for a senior

Explain that both interface types are sorted together in one list, not per-type.

for a principal

Advise on leaving numbering gaps, fail-fast chaining, and when to replace ordered-runner stacks with a dedicated orchestrator or ready-event listener.

## Why ordering matters If runner A must seed reference data before runner B builds a search index from it, their order is a correctness requirement, not a cosmetic detail. Bean creation order and classpath scanning order are **not** guaranteed, so you must declare ordering explicitly. ## How to declare order Three equivalent mechanisms, in decreasing convenience: 1. `@Order(int value)` on the runner class (or on the `@Bean` factory method). 2. Implement `org.springframework.core.Ordered` and return an `int` from `getOrder()`. 3. Implement `org.springframework.core.PriorityOrdered` for a stronger precedence tier (rarely needed here). **Lower value = higher precedence = runs earlier.** `Ordered.HIGHEST_PRECEDENCE` is `Integer.MIN_VALUE`; `Ordered.LOWEST_PRECEDENCE` is `Integer.MAX_VALUE`, which is also the **default** when no order is specified. Two runners with the same order have an unspecified relative order. ## The critical scope nuance: both interfaces are sorted together Spring Boot's `SpringApplication.callRunners` gathers **all** `ApplicationRunner` beans **and all** `CommandLineRunner` beans into one combined list and sorts it with `AnnotationAwareOrderComparator`. Therefore: - Ordering is **global across both interface types**, not per-type. - An `ApplicationRunner` with `@Order(10)` runs before a `CommandLineRunner` with `@Order(20)`. - There is no implicit rule that one interface type runs before the other. This surprises many candidates who assume all `ApplicationRunner`s run, then all `CommandLineRunner`s (or the reverse). ## Execution characteristics - Runners run **sequentially** on the main application thread; there is no parallelism. - If an earlier runner throws, `callRunners` rethrows immediately — later runners do **not** run, and startup aborts. So ordering also defines a fail-fast chain. - All of this happens after context refresh and before `ApplicationReadyEvent`. ## Design guidance - Encode real dependencies with explicit `@Order` values, leaving gaps (10, 20, 30) so you can insert runners later. - Avoid hidden coupling where a runner depends on a side effect of another runner without an order constraint. - For anything beyond simple sequencing (conditional, retryable, or long-running startup work), consider a dedicated orchestration bean or an `ApplicationReadyEvent` listener instead of stacking many ordered runners. ## @Order vs bean method When you register a runner via an `@Bean` method rather than `@Component`, you can put `@Order` on the method. Both are read by `AnnotationAwareOrderComparator`.

  • If an ApplicationRunner has @Order(5) and a CommandLineRunner has @Order(1), which runs first?
    The CommandLineRunner. Both types are collected into one list and sorted together by order value; 1 is lower than 5, so it runs first regardless of interface type.
  • What order do two runners run in if neither declares @Order?
    Both default to LOWEST_PRECEDENCE, so their relative order is unspecified. Never rely on it; declare @Order if the order matters.

saying these in an interview costs you the question

  • Claiming all ApplicationRunners run before all CommandLineRunners (or vice versa)
  • Saying higher @Order value runs first
  • Assuming bean-definition or classpath order is a reliable ordering guarantee
  • Thinking runners execute in parallel

context