For AI agents: the complete documentation index is at llms.txt. Every page is also available as markdown by appending .md to its URL, or by sending an Accept: text/markdown request header.

Write-Ahead Log (WAL)

Write-Ahead Log (WAL) records all changes before applying them to storage. This enables concurrent writes, crash recovery, and replication.

WAL is enabled by default and recommended for all tables.

Why WAL matters​

CapabilityDescription
Concurrent writesMultiple clients can write simultaneously without blocking
Crash recoveryAfter a restart, committed transactions are replayed from the log. Surviving a power loss needs a commit mode that flushes the log, such as adaptive
ReplicationWAL enables high availability and disaster recovery
Out-of-order handlingLate-arriving data is merged efficiently. See Out-of-order data.
DeduplicationEnables deduplication with DEDUP UPSERT KEYS or DEDUP SKIP KEYS

In QuestDB Enterprise, WAL segments are sent to object storage immediately on commit, enabling real-time replication to standby nodes.

Creating WAL tables​

WAL is enabled by default for partitioned tables:

CREATE TABLE prices (
ts TIMESTAMP,
ticker SYMBOL,
price DOUBLE
) TIMESTAMP(ts) PARTITION BY DAY;
-- This is a WAL table (default)

You can be explicit with the WAL keyword:

CREATE TABLE prices (...)
TIMESTAMP(ts) PARTITION BY DAY WAL;

Requirements​

WAL requires partitioning. Non-partitioned tables cannot use WAL.

Table creation methodDefault partitioningWAL enabled?
SQL CREATE TABLE without PARTITION BYNoneNo
SQL CREATE TABLE with PARTITION BYAs specifiedYes
ILP auto-created tablesPARTITION BY DAYYes
-- Non-partitioned = no WAL (not recommended for time-series)
CREATE TABLE static_data (key VARCHAR, value VARCHAR);

-- Partitioned = WAL enabled (recommended)
CREATE TABLE prices (...)
TIMESTAMP(ts) PARTITION BY DAY;

If you need WAL features (concurrent writes, replication, deduplication), always specify PARTITION BY when creating tables via SQL.

Checking WAL status​

Check if a table uses WAL:

SELECT name, walEnabled FROM tables() WHERE name = 'prices';

Check WAL table status:

SELECT * FROM wal_tables();

If WAL transactions are suspended (rare), resume them:

ALTER TABLE prices RESUME WAL;

For a suspended materialized view or live view, use ALTER MATERIALIZED VIEW RESUME WAL or ALTER LIVE VIEW RESUME WAL instead.

How WAL works​

When data is written to a WAL table:

  1. Data is written to WAL segments (fast sequential writes)
  2. Transaction is committed and acknowledged to client
  3. WAL apply job merges data into table storage asynchronously
  4. In Enterprise, WAL segments replicate to object storage

This decouples the commit (fast) from storage application (background), enabling high write throughput.

WAL apply sorts and commits many WAL transactions together as one block; larger blocks reduce out-of-order merges but use more memory per block. Adaptive blocks are enabled by default and grow within a memory budget.

Whether an acknowledged transaction survives an operating system crash or a power loss depends on the commit mode. In the default nosync mode, nothing is flushed to the disk. In adaptive commit mode, which is unrelated to the adaptive apply blocks above, each commit flushes its WAL files, and the table files are flushed at periodic save points. See Durability and commit modes.

Diagram showing the sequencer allocating txn numbers to events chronologically
The sequencer allocates unique transaction numbers and serves as the single source of truth.
Diagram showing the WAL job application and WAL collect events and commit to QuestDB
The WAL apply job collects transactions sequentially for writing to storage.

Configuration​

WAL behavior can be tuned via server configuration:

To convert an existing table between WAL and non-WAL:

ALTER TABLE prices SET TYPE WAL;
-- Requires database restart to take effect

See ALTER TABLE SET TYPE for details.

See also​