# Transactions

> Atomic statements and multi-statement transactions with BEGIN, COMMIT and ROLLBACK.

Every SQL statement commits atomically: it is applied completely, or nothing is
written. Several statements commit together inside a transaction.

## A transaction

```sql
BEGIN;

UPSERT INTO balances (
  chain_id, address, token, amount, updated_at, balance_index, balance_version
)
VALUES (1, '0x4b1e7c2a', 'USDC', 1500000000, '2026-10-01 12:00:00.000', 1001, 1)
ATTRIBUTE GROUP holding;

UPSERT INTO balances (
  chain_id, address, token, amount, updated_at, balance_index, balance_version
)
VALUES (1, '0x9c2e4f1a', 'USDC', 2500000000, '2026-10-01 12:00:00.000', 1001, 1)
ATTRIBUTE GROUP holding;

INSERT INTO transfers (
  chain_id, token, sender, recipient, amount, transferred_at, _index
)
VALUES (
  1, 'USDC', '0x4b1e7c2a', '0x9c2e4f1a', 1000000000, '2026-10-01 12:00:00.000',
  1001
);

COMMIT;
```

Both balances and the transfer become visible together at `COMMIT`.
`ROLLBACK` discards every statement since `BEGIN`.

| Statement | Effect |
| --- | --- |
| `BEGIN` / `START TRANSACTION` | Opens a transaction on the session. |
| `COMMIT` | Commits every statement of the transaction atomically. |
| `ROLLBACK` | Discards every statement of the transaction. |

## What one statement guarantees

| Statement | Unit of atomicity |
| --- | --- |
| `INSERT`, `UPSERT`, `REPLACE` | one row tuple, optionally one attribute group of it |
| `UPDATE` | the named columns of the row with one complete primary key, optionally within one group |
| `DELETE` | the row with one complete primary key, every group included |
| DDL (`CREATE`, `ALTER`, `DROP`) | the one definition change |

After the receipt returns, the next read sees the write. See
[Consistency](/docs/concepts/consistency).

Rows sent in bulk go through the HTTP write-batch and bulk-load routes; see
[Protocol](/docs/drivers/protocol) for their acknowledgement contract.

## Designing writes

- Put the facts that change together in one row, in one attribute group of a
  row, or in one transaction.
- Record each step of a workflow as an event in an APPEND table, and derive the
  current state with a [transformation](/docs/sql/create-transformation).
- Make retries safe. On columns with the default `REPLACE` reducer, an `UPSERT`
  or `REPLACE` sent twice with the same values leaves the same row. An `INSERT`
  of an existing key reports the duplicate instead of writing it twice.
- Use `VALID BY` and `REVISION BY` on keyed tables so late or repeated writes
  resolve deterministically. See
  [Versioned tables](/docs/concepts/versioned-tables).

---

Source: https://nyxdb.io/docs/sql/transactions/
