skip to content

Flows & Nested Jobs

Flows can be defined once and reused, wrapped as a step, or a whole child job can be nested inside a parent. Interviewers ask about composition when a suite of jobs shares the same preparation and cleanup.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

5

Compare FlowStep and JobStep: what is the key difference, and how do you choose between them?

level: middleimportance: must knowfreq 48%

answer

  1. FlowStep = wrap Flow, same JobExecution
  2. JobStep = wrap Job, separate JobExecution
  3. JobStep needs JobLauncher + JobParametersExtractor
  4. FlowStep = lightweight step reuse
  5. JobStep = independent identity/restart boundary

basics

~20 s

FlowStep wraps a Flow and runs its steps inside the current job execution. JobStep wraps a whole Job and launches it as a separate execution with its own parameters and identity. Use FlowStep to reuse steps; use JobStep to nest an independent job.

solid answer

~40 s

Both adapt something into a `Step`, but at different granularity. `FlowStep` (`StepBuilder.flow(flow)`) wraps a `Flow`: its inner steps execute within the **current `JobExecution`**, sharing the parent's identity, parameters, and restart boundary — it is just modular reuse of step-wiring. `JobStep` (`StepBuilder.job(childJob)`) wraps a whole `Job`: it uses a `JobLauncher` to run the child as a **separate `JobExecution`/`JobInstance`**, with its own parameters supplied by a `JobParametersExtractor`, its own metadata rows, and its own restart boundary. Choose `FlowStep` when you only need to reuse a coherent sub-sequence of steps as a unit inside one job. Choose `JobStep` when the child is (or should be) an independently runnable, independently parameterized, independently restartable job that you also want to orchestrate from a parent. JobStep is heavier and introduces cross-instance restart reasoning and the duplicate-parameter pitfall.

go deeper

for a junior

Can state FlowStep wraps a Flow and JobStep wraps a Job.

for a middle

Explains the same-execution vs separate-execution distinction and that JobStep needs a launcher and parameters extractor.

for a senior

Chooses correctly based on identity/restart/parameter isolation needs and articulates the metadata/restart cost of JobStep.

for a principal

Considers operational trade-offs — monitoring, restart surface, and whether orchestration should even live inside batch versus an external scheduler.

## Same shape, different weight Both `FlowStep` and `JobStep` implement the `Step` interface so they can slot into a job, but they wrap different things and have very different runtime semantics. ### FlowStep — reuse step-wiring - Built with **`StepBuilder.flow(Flow)`**. - Wraps a **`Flow`** (a graph of steps). - Inner steps run as **normal steps of the current `JobExecution`** — same job instance, same parameters, same restart boundary. - No `JobLauncher`, no `JobParametersExtractor`. - Lightweight; it is essentially "treat this sub-flow as one branching unit." ### JobStep — nest a whole job - Built with **`StepBuilder.job(Job)`** plus **`.launcher(JobLauncher)`** and usually **`.parametersExtractor(...)`**. - Wraps a **`Job`**. - Launches the child so it gets its **own `JobInstance`/`JobExecution`**, own metadata, own restart boundary. - Child parameters come from a **`JobParametersExtractor`** (they are not inherited automatically). - Heavier; introduces cross-instance identity and the `JobInstanceAlreadyCompleteException` pitfall on duplicate identifying parameters. ## Decision table | Question | Use FlowStep | Use JobStep | |---|---|---| | Need to reuse a *sequence of steps* as a unit? | Yes | — | | Child must be *independently runnable* as its own job? | — | Yes | | Need *separate parameters* for the nested unit? | — | Yes (extractor) | | Want a *separate restart/identity boundary*? | — | Yes | | Want the lightest option, same execution? | Yes | — | ## Practical guidance - Prefer **FlowStep** by default for intra-job modularity — it is simpler and keeps everything under one execution for easy monitoring and restart. - Reach for **JobStep** when you already have (or need) a standalone job that must also participate in a larger orchestration, or when you genuinely need the child to have its own parameterization/identity. Be deliberate: it doubles the metadata/restart surface. - Neither is about parallelism — running steps concurrently is a split concern, separate from these composition adapters. ## Common mistake Candidates often conflate the two and claim FlowStep launches a separate job or that JobStep shares the parent execution. The single most important distinguishing fact: **FlowStep = same JobExecution; JobStep = separate child JobExecution.**

  • Which one requires a JobParametersExtractor, and why?
    JobStep. Because the child runs as a separate job, its parameters are not inherited; the extractor derives them from the parent step/job execution context. FlowStep shares the parent execution, so no extractor is needed.
  • You have an existing standalone reconciliation Job you now want to run as part of a nightly master job. Which adapter fits?
    JobStep — it lets the existing Job run as a step while keeping its own identity, parameters, and restart boundary. FlowStep only reuses step-wiring within one execution.

saying these in an interview costs you the question

  • Saying FlowStep launches a separate JobExecution
  • Saying JobStep runs under the parent's JobExecution
  • Thinking either adapter is about parallel execution

context

open as a page

Explain JobStep: how do you nest a child Job inside a parent job, and how are the child's JobParameters supplied?

level: seniorimportance: must knowfreq 50%

basics

~20 s

JobStep is a Step that launches a whole child Job. You build it with StepBuilder.job(childJob), give it a JobLauncher, and a JobParametersExtractor that pulls the child's JobParameters from the parent step/job execution context. The child runs as its own separate JobExecution.

open as a page

What is a reusable Flow in Spring Batch, and how do you build one and plug it into a Job?

level: juniorimportance: should knowfreq 45%

basics

~10 s

A Flow is a named, reusable sequence of steps with transitions. You build one with FlowBuilder<Flow>().start(stepA).next(stepB).build(), then start a Job from it with JobBuilder.start(flow).end().build().

open as a page

What is FlowStep, and when would you wrap a Flow as a single Step inside a job?

level: middleimportance: should knowfreq 40%

basics

~20 s

FlowStep turns a whole Flow into one Step. You build it with StepBuilder.flow(flow). The flow's inner steps run as normal within the same job execution, but the outer job sees them grouped as a single named step.

open as a page

In a production design, when is JobStep-based nested-job composition appropriate, and what identity/restart pitfalls must you guard against?

level: principalimportance: should knowfreq 30%

basics

~20 s

Use JobStep to orchestrate independently-runnable child jobs from a parent. Guard against duplicate identifying parameters (JobInstanceAlreadyCompleteException), reason about two separate restart boundaries, ensure the extractor forwards a unique run id, and confirm the launcher/isolation model fits.

open as a page