skip to content

JobInstance vs JobExecution

A JobInstance is identified by the job name plus its identifying parameters, and each attempt to run it is a JobExecution. Interviewers ask why running the same job twice with the same parameters is refused — that identity rule is why.

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

explore

questions

5

In Spring Batch, what is the difference between a JobInstance and a JobExecution?

level: juniorimportance: must knowfreq 78%

answer

  1. Instance = logical run; Execution = one attempt
  2. Identity = job name + identifying params
  3. One instance -> many executions (restart)
  4. BATCH_JOB_INSTANCE vs BATCH_JOB_EXECUTION
  5. Completed instance -> AlreadyCompleteException

basics

~20 s

A JobInstance is a logical run of a job (job name + its identifying parameters). A JobExecution is a single attempt to run that instance. One JobInstance can have several JobExecutions if earlier attempts failed and were restarted.

solid answer

~40 s

A JobInstance represents the logical concept of a job run — it is identified by the job's name plus its identifying JobParameters (for example an 'end-of-day' job for date 2026-07-22). A JobExecution is one concrete attempt to run that JobInstance: it has a start time, end time, BatchStatus (STARTED, COMPLETED, FAILED) and ExitStatus. The relationship is one-to-many: a single JobInstance can own many JobExecutions. If the first attempt fails, restarting the same instance creates a second JobExecution against the same JobInstance, so the instance is 'run number N' while each execution is 'attempt M of that run'. Spring Batch persists both in its metadata tables (BATCH_JOB_INSTANCE, BATCH_JOB_EXECUTION) via the JobRepository.

code

java · 15 lines
java
// A JobExecution is what JobLauncher.run(...) returns.
// From it you can walk back to the owning JobInstance.
JobExecution execution = jobLauncher.run(endOfDayJob,
        new JobParametersBuilder()
                .addLocalDate("runDate", LocalDate.of(2026, 7, 22))
                .toJobParameters());

JobInstance instance = execution.getJobInstance();

System.out.println(instance.getJobName());        // "endOfDayJob"
System.out.println(instance.getInstanceId());     // logical run id (BATCH_JOB_INSTANCE)
System.out.println(execution.getId());            // this attempt's id (BATCH_JOB_EXECUTION)
System.out.println(execution.getStatus());        // BatchStatus, e.g. COMPLETED or FAILED
// If this attempt failed and we relaunch with the SAME runDate,
// Spring Batch reuses `instance` and creates a NEW JobExecution.

go deeper

for a junior

Must nail the one-line distinction: instance = logical run, execution = one attempt, one-to-many on restart.

for a middle

Should name the metadata tables and know restart reuses the instance and adds an execution.

for a senior

Should connect the distinction to restartability, ExecutionContext reuse, and the JobRepository/JobLauncher flow.

for a principal

Should reason about identity as the contract that makes idempotency and audit possible, and its operational consequences.

## The two core domain objects Spring Batch models a batch job with a small set of domain objects. The two most fundamental are **`JobInstance`** and **`JobExecution`**, and confusing them is the single most common Spring Batch mistake. ### JobInstance = a logical run A **`JobInstance`** represents the *logical* notion of 'this job, run for this input'. It is uniquely identified by: 1. the **job name** (the `Job` bean's name), and 2. the **identifying `JobParameters`** for that run. Example: an end-of-day settlement job that runs once per business day. The run for `2026-07-21` and the run for `2026-07-22` are **two different `JobInstance`s**, because their identifying parameter (the date) differs. Think of a `JobInstance` as answering *'which run is this?'*. It is stored in the **`BATCH_JOB_INSTANCE`** table. > Note: *which* parameters count toward identity (identifying vs non-identifying `JobParameters`) is governed by a separate mechanism covered elsewhere. Here it is enough to know that identity = job name + identifying parameters. ### JobExecution = one attempt A **`JobExecution`** represents a *single attempt* to run a `JobInstance`. It carries the runtime state of that attempt: - **`BatchStatus`** — an enum: `STARTING`, `STARTED`, `STOPPING`, `STOPPED`, `FAILED`, `COMPLETED`, `ABANDONED`. - **`ExitStatus`** — a richer exit code (e.g. `COMPLETED`, `FAILED`, or a custom string) usable for flow decisions. - `startTime`, `endTime`, `createTime`, `lastUpdated`. - A list of **`StepExecution`s** (one per step attempt). - An **`ExecutionContext`** (key/value state persisted for restart). - A reference back to its `JobInstance`. It is stored in the **`BATCH_JOB_EXECUTION`** table, with a foreign key to `BATCH_JOB_INSTANCE`. ### The one-to-many relationship One `JobInstance` can have **many** `JobExecution`s. This happens on **restart**: 1. You launch the end-of-day job for `2026-07-22`. A `JobInstance` is created, and a first `JobExecution` starts. 2. It **fails** halfway (DB outage). That `JobExecution` ends with `BatchStatus.FAILED`. 3. You relaunch with the **same** identifying parameters. Spring Batch finds the **existing** `JobInstance` (identity matches) and creates a **new, second** `JobExecution` to retry — reusing the persisted `ExecutionContext` so restartable steps can resume. So: `JobInstance` = 'the run', `JobExecution` = 'attempt #N of the run'. ### Why the distinction matters - **Restartability**: Spring Batch can only resume a run if it can identify the same `JobInstance` and find its prior failed `JobExecution` and saved context. - **Preventing duplicate work**: if a `JobInstance` already `COMPLETED`, relaunching it with identical identifying parameters throws **`JobInstanceAlreadyCompleteException`** — you cannot silently re-run yesterday's completed settlement. - **Auditing**: the metadata tables give you a full history — every attempt (`JobExecution`) grouped under its logical run (`JobInstance`). ### Who creates them The **`JobRepository`** persists both. The **`JobLauncher`** (via `run(Job, JobParameters)`) asks the repository for the matching `JobInstance` (creating one if none exists), then creates a fresh `JobExecution`, and runs it. ### Common gotchas - Relaunching with the *exact same* identifying parameters does **not** create a new `JobInstance` — it targets the existing one (and may throw if it already completed). To get a brand-new run, an **identifying parameter must change** (a common trick is a `RunIdIncrementer` or a timestamp). - `StepExecution` belongs to a `JobExecution`, not directly to a `JobInstance`. - `BatchStatus` (framework enum) and `ExitStatus` (flow-control code) are different things and live on the `JobExecution`/`StepExecution`.

  • If a job's first execution fails and you restart it, how many JobInstances and JobExecutions exist?
    One JobInstance (identity unchanged) and two JobExecutions — the failed attempt and the restart attempt, both linked to that single instance.
  • Which object holds the BatchStatus and StepExecutions — JobInstance or JobExecution?
    JobExecution. The JobInstance is just the logical identity; runtime status, timing, StepExecutions and the ExecutionContext all live on the JobExecution.

saying these in an interview costs you the question

  • Saying JobInstance and JobExecution are the same thing or interchangeable
  • Claiming each restart creates a new JobInstance
  • Putting BatchStatus/StepExecutions on the JobInstance instead of the JobExecution

context

open as a page

What determines whether launching a job creates a new JobInstance or reuses an existing one?

level: middleimportance: must knowfreq 66%

basics

~20 s

The job name plus its identifying JobParameters. If that combination has been seen before, Spring Batch reuses the existing JobInstance; if it is new, it creates a new one. Same job + same identifying params = same instance.

open as a page

Where do StepExecution and the ExecutionContext live relative to JobInstance and JobExecution, and why does it matter?

level: middleimportance: should knowfreq 40%

basics

~20 s

StepExecutions and the ExecutionContext belong to a JobExecution, not directly to the JobInstance. Each run attempt has its own StepExecutions and context. Because there can be many JobExecutions per instance, each attempt gets a fresh set.

open as a page

Walk through what happens to JobInstance and JobExecution across a failure and a restart, including the metadata.

level: seniorimportance: should knowfreq 52%

basics

~20 s

The first launch creates one JobInstance and a JobExecution that fails. On restart with the same identifying parameters, Spring Batch reuses the JobInstance, creates a second JobExecution, and resumes using the persisted ExecutionContext. Now the instance has two executions.

open as a page

Why did Spring Batch split the run concept into JobInstance and JobExecution instead of a single object, and what does that buy an operator?

level: principalimportance: nice to knowfreq 30%

basics

~10 s

Separating 'the logical run' (JobInstance) from 'each attempt' (JobExecution) lets Spring Batch guarantee a run happens once while still allowing many retry attempts. It enables restartability, idempotency, per-attempt metrics, and a clean audit history.

open as a page