Sequences and Generated Identifiers
corebeginnerA sequence is its own database object that generates a new, incrementing integer every time it is asked, via nextval(). It exists independently of any table — a column with a DEFAULT of nextval('some_sequence') is simply a column that asks the sequence for the next value on every INSERT that omits it.
Think of it as
A sequence is not a property of a column — it is a separate, standalone object in the database that happens to be wired up as a column's default. This separation is what makes a sequence usable across multiple tables if desired, inspectable directly (SELECT * FROM some_sequence), and independently resettable — none of which would make sense if the increment logic were baked directly into the column itself rather than being its own object with its own state.
What we're doing: Query a sequence directly, independent of any table, to show it is a genuine standalone object with its own state.
- 1–2
- The sequence and the table are two separate objects — the column's DEFAULT is what connects them.
- 5
- The sequence can be queried directly, like a table, showing its own current state.
- 6
- nextval() advances the sequence even though no row was ever inserted — proving the sequence has state independent of orders.
last_value
------------
2
nextval
---------
3Why this works: last_value confirms the sequence has already advanced to 2 after two inserts consumed values 1 and 2 — but the second query, calling nextval() directly with no INSERT anywhere near it, advances the sequence to 3 anyway, which is only possible because the sequence is a genuinely independent object with its own persistent state, not merely an internal counter attached to the orders table's row count.
Assuming a sequence's current value reflects a table's actual row count
Wrong
Better
What you see: Code that infers "how many orders exist" from a sequence's current value is wrong as soon as any row has ever been deleted, or any transaction using the sequence was ever rolled back — both leave gaps the sequence does not know or care about.
Why: A sequence tracks only "what value was handed out last," completely independent of what became of the rows that used those values — it has no awareness of deletes, rollbacks, or the table at all, since it is not actually part of the table's data. Row count must always come from counting rows directly (COUNT(*)), never inferred from a sequence, which the next concept's look at sequence gaps explores in more depth.
- orders_id_seq — a standalone sequence object
- leads to nextval(...)
- nextval(...) — requests the next value, atomically
- leads to id column DEFAULT
- id column DEFAULT — used automatically on INSERT if omitted
A sequence vs a column relying on it
Together
Remember: A sequence is its own standalone object with persistent state, independent of any table — SERIAL/IDENTITY are convenience syntax that create one automatically and wire a column's DEFAULT to it, not a different underlying mechanism.
See also: generated as identity · sequence gaps

