Skip to main content
Output workers run workflows and activities through Temporal. These settings control compute, memory, and IO behavior:
  • Compute: how many Workflow and Activity Tasks can execute concurrently.
  • Memory: how many Workflow Executions stay in the sticky cache.
  • IO: how many pollers long-poll Temporal for new tasks.
Start with the defaults. Tune only when you see backlog in Temporal, high memory use, underused CPU, or task timeouts.

Concurrency and Polling

These env vars map to Temporal worker execution slots, cache, and pollers. See Temporal’s Worker performance guide, Worker tuning quick reference, and WorkerOptions.
VariableDefaultResourceEffect
TEMPORAL_MAX_CONCURRENT_ACTIVITY_TASK_EXECUTIONS40ComputeMaximum Activity Task executions running at once. Each Output step, evaluator, LLM call wrapper, or API call is usually an activity. Raise this to process more activities concurrently; lower it to reduce memory, CPU, or outbound API pressure.
TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASK_EXECUTIONS200ComputeMaximum Workflow Task executions running at once. Workflow Tasks are usually lightweight state-machine work. Raise this if Workflow Task backlog grows and CPU is low; lower it if Workflow Task timeouts increase.
TEMPORAL_MAX_CACHED_WORKFLOWS1000MemoryMaximum Workflow Executions kept in Temporal’s sticky workflow cache. Higher values reduce workflow replay work; lower values free memory sooner after traffic spikes.
TEMPORAL_MAX_CONCURRENT_ACTIVITY_TASK_POLLS5IONumber of concurrent Activity Task pollers. Raise this if activity execution slots are available but the worker is not fetching tasks fast enough. Keep it lower than activity execution slots.
TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASK_POLLS5IONumber of concurrent Workflow Task pollers. Raise this if workflow execution slots are available but polling is the bottleneck. Keep it lower than workflow execution slots.
Example:
TEMPORAL_MAX_CONCURRENT_ACTIVITY_TASK_EXECUTIONS=150
TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASK_EXECUTIONS=600
TEMPORAL_MAX_CACHED_WORKFLOWS=50
TEMPORAL_MAX_CONCURRENT_ACTIVITY_TASK_POLLS=10
TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASK_POLLS=10

Worker Tuner

TEMPORAL_WORKER_TUNER accepts a JSON-encoded Temporal WorkerOptions.tuner. Use it when fixed concurrency limits are too rigid and you want Temporal’s slot suppliers to control how many tasks the worker accepts. Resource-based auto-tuning is most useful for avoiding out-of-memory failures and absorbing bursts of low-resource work, such as Activities that spend most of their time waiting on external HTTP or I/O. Temporal recommends validating it by monitoring host CPU and memory under full load and confirming they settle near your configured targets. See Temporal’s resource-based auto-tuning announcement for the model behind the feature. Choose exactly one tuner shape:
  • Resource-based tuner: one set of tunerOptions, plus optional *SlotOptions.
  • Mixed slot suppliers: one *SlotSupplier object for each task type.
Do not mix tunerOptions / *SlotOptions with *SlotSupplier fields in the same JSON object. When TEMPORAL_WORKER_TUNER is set, Output passes it to Temporal as tuner and does not pass these incompatible execution options:
  • TEMPORAL_MAX_CONCURRENT_ACTIVITY_TASK_EXECUTIONS
  • TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASK_EXECUTIONS
Polling and cache settings still apply:
  • TEMPORAL_MAX_CONCURRENT_ACTIVITY_TASK_POLLS
  • TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASK_POLLS
  • TEMPORAL_MAX_CACHED_WORKFLOWS

Resource-Based Tuner

Use a ResourceBasedTuner to let Temporal adjust slots based on target CPU and memory usage. This is the simpler tuner shape. You can provide only workflow and activity slot options; Temporal applies defaults for local activity and Nexus slots.
TEMPORAL_WORKER_TUNER='{
  "tunerOptions": {
    "targetMemoryUsage": 0.8,
    "targetCpuUsage": 0.9
  },
  "workflowTaskSlotOptions": {
    "minimumSlots": 2,
    "maximumSlots": 1000,
    "rampThrottle": "10ms"
  },
  "activityTaskSlotOptions": {
    "minimumSlots": 1,
    "maximumSlots": 100,
    "rampThrottle": "50ms"
  }
}'
Resource-based fields:
FieldEffect
targetMemoryUsageTarget process memory usage as a fraction from 0 to 1.
targetCpuUsageTarget process CPU usage as a fraction from 0 to 1.
minimumSlotsSlots issued regardless of current resource checks.
maximumSlotsUpper bound for slots of that task type.
rampThrottleMinimum delay before issuing another slot after minimumSlots is reached.

Mixed Slot Suppliers

Use a TunerHolder to choose a slot supplier per task type. This is useful when workflow tasks should remain fixed but activities should scale with CPU and memory.
TEMPORAL_WORKER_TUNER='{
  "workflowTaskSlotSupplier": {
    "type": "fixed-size",
    "numSlots": 10
  },
  "activityTaskSlotSupplier": {
    "type": "resource-based",
    "tunerOptions": {
      "targetMemoryUsage": 0.8,
      "targetCpuUsage": 0.9
    },
    "minimumSlots": 1,
    "maximumSlots": 100,
    "rampThrottle": "50ms"
  },
  "localActivityTaskSlotSupplier": {
    "type": "fixed-size",
    "numSlots": 10
  },
  "nexusTaskSlotSupplier": {
    "type": "fixed-size",
    "numSlots": 10
  }
}'
When using the per-task supplier form, Temporal requires all four supplier fields: workflowTaskSlotSupplier, activityTaskSlotSupplier, localActivityTaskSlotSupplier, and nexusTaskSlotSupplier. Omitting local activity or Nexus suppliers can fail worker startup.
Supplier types:
TypeFieldsEffect
fixed-sizenumSlotsAlways allows up to a fixed number of slots for that task type.
resource-basedtunerOptions, minimumSlots, maximumSlots, rampThrottleDynamically adjusts slots based on CPU and memory targets.
Temporal also supports custom slot suppliers in code, but TEMPORAL_WORKER_TUNER is JSON and should be used only for fixed-size and resource-based suppliers.

What to Watch

Use Temporal metrics before changing values. The main question is whether the worker has no execution capacity left, or whether it has capacity but is not polling fast enough. See Temporal’s SDK metrics reference, Worker health, and performance bottlenecks guide.
SignalMeaningTuning response
High temporal_workflow_task_schedule_to_start_latency or temporal_activity_schedule_to_start_latencyTasks are waiting in the queue before a worker starts them.Check slots, pollers, worker count, and host CPU/memory.
temporal_worker_task_slots_available near zeroWorker execution slots are full.Increase execution slots, add workers, or use resource-based slots if host resources are available.
High schedule-to-start latency while slots are often availableThe worker may not be polling fast enough.Increase the matching poller count.
High host memoryWorker process or workflow cache is too large for the host.Lower activity slots, lower TEMPORAL_MAX_CACHED_WORKFLOWS, or use a resource-based tuner with a lower targetMemoryUsage.
Low CPU/memory with growing backlogThe worker has host capacity but is not accepting enough work.Raise execution slots, raise pollers, or add resource-based activity slots with a higher maximumSlots.

Choosing Values

If memory is high, lower activity slots first. Activities usually hold network responses, LLM payloads, browser state, or other heavier objects. If Temporal shows activity backlog and the worker has spare CPU and memory, raise activity execution slots or use a resource-based tuner with a higher maximumSlots. If workflow task backlog grows while CPU is low, check temporal_worker_task_slots_available first. If workflow slots are depleted, raise workflow task execution slots. If slots are available but schedule-to-start latency is high, raise workflow task pollers. If workflow task timeouts increase, lower workflow task execution slots. If CPU and memory vary heavily by workload, prefer TEMPORAL_WORKER_TUNER with resource-based activity slots over a large fixed activity concurrency. Tune incrementally and load test before applying large production changes. Temporal’s Introduction to Worker Tuning is a good overview of when to scale workers horizontally versus increasing per-worker slots or pollers.