How does Spring Boot automatically run batch jobs on startup, and how do you control which jobs run?
answer
- JobLauncherApplicationRunner runs after context start
- spring.batch.job.enabled=true default
- spring.batch.job.name (Boot 3) / names (Boot 2)
- args -> JobParameters
- blocks startup + drives exit code
basics
~10 sBoot registers a JobLauncherApplicationRunner that, after the context starts, calls JobLauncher.run() on the Job beans it finds. It's on by default; set spring.batch.job.enabled=false to disable, or spring.batch.job.name to pick a specific job.
solid answer
~40 sSpring Boot's batch auto-configuration contributes a JobLauncherApplicationRunner — an ApplicationRunner that runs after the context is ready and invokes the auto-configured JobLauncher on the discovered Job beans. It's enabled by default (spring.batch.job.enabled=true), which is why a batch Boot app 'just runs the job' on startup. If there are multiple Job beans you should tell Boot which to run via spring.batch.job.name (Boot 3; it was the plural spring.batch.job.names in Boot 2). Command-line args are converted into JobParameters, so you can pass runtime values like --runDate=2026-07-22. To stop auto-running entirely — common when you trigger jobs yourself from a controller or scheduler — set spring.batch.job.enabled=false. Because it uses the default (sync) launcher, startup blocks until the job completes, and the exit code reflects the job's result.
code
java · 17 lines// application.yml
// spring:
// batch:
// job:
// enabled: true # default; false disables startup auto-run
// name: importJob # Boot 3 (was spring.batch.job.names in Boot 2)
// Launch with parameters converted from CLI args:
// java -jar app.jar --runDate=2026-07-22 --chunk=100
@Bean
Job importJob(JobRepository repo, Step step) {
return new JobBuilder("importJob", repo)
.incrementer(new RunIdIncrementer()) // fresh instance each boot
.start(step)
.build();
}go deeper
Know Boot auto-runs the job at startup and enabled=false turns it off.
Name JobLauncherApplicationRunner, the enabled/name properties, and the Boot 2->3 rename.
Explain arg->JobParameters conversion, blocking startup + exit codes, and multi-job disambiguation.
Discuss batch-as-container (k8s/cron) patterns using exit codes, and why a web app usually disables startup auto-run.
## The auto-run mechanism Spring Boot's `BatchAutoConfiguration` registers a bean called **`JobLauncherApplicationRunner`** (it was `JobLauncherCommandLineRunner` in older Boot). It implements `ApplicationRunner`, so Boot calls it **once, after the ApplicationContext is fully started**. Inside, it takes the auto-configured `JobLauncher` and calls `run(job, params)` for the eligible `Job` bean(s) in the context. This is the machinery that makes a Spring Boot batch application execute its job simply by starting the app (the classic `java -jar app.jar` batch pattern). ## Enabling / disabling - Controlled by **`spring.batch.job.enabled`** — **default `true`**. When batch auto-config is active and a `Job` bean exists, the runner is registered. - Set **`spring.batch.job.enabled=false`** to prevent any startup execution. Do this when you launch jobs yourself (REST endpoint, `@Scheduled`, message listener) and don't want them firing at boot. ## Selecting which job(s) If the context has **more than one `Job` bean**, you must disambiguate, otherwise Boot may refuse or run all/none as configured: - **Boot 3.x:** `spring.batch.job.name=<jobBeanName>` — a **single** job name. - **Boot 2.x:** `spring.batch.job.names=job1,job2` — comma-separated list (plural). This property was **renamed** in Boot 3. ## Passing parameters via the command line `JobLauncherApplicationRunner` converts application arguments into `JobParameters`. So: ``` java -jar app.jar --runDate=2026-07-22 --chunk=100 ``` becomes JobParameters `{runDate=2026-07-22, chunk=100}` (parsed via the configured `JobParametersConverter` — `DefaultJobParametersConverter` or `JsonJobParametersConverter`). This is how you feed identifying/runtime values into an on-startup run. ## Blocking + exit code Because it uses the default `TaskExecutorJobLauncher` with a `SyncTaskExecutor`, the runner **blocks** the startup thread until the job finishes. Combined with Boot's `ExitCodeGenerator` support, a failed job can make the JVM exit with a **non-zero exit code** — very useful for Kubernetes/cron scheduling where the orchestrator watches the exit status. (A short-lived batch app typically shuts the context down once the runner returns.) ## Re-run semantics on startup Every startup with the **same identifying parameters** targets the same `JobInstance`. If the previous run COMPLETED, the runner will hit `JobInstanceAlreadyCompleteException` — hence a common pattern is a `RunIdIncrementer` on the job or passing a unique parameter each launch, so repeated boots create new instances. ## Gotchas - Multiple `Job` beans without `spring.batch.job.name` set is the most common surprise — either nothing runs as expected or startup fails. Name the job explicitly. - The property is **`name` (singular) in Boot 3**, not the old plural `names`; copying a Boot 2 config forward silently does nothing. - Auto-run uses the **sync** launcher, so a long job delays application 'readiness' — fine for a job app, wrong for a web service that should stay up. - Disabling with `spring.batch.job.enabled=false` still leaves `JobLauncher`, `JobRepository`, etc. available for manual triggering — you keep the infrastructure, you just skip the startup call.
- You have two Job beans and only one runs (or startup fails). Why?Boot doesn't know which to auto-run. Set spring.batch.job.name (Boot 3) / spring.batch.job.names (Boot 2) to the intended job bean name.
- How do command-line arguments reach the job?JobLauncherApplicationRunner converts application args into JobParameters via a JobParametersConverter, so --runDate=... becomes an identifying parameter.
- How do you keep the batch infra but stop jobs firing at boot?Set spring.batch.job.enabled=false. JobLauncher/JobRepository stay available so you can trigger jobs manually from a controller or scheduler.
saying these in an interview costs you the question
- Saying jobs never run automatically in Boot.
- Using spring.batch.job.names in Boot 3 (renamed to name).
- Thinking @Scheduled is what auto-runs the job at startup (it's JobLauncherApplicationRunner).
- Assuming the auto-run is asynchronous.