Skip to main content

CREATE SEQUENCE

Turso Extension: CREATE SEQUENCE is a Turso-specific statement not available in standard SQLite.
The CREATE SEQUENCE statement defines a named sequence object that generates a series of numeric values. Sequences are independent of any table and can be used across multiple tables and queries via the nextval(), currval(), and setval() functions.

Syntax

Description

A sequence generates a series of integer values according to its configuration. Each call to nextval() produces the next value in the series. Sequences are persisted in the database schema and survive restarts. Unlike AUTOINCREMENT on an INTEGER PRIMARY KEY, sequences are standalone objects. A single sequence can supply values to multiple tables, or multiple sequences can feed into different columns of the same table.

Parameters

Validation

The following rules are enforced at creation time:
  • INCREMENT BY must not be zero.
  • MINVALUE must be less than MAXVALUE.
  • For ascending sequences (INCREMENT > 0): START must be greater than or equal to MINVALUE.
  • For descending sequences (INCREMENT < 0): START must be less than or equal to MAXVALUE.

Sequence Functions

nextval()

Returns the next value from the sequence and advances it.
On the first call, nextval() returns the START value. Each subsequent call increments by INCREMENT BY. Sequence persistence under WAL mode is transactional: the sequence backing-table update is committed or rolled back with the transaction that called nextval(). Under MVCC mode (journal_mode=experimental_mvcc) inside BEGIN CONCURRENT, the backing-table write is autonomous and survives an outer ROLLBACK (postgres-like). For BEGIN / BEGIN IMMEDIATE / autocommit, the inner write is bundled with the outer and rolls back with it (SQLite-like). Turso does not guarantee gap-free sequences, and it also does not guarantee PostgreSQL-style permanent burning of values from rolled-back transactions in WAL mode or under an exclusive (BEGIN IMMEDIATE / BEGIN DEFERRED) MVCC outer. If a transaction calls nextval() and rolls back, that value may be generated again later if no committed transaction used that value or a later value. If another concurrent transaction commits after allocating a later value, the rolled-back value can remain a gap. The guarantee is that persisted sequence state remains consistent with committed database state.

currval()

Returns the last value returned by nextval() in the current connection. Raises an error if nextval() has not been called on this sequence in the current session.

setval()

Sets the sequence to an explicit value.

Examples

Basic Sequence

Custom Start and Increment

Descending Sequence

Cycling Sequence

When the sequence reaches its boundary, it wraps around:
Without CYCLE, exceeding the boundary raises an error:

Sequence as Column Default

A sequence can supply default values for a table column:

IF NOT EXISTS

Concurrency

nextval() and setval() persist sequence state to a backing table. In WAL mode (the default), the backing-table write rides on the caller’s write transaction. Only one connection can hold the write lock at a time; if another connection is already writing, SELECT nextval(...) will return SQLITE_BUSY (“Database is busy”). This is different from AUTOINCREMENT, which uses a process-local allocator and writes the committed watermark with the table insert. In MVCC mode (journal_mode=experimental_mvcc), nextval() inside a BEGIN CONCURRENT outer wraps the backing-table write in an autonomous inner transaction that commits immediately and independently of the outer’s eventual commit or rollback. This lets multiple concurrent BEGIN CONCURRENT callers each get a fresh value (serialized by the standard MVCC PK conflict + bounded retry on the backing table), and matches PostgreSQL’s “burnt value” semantics for this case. For autocommit, BEGIN, BEGIN IMMEDIATE, and BEGIN DEFERRED, the outer holds the exclusive lock and the inner write runs inline — under those modes a ROLLBACK un-burns the value (SQLite-like). In rollback cases, generated values are not guaranteed to be reused and are not guaranteed to remain gaps. Reuse depends on the outer transaction mode and on whether another committed transaction advanced the durable watermark past that value. If your workload calls nextval() from many concurrent connections in WAL mode, consider using AUTOINCREMENT instead, or serializing sequence access at the application level.

Recovering the current value

The “current value” reachable from a fresh connection depends on mode:
  • WAL mode: read seq from sqlite_sequence (for AUTOINCREMENT tables) or query the sequence backing table directly:
    Both are kept in sync at commit time.
  • MVCC mode: sqlite_sequence is updated only at checkpoint time — between checkpoints it may lag the actual high-water mark or be empty for a freshly-created AUTOINCREMENT table. Do not rely on sqlite_sequence to recover the live value in MVCC mode. Instead, query the internal sequence backing table directly:
    For AUTOINCREMENT, the sequence name is __turso_internal_autoincrement_<table>, so the backing-table query becomes:
    After PRAGMA wal_checkpoint(TRUNCATE), the backing table is coalesced to a single row and sqlite_sequence is also brought up to date with exactly one row per AUTOINCREMENT table — at that point both are safe to read with normal SQLite-compatible queries.

Errors

See Also