Every row needs a unique, stable identifier — its primary key. It's how Read, Update, and Delete find a specific record.
1id BIGSERIAL PRIMARY KEY -- 1, 2, 3, 4, ...Pros: small, fast, human-readable, naturally ordered.
Cons: guessable (/tasks/1, /tasks/2…), leaks how many rows exist, awkward across distributed systems.
1id UUID PRIMARY KEY DEFAULT gen_random_uuid() -- 9f1c...Pros: unguessable, generatable on the client, collision-free across databases. Cons: larger (16 bytes), not human-friendly, random UUIDv4 can fragment indexes.
| Use case | Pick |
|---|---|
| Internal tooling, simple apps | Auto-increment |
| Public APIs, anything user-facing | UUID (or a slug) |
| Distributed / offline-first | UUID |
A common hybrid: keep a BIGSERIAL primary key internally, plus a public UUID or slug column for URLs.
Prefer surrogate keys. Real-world "unique" values change more often than you'd think — emails get reassigned, usernames get edited. A surrogate key never has to.