Every table has a rowid (almost)
By default every SQLite table has an invisible rowid — a 64-bit integer the engine assigns to each row. It's how indexes and joins find rows internally. You can see it explicitly:
SELECT rowid, * FROM users;When you declare a column INTEGER PRIMARY KEY (note: exactly that spelling, not INT PRIMARY KEY), SQLite makes that column an alias for rowid. The column becomes the rowid — no extra storage, no extra index, just a name for the integer SQLite was already maintaining.
Other primary key shapes:
- Composite primary key —
PRIMARY KEY (a, b)on multiple columns. - WITHOUT ROWID tables — useful for tables keyed by something other than an integer (e.g., a UUID); the column you declare is the actual storage key.
Warning:
INT PRIMARY KEY ≠ INTEGER PRIMARY KEY. The first is a regular indexed column; only the exact word INTEGER activates the rowid-alias optimization. Easy bug to ship — your inserts work but performance silently regresses on large tables.