Skip to main content

Classic design · Mid

Distributed counter (celebrity likes and views)

Classic interview design. Key points: hot key and sharded counters, and job scheduling.

14 min read · Content reviewed on October 23, 2026

Short answer

Classic interview design. Key points: hot key and sharded counters, and job scheduling. A post's like counter is the example Firestore's own documentation uses for documents that work as counters, alongside an item's favorites.

01 · THE PROBLEM

A number everyone increments

A post's like counter is the example Firestore's own documentation uses for documents that work as counters, alongside an item's favorites.

The limit shows up when the counter is a single document. In Firestore you cannot update a single document at an unlimited rate and, with frequent enough increments, contention arises on that document's updates.

  1. Each like reaches the likes API.

    Architecture diagram: Counter in a single document
    CLUsers
    CPLikes API
    DBCounter document
  2. The API increments a single document, which holds the counter's value.

    Architecture diagram: Counter in a single document
    CLUsers
    CPLikes API
    DBCounter documentsingle counter
  3. When the increments become frequent enough, updates to that document start competing with each other.

    Architecture diagram: Counter in a single document
    CLUsers
    CPLikes API
    DBCounter documentcontention
  4. Under high, sustained volume of concurrent operations, the single document can become a hot spot.

    Architecture diagram: Counter in a single document
    CLUsers
    CPLikes API
    DBCounter documenthot spot

The scaling documentation describes the same hot spot: high, sustained volumes of concurrent operations on a single document can cause a hot spot on it, and the recommendation is to change the data model to split or replicate the data across multiple documents.

02 · SHARDING THE COUNTER

Many documents, one sum

The documentation's solution is the distributed counter: each counter is a document with a subcollection of shards, and the counter's value is the sum of the shards' values. It is the idea of sharding the write applied to a single number.

  1. Each like reaches the likes API, as before.

    Architecture diagram: Sharded counter
    CLUsers
    CPLikes API
    DBFragmento A
    DBFragmento B
    DBFragmento C
  2. To record the like, the API picks a random shard and increments only that one.

    Architecture diagram: Sharded counter
    CLUsers
    CPLikes API
    DBFragmento A
    DBFragmento Bonly this one
    DBFragmento C
  3. The next like picks another shard, and the writes are spread across different documents.

    Architecture diagram: Sharded counter
    CLUsers
    CPLikes API
    DBFragmento Aanother draw
    DBFragmento B
    DBFragmento C
  4. The counter's value is the sum of the shards' values.

    Architecture diagram: Sharded counter
    CLUsers
    CPLikes API
    DBFragmento A
    DBFragmento B
    DBFragmento C
  5. Write throughput grows linearly with the number of shards.

    Architecture diagram: Sharded counter
    CLUsers
    CPLikes API
    DBFragmento A
    DBFragmento B
    DBFragmento Cmore capacity

To increment, a random shard is chosen. Write throughput grows linearly with the number of shards: a distributed counter with 10 shards supports 10 times more writes than a traditional counter. In the documentation's code example, each shard can be incremented once per second, which is why several shards are needed to allow more frequent increments.

03 · THE PRICE OF READING

Sharding pushes the cost onto the reader

The documentation points out the cost of the number of shards. With few shards, some transactions have to retry before succeeding and writes get slower; with too many shards, reads get slower and more expensive.

Reading the value costs more with each added shard: read cost grows linearly with the number of shards, because the entire subcollection of shards has to be loaded.

In practice, this becomes a sizing question: how much write traffic the counter gets and how much it is read.

04 · CONSOLIDATED TOTAL AND JOBS

Reading a ready-made number

One way to offset the read cost is to keep the total in a separate total document, updated at a slower cadence, and have clients read that document. The tradeoff is that clients have to wait for that document to be updated, instead of computing the total by reading all the shards right after each update.

  1. Likes keep going to the shards, as before.

    Architecture diagram: Shards with a total document
    CLUsers
    CPLikes API
    DBFragmento A
    DBFragmento B
    CPConsolidation job
    DBTotal document
    CPRead API
  2. Reading the value by summing the shards requires loading the whole subcollection, and the cost grows linearly with their number.

    Architecture diagram: Shards with a total document
    CLUsers
    CPLikes API
    DBFragmento Aexpensive read
    DBFragmento Bexpensive read
    CPConsolidation job
    DBTotal document
    CPRead API
  3. The total document is updated at a slower cadence than the writes; in this design, the consolidation job does that.

    Architecture diagram: Shards with a total document
    CLUsers
    CPLikes API
    DBFragmento A
    DBFragmento B
    CPConsolidation jobsums and writes
    DBTotal documenttotal
    CPRead API
  4. Clients read the total from that document, instead of summing the shards.

    Architecture diagram: Shards with a total document
    CLUsers
    CPLikes API
    DBFragmento A
    DBFragmento B
    CPConsolidation job
    DBTotal documentcheap read
    CPRead API
  5. The tradeoff is waiting for the total document to be updated, instead of computing the total right after each update.

    Architecture diagram: Shards with a total document
    CLUsers
    CPLikes API
    DBFragmento A
    DBFragmento B
    CPConsolidation job
    DBTotal documentwaits for the update
    CPRead API
AspectoSum of the shardsTotal document
How the value is obtainedSum of all shards on every queryThe client reads the total document
Read costGrows linearly with the number of shardsOffsets the read cost of the shards
Total freshnessComputed right after each updateThe client waits for the total document to be updated

A scheduled job is a natural way to implement this slower cadence. The interval between runs is a product decision: how stale the number can appear to the reader. The total now converges to the sum of the shards with a delay, a typical tradeoff of eventual consistency.

05 · ALTERNATIVES AND WRAP-UP

Shard, replicate, or increment in memory

Firestore in Datastore mode documentation points to two ways out: use sharding or replication to handle hot spots. Replication keeps N copies of the same entity and allows a read rate N times higher; sharding is for writing at a higher rate and breaks the entity into smaller pieces.

Outside Firestore, the Redis counter pattern uses atomic increment operations: the idea is to send an INCR command to Redis on every operation.

Frequently asked questions

What is Distributed counter (celebrity likes and views)?

Classic interview design. Key points: hot key and sharded counters, and job scheduling.

What does the Distributed counter (celebrity likes and views) design cover?

It is organized in these sections: A number everyone increments, Many documents, one sum, Sharding pushes the cost onto the reader, Reading a ready-made number, and Shard, replicate, or increment in memory.

How long is Distributed counter (celebrity likes and views) and what level is it?

It takes about 14 minutes to read and is rated Mid level.

Now design it yourself

Run this case as an interview in the System Design school: you make the decisions, the tutor challenges them and you see how your design scores.