Skip to content

CONCEPT Cited by 1 source

numHistoryShards immutability

numHistoryShards is the shard count of Temporal's History subsystem — the value that determines how many partitions Temporal will hash workflows across. It is immutable after the initial cluster deployment. "The configured value assigned in this step directly impacts the system's throughput, latency, and resource utilization. Getting this configuration right for your setup and performance targets is essential for production, and the value is immutable after the initial cluster deployment. You must set this value high enough to scale with this Cluster's worst-case peak load" (Source: sources/2026-04-21-planetscale-temporal-workflows-at-scale-sharding-in-production).

The one-way door

Most sharded-storage systems treat shard count as a runtime-mutable dimension: Vitess Reshard can grow 1→4→8→16 shards online; Dynamo-family systems split ranges transparently; TAO re-partitions on the fly. Temporal's numHistoryShards does not have this property. The shard-id hash is baked into Temporal's code path — every workflow that exists in the cluster has a workflow_id → shard_id mapping computed at creation time. Changing numHistoryShards would re-hash every existing workflow to a different shard, invalidating all in-flight history replay.

The upshot: numHistoryShards is a worst-case-sizing decision you make once, at cluster creation time. Get it wrong low and you hit the single-shard throughput ceiling with no way to escape except migrating workflows to a new cluster.

Why the value can't just be changed

Temporal's serialise-per-shard discipline requires that the History subsystem hold a single-writer lock per shard. If numHistoryShards changed from N to M mid-cluster, existing workflows' shard_id = hash(workflow_id) mod N addresses would no longer match the M-shard topology — and the shard-ownership locks would be meaningless. Fixing this requires re-hashing every workflow, which means reading every live event history, re-writing it under the new shard, and updating the in-memory state held by every History process. None of this can happen online without stopping all workflows first.

Sizing guidance

Longoria's rule: "You must set this value high enough to scale with this Cluster's worst-case peak load." In practice this means:

  1. Measure (or estimate) peak persistence-layer latency under worst-case load.
  2. Compute the single-shard ceiling: 1 / latency.
  3. Divide the worst-case target QPS by the single-shard ceiling to get minimum shard count.
  4. Multiply by a safety factor (3×–5× is common in public guidance — see the Shilkov 2021 sizing post referenced in Part 1) to allow headroom for:
  5. Traffic growth between deploy and reshard-forced migration
  6. Skew in hash(workflow_id) distribution
  7. Cold-start spikes when the cluster restarts
  8. Deploy.

Distinction from storage-layer shard count

numHistoryShards (Temporal) and Vitess shard count (storage) are independent knobs:

Knob Mutable? What it partitions
numHistoryShards No (cluster-lifetime immutable) Temporal workflows across History processes
Vitess shard count Yes (online via Reshard) MySQL rows across MySQL primaries

A Temporal cluster running on a sharded Vitess backing store has both — and changing the Vitess shard count is safe (resharding is online, doesn't touch Temporal's hash function); changing numHistoryShards is not. Operators should treat the two as separate capacity-planning exercises: Vitess shard count sized for data volume + IOPS cost; numHistoryShards sized for peak operation rate.

Contrast with other sharded systems

  • Vitess numShards: mutable online via Reshard + VReplication + SwitchTraffic. No workflow state is embedded in the shard mapping.
  • Cassandra virtual nodes (vnodes): mutable via nodetool repair/rebalance.
  • Elasticsearch number_of_shards: immutable per index, but indices can be split (_split API) or re-indexed into a new index with a different shard count.
  • Temporal numHistoryShards: immutable per cluster; requires new cluster + workflow migration to change. Closest peer is Kafka topic num.partitions (immutable; increasing partitions doesn't re-hash existing messages) — but Kafka partitions less-strictly constrain correctness than Temporal shards.

Seen in

Last updated · 550 distilled / 1,221 read