Why Using Email as a Primary Key Is a Terrible Idea (With Receipts)
I tried finding a good writeup on why email is a bad primary key. Most results were either a Stack Overflow comment or some post that just said "don't do it" with no real reasons.
So here's the one I wanted to find.
Quick background — what is a primary key?
A primary key is how your database tells rows apart. Every table has one. When you link tables together — like connecting payments to the right employee — you use that key.
The rules: it should be unique, stable (never changes), and system-controlled (not owned by a user).
Email checks the first box. It fails the other two.
1. Emails change. Primary keys can't.
This is the main one.
If email is just a regular column and someone changes it, you update one row. Done. If email is the primary key — the thing every other table points to — you need to update every single table that references it. Orders, sessions, audit logs, everything.
Miss one? Now half your system knows the user as priya@oldcompany.com and the other half knows priya@newcompany.com. Good luck debugging that.
There's a Hacker News thread [1] where engineers say it's "trivial to fix with a surrogate key, a week of migrations without one."
The standard advice is to use surrogate keys (auto-generated IDs, integers, UUIDs) instead of natural keys (real-world stuff like email). Martin Fowler covers this in Patterns of Enterprise Application Architecture.
2. Email uniqueness is not guaranteed
Email is only unique if everyone follows the rules. They don't.
Benjamin Taub [2] worked on a database for The Henry Ford museum. They found multiple people sharing one email address. Families sharing an inbox. Parents using their email for their kids.
HubSpot hit the same problem [3]. Their forum has customers complaining that families sharing one email get treated as one person. One person's data overwrites another's.
If your database has UNIQUE on email and two people share one, the second person can't be created. Silent failure, bad data, support ticket.
3. Strings are slower than numbers
Numbers are faster for databases to compare. A string like an email can be up to 254 characters — the database checks each character one by one. Numbers are instant.
Also takes more space. An integer = 4 bytes. An email = 20–40 bytes. That key goes into every related table. At scale it adds up.
4. Email in URLs just looks ugly
If email is your ID, your URLs look like /users/priya@company.com. The @ has to be encoded as %40 and it just looks bad.
Better approach — keep your usual ID and use query params when you need to find someone by email:
GET /users?email=priya@company.com
GET /users?search=priyaSame result, cleaner URL, no encoding issues. Email is just a filter, not the identity.
What to do instead
CREATE TABLE employees (
id SERIAL PRIMARY KEY,
email VARCHAR(254) UNIQUE,
name VARCHAR(255)
);Look up by email when needed:
SELECT * FROM employees WHERE email = 'priya@company.com';Reference by ID everywhere else:
SELECT * FROM payroll WHERE employee_id = 1042;Email tells you who the person is. The ID tells the system how to track them. Keep those separate.
TL;DR
| Problem | What happens |
|---|---|
| Emails change | Have to update every table |
| Emails aren't always unique | Two people can share one email |
| Strings are slow | Numbers are faster |
| Email in URLs | Ugly URLs, encoding problems |
Use a surrogate key. Keep email as a regular column. Simple change, saves a lot of pain.
Sources
[1] Hacker News — surrogate vs natural key: https://news.ycombinator.com/item?id=40581759
[2] Benjamin Taub, "Email Address is a Really Bad Key": https://www.linkedin.com/pulse/email-address-really-bad-key-benjamin-taub
[3] HubSpot Community — shared emails: https://community.hubspot.com/t5/HubSpot-Ideas/Use-custom-unique-identifier-instead-of-email-address/idi-p/376217
[4] RFC 5321 — email length limits: https://datatracker.ietf.org/doc/html/rfc5321
[5] PostgreSQL mailing list — string vs int performance: https://www.postgresql.org/message-id/b42b73150909121052n63711eebn5720b62430e3917e%40mail.gmail.com