BEGIN CONCURRENT — you must use different connections, not parallel statements within the same connection.
Turso supports three transaction types: deferred, immediate/exclusive, and concurrent.
Syntax
Transaction types
| Type | When to use |
|---|---|
DEFERRED (default) | General read/write workloads where write latency is acceptable |
IMMEDIATE | When you need an exclusive write lock from the start |
EXCLUSIVE | Alias for IMMEDIATE in Turso |
CONCURRENT | MVCC mode only — maximum write throughput with optimistic concurrency |
Deferred transactions
A deferred transaction starts in a suspended state and acquires no snapshot or locks until the first SQL statement runs.First read statement
A read transaction begins. Multiple read transactions can coexist concurrently.
First write statement
The read transaction upgrades to a write transaction, or a write transaction begins directly. Only one write transaction is allowed at a time. A concurrent write fails with
SQLITE_BUSY.Automatic restart behavior
If a deferred transaction has performed no reads or writes yet, and another write transaction commits concurrently, the database automatically restarts the deferred transaction. However, once a deferred transaction has already performed reads, it cannot be automatically restarted — the application must manually roll back and retry.If your deferred transaction receives a
SQLITE_BUSY error after reads have occurred, roll back the transaction and retry from the beginning.Immediate and exclusive transactions
An immediate transaction acquires a reserved write lock as soon asBEGIN IMMEDIATE executes. This prevents other write transactions from starting, while still allowing reads.
EXCLUSIVE is always an alias for IMMEDIATE in Turso, matching SQLite’s behavior in WAL mode.BEGIN IMMEDIATE executes, the statement fails immediately with SQLITE_BUSY.
Concurrent transactions (MVCC only)
Concurrent transactions are only available when the database is running in MVCC journal mode. They use optimistic concurrency control to allow multiple transactions to read and write simultaneously.Lifecycle
WhenBEGIN CONCURRENT executes, the database:
- Assigns a unique transaction ID
- Records a begin timestamp from the logical clock
- Creates an empty read set and write set to track accessed rows
- Acquires no locks
Snapshot isolation
Each concurrent transaction reads from a consistent snapshot of the database as of its begin timestamp:- Reads see all data committed before the transaction’s begin timestamp
- Reads do not see writes from other transactions that commit after this transaction starts
- Reads within the same transaction are consistent (repeatable reads)
- Multiple concurrent transactions can read and write simultaneously without blocking each other
Commit and conflict detection
When a concurrent transaction commits, the database performs these steps in order:Exclusive transaction check
If an active exclusive transaction exists (started with
BEGIN IMMEDIATE or a deferred transaction that upgraded to a write transaction), the concurrent transaction cannot commit and receives SQLITE_BUSY. Concurrent transactions can still read and write while an exclusive transaction is active — they just cannot commit until it completes.Write-write conflict detection
For each row in the write set, the database checks whether the row was modified by another transaction. A conflict occurs when:
- The row is currently being modified by another active transaction, or
- The row was modified by a transaction that committed after this transaction’s begin timestamp
Commit or abort
If no conflicts are detected, the transaction commits. All row versions in the write set have their begin timestamps updated to the commit timestamp, making them visible to future transactions.If a conflict is detected, the transaction fails with
SQLITE_BUSY and must be rolled back and retried.Interaction with exclusive transactions
| Situation | Result |
|---|---|
| Exclusive transaction is active, concurrent transaction reads | Allowed |
| Exclusive transaction is active, concurrent transaction writes | Allowed |
| Exclusive transaction is active, concurrent transaction commits | SQLITE_BUSY — wait for exclusive to finish |
| Concurrent commit has write-write conflict | SQLITE_BUSY — roll back and retry |
Retry pattern
Best practices
- For maximum concurrency in MVCC mode, use
BEGIN CONCURRENTfor all write transactions. Only useBEGIN IMMEDIATEwhen you need to guarantee exclusive write access, such as during schema changes. - Keep transactions short to reduce lock contention and conflict probability.
- Always handle
SQLITE_BUSYin application code when using concurrent transactions. Implement exponential backoff before retrying. - Do not interleave statement execution across different transactions on a single connection. Use separate connections for concurrent workloads.
AUTOINCREMENTis not supported in MVCC mode. UseINTEGER PRIMARY KEYwithoutAUTOINCREMENTinstead.