SQLite B-Tree Sidecar Format — v3¶
A compact binary file containing a selected set of SQLite database pages, indexed by page number. Designed to let a remote-storage SQLite reader prefetch and cache the pages SQLite must traverse on every query — the schema btree and all interior B-tree nodes — eliminating per-query round trips for B-tree navigation.
This document specifies the byte layout. It does not specify which pages a producer should include; any subset of pages is valid as long as the layout below is correct.
Wire format¶
All multi-byte integers are little-endian. Byte offsets are zero-based.
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 8 | magic |
b"SFBTM\x00\x00\x00" |
| 8 | 4 | format_version |
u32 — value 3 for this spec |
| 12 | rest | body |
zstd-compressed body (see next) |
The magic and version are deliberately uncompressed so a reader can validate the artifact and reject unsupported versions before paying the decompression cost.
Body format¶
After zstd-decompressing body, the bytes are:
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 4 | page_size |
u32 — SQLite page size in bytes |
| 4 | 4 | n |
u32 — number of pages in the sidecar |
| 8 | 8 · n | index |
n × (u32 pageno, u32 offset), sorted ascending |
| 8 + 8 · n | page_size · n | slabs |
n × page_size-byte page contents, in same order |
Field semantics¶
page_sizeis the SQLite database's page size — a power of two in the range[512, 65536].nis the number of(pageno, offset)index entries and the number of page slabs. Both arrays have the same length and the same ordering.pagenois the SQLite page number (1-based, matching SQLite's on-disk convention). Index entries are sorted strictly ascending bypageno.offsetis the body-relative byte position of the corresponding slab. For this spec (uniformpage_size),offset_i = 8 + 8*n + i * page_size. The field is stored explicitly so a consumer can write the decompressed body to a file and access individual pages viapreadwhile holding only thepageno → offsetmap in memory.- A slab is the SQLite page for the corresponding
pageno, byte-for-byte identical toread(source_db, (pageno - 1) * page_size, page_size)from the source database.
Validation¶
A reader rejects the sidecar if any of:
magicdoes not matchb"SFBTM\x00\x00\x00".format_versionis not understood by the reader.- zstd decompression fails.
page_sizeis not a power of two in[512, 65536].- Index entries are not strictly ascending by
pageno. - Any
offset + page_sizeexceeds the body length.
A producer is responsible for ensuring its output passes these checks.
Versioning¶
format_version is a monotonic u32. A reader that receives a higher
version than it understands should treat the sidecar as absent and fall
back to fetching pages on demand. Versions 1 and 2 existed during
development and never shipped in a release.
Reference parser (Python)¶
import struct
import zstandard
MAGIC = b"SFBTM\x00\x00\x00"
VERSION = 3
def parse_sidecar(blob: bytes) -> tuple[int, list[tuple[int, bytes]]]:
"""Return ``(page_size, [(pageno, page_bytes), ...])``."""
assert blob[:8] == MAGIC, "bad magic"
fv = int.from_bytes(blob[8:12], "little")
assert fv == VERSION, f"unsupported format_version {fv}"
body = zstandard.ZstdDecompressor().decompress(blob[12:])
page_size, n = struct.unpack("<II", body[:8])
pairs = struct.unpack(f"<{2 * n}I", body[8 : 8 + 8 * n])
return page_size, [
(pageno, body[offset : offset + page_size])
for pageno, offset in zip(pairs[0::2], pairs[1::2], strict=True)
]
Reference producer (Python)¶
import struct
import zstandard
def build_sidecar(page_size: int, pages: list[tuple[int, bytes]]) -> bytes:
"""Build a v3 sidecar.
``pages`` must be sorted strictly ascending by ``pageno``; each
``page_bytes`` must be exactly ``page_size`` bytes.
"""
n = len(pages)
data_start = 8 + 8 * n
index_pairs: list[int] = []
for i, (pageno, _) in enumerate(pages):
index_pairs.extend([pageno, data_start + i * page_size])
body = (
struct.pack("<II", page_size, n)
+ (struct.pack(f"<{2 * n}I", *index_pairs) if n else b"")
+ b"".join(slab for _, slab in pages)
)
return (
MAGIC
+ VERSION.to_bytes(4, "little")
+ zstandard.ZstdCompressor(level=3).compress(body)
)