✦ For everyone, free.

Practical knowledge for real and everyday life

Home

Kubernetes Job Completion Modes

Kubernetes Job Completion Modes define how Jobs finish, ensuring tasks run to completion in containerized environments.

Kubernetes Job Completion Modes is the classification of how a batch/v1 Job determines Pod identity and tracks progress toward completion, controlled by the .spec.completionMode field. This single field changes how the Job controller reasons about which units of work have finished, how Pods are able to distinguish themselves from their siblings, and what guarantees the Job makes about re-running work after a failure. Kubernetes defines two completion modes: NonIndexed and Indexed.

Choosing the correct completion mode is a foundational design decision for any batch workload, since it determines whether Pods can self-partition a larger task or must instead rely entirely on external coordination to avoid duplicating or skipping work.


NonIndexed Completion Mode

Behavior

NonIndexed is the default completion mode. Pods created by the Job are functionally interchangeable from the controller's point of view — each one simply counts as either a success or a failure, with no notion of which "slot" of work it represents. The Job is complete once the total number of successful Pods reaches .spec.completions.

When It Fits

NonIndexed mode fits workloads where any Pod can do any unit of remaining work, typically because the Pods coordinate through an external mechanism such as a message queue, a database-backed task table, or a shared work list. It also fits the simplest case of all: a Job with completions: 1, where there is only one unit of work and no partitioning is needed at all.

Limitation

Because Pods have no built-in identity, NonIndexed Jobs cannot statically assign a specific range of input (a file, a shard, a partition) to a specific Pod without additional external bookkeeping. The Pods themselves must implement whatever coordination is required to avoid two Pods processing the same item twice.


Indexed Completion Mode

Behavior

Indexed mode assigns each Pod a completion index, an integer from 0 to completions - 1. This index is injected into the Pod as the annotation batch.kubernetes.io/job-completion-index and is commonly surfaced to the application through an environment variable via fieldRef. The Job controller tracks completion per index, not just in aggregate — meaning it knows precisely which indices have succeeded and which still need to run or be retried.

Static Work Partitioning

Because each Pod knows its own index deterministically before it starts, Indexed mode allows the workload itself to statically compute which shard, offset, or file range it owns, without needing an external coordinator or shared queue. This is the pattern used for parallel data processing over pre-partitioned datasets, distributed machine learning training steps, and rendering pipelines that split frames across workers.

Independent Retry per Index

With backoffLimitPerIndex set, each index gets its own failure budget, so a transient failure on index 7 does not affect the retry accounting for any other index. This is a meaningful reliability improvement over NonIndexed mode for large fan-out Jobs, since one consistently failing shard does not need to consume the entire Job's shared backoff budget.

Pod Hostnames and Networking

Indexed Jobs can optionally set a subdomain and enable a headless Service association so that each Pod's hostname deterministically encodes its index (similar in spirit to StatefulSet Pod naming), which is useful for workloads where Pods need to address each other directly by index, such as certain distributed training topologies.


Choosing Between Modes

ConsiderationNonIndexedIndexed
Pod identityNoneDeterministic index per Pod
Work partitioningExternal (queue, DB)Static, computed from index
Per-unit retry isolationAggregate onlyOptional, per-index
Typical use caseQueue consumers, single-Pod JobsSharded batch processing, distributed compute

Example: Indexed Job

apiVersion: batch/v1
kind: Job
metadata:
  name: codartium-indexed-shards
spec:
  completions: 8
  parallelism: 4
  completionMode: Indexed
  backoffLimitPerIndex: 2
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: shard-worker
          image: codartium/shard-worker:latest
          env:
            - name: JOB_COMPLETION_INDEX
              valueFrom:
                fieldRef:
                  fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
          command: ["process-shard", "--index", "$(JOB_COMPLETION_INDEX)", "--total", "8"]
kubectl apply -f indexed-shards.yaml
kubectl get pods -l job-name=codartium-indexed-shards -L batch.kubernetes.io/job-completion-index
kubectl get job codartium-indexed-shards -o jsonpath='{.status.completedIndexes}'