Compare FlowStep and JobStep: what is the key difference, and how do you choose between them?
answer
- FlowStep = wrap Flow, same JobExecution
- JobStep = wrap Job, separate JobExecution
- JobStep needs JobLauncher + JobParametersExtractor
- FlowStep = lightweight step reuse
- JobStep = independent identity/restart boundary
basics
~20 sFlowStep 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 sBoth 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
Can state FlowStep wraps a Flow and JobStep wraps a Job.
Explains the same-execution vs separate-execution distinction and that JobStep needs a launcher and parameters extractor.
Chooses correctly based on identity/restart/parameter isolation needs and articulates the metadata/restart cost of JobStep.
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