Social network scaling
Social network scaling and launch checklist
A social network stays fast by paginating every list, indexing the main questions, and deferring heavy work until a measured trigger fires. At launch, apply 12 rules, watch 10 signals and hold the performance targets below.
Last checked
Rules to apply at launch
- Pagination: Every list (home timeline, profile posts, replies, followers, likes, notifications, inbox, thread, search) uses keyset pagination on an indexed (sort_key, id) tuple; no OFFSET, page size capped at 30-50, cursors are opaque and signed.
- Fanout: Hybrid timeline: push (timeline_entries) for authors under FANOUT_CELEBRITY_THRESHOLD followers, pull for celebrities merged at read time from a capped set of <= 200 followed celebrities. Fan-out is a queued, resumable, batched job, never inline in the post request, and per-post write volume is capped.
- Data growth: timeline_entries is hash partitioned by user_id and trimmed to the newest TIMELINE_MAX_ENTRIES per user; deep history beyond the cap is served by pull (author index) and is never precomputed. Dormant users (no activity in 30 days) are skipped on push and rebuilt lazily on their next visit.
- Fanout: No hot rows: engagement counters are sharded (default 16 shards, raised per hot post) and rolled up by cron into post_counters, the only table read on the request path. Likes are idempotent by unique (user_id, post_id), so retries and double taps never inflate counts.
- Caching: Timeline pages are hydrated in batch: one query for posts by id array, one for authors, one for counters, one for 'liked by me'; <= 6 queries per page regardless of page size, no N+1.
- Cdn: Image variants are generated once at upload by a batch job, stored under immutable content-addressed keys with Cache-Control: public, max-age=31536000, immutable, and served from the edge; there are no per-request transforms (they are a per-use billable surprise). Responsive srcset with stored width/height and blurhash.
- Idempotency: Post creation takes a client idempotency key; likes, follows, reports, blocks, timeline entries, hashtag links and DMs (sender_id, client_msg_id) are idempotent by natural unique keys, so retries and replays are safe.
- Rate limits: Per-user and per-IP limits on post, reply, like, follow, DM, report, search and upload-presign, scaled by account age and trust tier; new accounts start at roughly 20% of the limits. Over-limit requests are refused with 429 and Retry-After, never queued.
- Search: Posts use tsvector + GIN; people and tags use trigram GIN; results are keyset paginated and capped at 100 candidates per query. A dedicated search engine is deferred until the stated trigger.
Performance targets
| What to measure | Target |
|---|---|
| Home timeline API (30 posts hydrated) | p95 < 250 ms, <= 6 queries, zero N+1 |
| Post create to visible to followers (non-celebrity, under 5k followers) | p95 < 5 s via fan-out job; author sees own post immediately |
| Like/unlike | p99 < 100 ms, 2 statements, no row-level lock wait on viral posts |
| Profile and permalink page LCP | < 2.5 s; TTFB < 200 ms from edge cache for logged-out viewers |
| Image delivery | edge cache hit ratio > 95%; thumbnail bytes < 60 KB at 640 w WebP |
| Search (people/posts/tags) | p95 < 300 ms, keyset paginated, <= 100 candidates |
| Notification badge and inbox | p95 < 120 ms |
| Fan-out throughput | >= 5,000 timeline rows per second per worker; fan-out queue age p95 < 30 s |
What to watch
- Metric timeline latency ms: histogram for /api/timeline split by push-only vs push+celebrity-pull; the core read number.
- Metric fanout queue depth and age: oldest queued fanout_post age and rows written per second; drives the fan-out alert.
- Metric counter rollup lag s: age of the stalest hot post_counters row.
- Metric cdn cache hit ratio: image and permalink hit ratio at the edge; a drop signals a cache-key or TTL regression.
- Metric moderation queue age: oldest unreviewed report; reports per 1k posts.
- Metric rate limit rejections: 429s by action and trust tier; spikes indicate a bot wave or a too-tight limit.
- Log structured request, fan-out and moderation logs: request id, hashed user id, post id, job id; no DM bodies, tokens or signed URLs.
- Trace post -> fan-out -> timeline-visible trace: one trace id from create through the last fan-out batch.
Recurring work
- fanout_post: runs queue (on post publish, non-celebrity author). Guard: keyset batches of FANOUT_BATCH_SIZE with the cursor persisted in the job row so retries resume; skips dormant users; hard cap of FANOUT_MAX_ROWS_PER_POST; idempotent via ON CONFLICT DO NOTHING; one job per post at a time.
- rollup_counters: runs cron 1m (hot posts every 10 s). Guard: touches only shards with updated_at newer than last run, bounded batch, raises counter_shards for posts above the hot threshold.
- emit_notifications: runs queue (like, reply, follow, mention events). Guard: dedupe by group_key, skips blocked/muted actors, per-recipient daily cap on email and push, batch of 500.
- trim_timelines: runs cron 15m. Guard: per-user delete beyond TIMELINE_MAX_ENTRIES in bounded chunks, never a table-wide delete.
- build_trending: runs cron 5m. Guard: reads hashtag_stats for the last 24 hourly buckets only; atomic swap of the trending table; spam-weighted by distinct authors.
- purge_deleted: runs queue (post delete, account deletion). Guard: removes timeline entries, media objects, hashtags, counters and search rows in chunks; idempotent; completes erasure within the GDPR window.
Add when the numbers say so
- Read replicas: Route timeline hydration, profile, search and explore reads to read replicas once primary CPU or read latency crosses the trigger; the data layer already separates read and write paths, so this is configuration. Read-your-writes for the author is served from the primary for 5 seconds.
- Realtime: Move DMs and live updates to a dedicated websocket tier with a pub/sub backbone when SSE connections or LISTEN/NOTIFY throughput hit the trigger.
Deferred until it is needed
| Deferred | Adopt it when |
|---|---|
| Dedicated websocket tier with pub/sub | > 20k concurrent connections or DM delivery p95 > 1 s. |
| Dedicated search engine (OpenSearch/Typesense) | > 500M indexed posts or search p95 > 300 ms. |
| Read replicas for timeline and profile reads | primary CPU > 60% sustained or timeline read p95 > 200 ms. |
| Dedicated cache or in-memory store for hot timelines | timeline p95 > 250 ms with the primary under 50% CPU. |
| ML ranker, embeddings and recommendation service | > 10k daily active users and engagement data collected. |
| Automated image/text moderation provider | reports per day exceed reviewer capacity. |
On Forge64
Forge64 matches your description to one of 12 reference architectures, writes the plan and data model into the project, generates the app, and runs a quality gate over the code before you see it. Each app gets its own Postgres database and sign-in with no per-user fee. Hosting on Forge Cloud and Forge Payments are rolling out.
Every metered resource on Forge64 has a hard cap, so a traffic spike stops at your limit instead of becoming a surprise bill. This is a reference design for the category, not a promise that every item is generated today. Built-ins such as email, background jobs, file uploads and search are coming soon, so anything here that needs them is something you add yourself for now.
FAQ
- When should I worry about scale for a social network?
- Not before a measured trigger fires. For example, for "Dedicated websocket tier with pub/sub": > 20k concurrent connections or DM delivery p95 > 1 s.
- What performance targets should a social network aim for?
- Home timeline API (30 posts hydrated): p95 < 250 ms, <= 6 queries, zero N+1. Post create to visible to followers (non-celebrity, under 5k followers): p95 < 5 s via fan-out job; author sees own post immediately. Like/unlike: p99 < 100 ms, 2 statements, no row-level lock wait on viral posts.
- Does Forge64 cap my usage costs?
- Yes. Every metered resource has a hard cap, and paid plans add an overage spend cap that you set.
Build your app with Forge64
One prompt to a running app with auth, database, hosting and payments. Start free, no credit card required.
Start building for free