# Social Graph Follows And FlockDB
Follow/follower storage looks like a graph problem, but not every graph-shaped problem needs a general graph database.
For Twitter-style follows, the hot operations are shallow adjacency-list reads:
- who do I follow?
- who follows me?
- does A follow B?
- page through millions of followers,
- count followers/following.
Deep traversal is not the main requirement.
## Day-Zero Relational Model
```text
relations(
from_user_id,
to_user_id,
relation_type,
state,
created_at
)
```
Use a generic table name like `relations` rather than `follows` if the product is likely to add:
- close friends,
- blocks,
- mutes,
- favorites,
- groups,
- follow requests.
Generic does not mean vague. It means the table represents a product abstraction broader than one current button.
## Why Sharding Breaks The Naive Query
If data is sharded by `from_user_id`, this is local:
```sql
select * from relations
where from_user_id = :me and relation_type = 'follows';
```
But this can scatter across every shard:
```sql
select * from relations
where to_user_id = :me and relation_type = 'follows';
```
The destination user could appear in rows whose sources live on many shards.
## FlockDB Trick: Store Reverse Edges
For one follow action:
```text
A follows B
B is_followed_by A
```
Now both reads are source-local:
```sql
-- who do I follow?
where source_id = A and relation = 'follows'
-- who follows me?
where source_id = A and relation = 'is_followed_by'
```
```mermaid
flowchart LR
Action[A follows B] --> Edge1[A -> B : follows]
Action --> Edge2[B -> A : is_followed_by]
```
The system pays 2x edge writes/storage to avoid scatter-gather reads. For social products, that is usually a good trade because reads dominate and follower-list reads must paginate predictably.
If A and B follow each other, there are four rows:
- A follows B,
- B is_followed_by A,
- B follows A,
- A is_followed_by B.
## Edge Shape
The FlockDB-style edge includes:
```text
source_id
destination_id
state
position
metadata
```
`position` is used for ordering and pagination. It can be a timestamp, sequence, rank, or affinity score depending on the product read.
## Pagination
Use keyset-style pagination by `position`, not `limit offset`.
```text
give me next N edges after position P
```
This keeps page N roughly as efficient as page 1 and avoids deep-offset scans.
## What FlockDB Is Not
FlockDB is not optimized for arbitrary graph walking:
- friends of friends of friends,
- shortest paths,
- community detection,
- centrality algorithms,
- large offline recommendations.
Use separate graph analytics / recommendation pipelines for those. The online follow graph should serve hot product reads cheaply.
## Hot Celebrity Shards
Celebrity accounts can concentrate edges and reads. Mitigations:
- assign high-fanout users to isolated shards,
- split celebrity follower lists by bucket,
- cache first pages aggressively,
- separate exact source-of-truth edges from public count/read models,
- precompute notification/fanout batches.
## Useful References
- [Twitter/X Engineering: Introducing FlockDB](https://blog.x.com/engineering/en_us/a/2010/introducing-flockdb)
- [twitter-archive/flockdb](https://github.com/twitter-archive/flockdb)
- [WTF: The Who to Follow Service at Twitter](https://archives.iw3c2.org/www2013/proceedings/p505.pdf)