Documentation

Solana Indexer Schema conventions

How the Solana Historical Data Indexer schema is put together: shared columns, raw base units, partition keys, retention windows, and the padding and naming gotchas that bite first.

// updated 2026-10-21

The Solana database holds 21 tables and 557 columns of decoded DEX activity. This page covers what is true across all of them; the per-table column lists live in the Table reference.

NOTE

Read this page before your first query. Four conventions - fixed-width padding, raw base units, per-table partition keys, and per-table retention - explain most of the surprises people hit in week one.

Shared columns

Almost every table carries the same transaction envelope. Use it for joins, time-series aggregation, and wallet-level work.

ColumnTypeWhat it is
block_timeDateTimeUTC timestamp of the block
block_date_utcDateUTC date, and on most tables the partition key
slotUInt32 / UInt64Solana slot number
tx_idxUInt16 / UInt32Transaction index within the block
signatureString / FixedString(128)Transaction signature, base58
fee_payerStringWallet that paid the fee
feeUInt64Fee actually paid, in lamports
provided_gas_feeUInt64Compute-unit price the transaction offered
provided_gas_limitUInt64Compute-unit limit requested
consumed_gasUInt64Compute units actually burned
parent_programStringProgram that invoked this instruction through CPI

(slot, tx_idx) identifies a transaction inside a block, and together with signature it is what you join on across tables.

TIP

parent_program is the aggregator fingerprint. A swap routed through Jupiter, a bot, or any other program carries that program's address here, while a direct call to the DEX does not. It is the cheapest way to split organic flow from routed flow.

Four gotchas

1. Fixed-width columns are null-padded

Older tables store mints, wallets, and signatures as FixedString(48) or FixedString(128). ClickHouse pads the unused bytes with \0, so a raw value will not compare equal to a plain base58 string, and grouping by it produces keys with invisible trailing bytes.

Strip the padding on both sides of any comparison or join:

SELECT replaceAll(toString(mint), '\0', '') AS mint_clean,
       count() AS launches
FROM pumpfun_token_creation
WHERE block_time >= now() - INTERVAL 1 DAY
GROUP BY mint_clean

Newer tables use plain String and need no cleanup. The Table reference shows the exact type per column.

2. Every amount is a raw base unit

Token and SOL amounts are integers in the smallest unit - lamports for SOL, and the mint's own base unit for SPL tokens. Nothing is pre-divided by decimals, and nothing is converted to USD. Divide by 1e9 for SOL; for a token, apply that mint's decimals.

Fee-rate columns follow the same rule: lp_fee_basis_points and protocol_fee_basis_points are basis points, not fractions.

3. The partition key is not the same on every table

Most tables partition on block_date_utc, but not all:

Partition keyTables
block_date_utcmost swap and migration tables
block_datemeteora_swaps
(block_date_utc, failed)pumpfun_v2_swaps
toYYYYMM(block_time)pumpfun_amm_admin_set_coin_creator
toYYYYMMDD(block_time)pumpfun_creator_fee_distributions
toYYYYMMDD(toDateTime(entry_timestamp))tx_timestamps
nonepumpfun_token_creation, pumpfun_all_swaps, raydium_launchpad_token_creation, solana_blocks, max_caps
WARNING

Filter on the partition column, and do it in PREWHERE. A swap query with no partition filter reads the whole table - on pumpswap_all_swaps that is about 1.74 TB and 5.16 billion rows in the published snapshot. PREWHERE block_date_utc >= today() - 7 cuts it to the parts you need before any other column is read.

4. Some columns only carry data from a certain date

Columns added after a table went live are marked (populated since ...) in the Table reference. The column exists on every row, but rows older than that date hold the type default - an empty string or a zero, not a NULL. Filter on the date range as well as the column value, or old rows will quietly look like real zeros.

Transaction metadata added to the schema

The published schema includes transaction context on Pump.fun launches and v2 swaps, Raydium swaps and Launchpad events, and Meteora swaps. Depending on the table, this includes fee_payer, blockhash_prefix, compute-budget instruction indexes, num_signatures, transaction_version, lookup_tables, and top_level_transfers_json. Check the exact column list and its populated-since date before joining older records.

Meteora Dynamic Bonding Curve swaps also expose curve_complete, base_reserve_after, and quote_reserve_after. Raydium Launchpad token creation includes amm_fee_on, transfer_fee_basis_points, and transfer_fee_max; its swap and creation tables include instruction_type.

Retention

Retention is per table. Nothing is a single global window.

WindowTables
14 daystx_timestamps, jito_tips
31 daystoken_transfers, sol_top_ups
90 daysmeteora_swaps, raydium_all_swaps, raydium_cpmm_swaps
1 yearpumpswap_all_swaps, pfamm_migrations, meteora_dynamic_bonding_swaps, all raydium_launchpad_*
Full historypumpfun_all_swaps, pumpfun_v2_swaps, pumpfun_token_creation, pumpfun_creator_fee_distributions, pumpfun_amm_admin_set_coin_creator, solana_blocks, max_caps
TIP

Need a longer window than the table keeps? Extended retention and one-off exports are arranged per customer - start in the portal or ask Telegram support before you build a pipeline that assumes the data will still be there.

Coverage and latency

History depth

The deepest table, pumpfun_token_creation, starts 17 January 2024. Every table's own window is listed in the Table reference.

Validation latency

~15 seconds between block confirmation and the row being queryable. Confirmed transactions only - never processed-level data that can revert.

Storage engine

SettingValue
DatabaseClickHouse, default database
EngineMergeTree family
Partitioningdaily on the table's date column (see above)
Sort order(slot, tx_idx) on transaction tables
Nanosecond timingseparate tx_timestamps table, joined on (slot, tx_idx)

See also

Table reference

All 21 tables, column by column.

Query examples

Working SQL you can paste.

Nanosecond timestamps

Sub-block timing via tx_timestamps.