Solana Configuration File
A Solana indexer is defined by a config.yaml with ecosystem: svm. It tells
HyperIndex which chain to read, which programs and instructions to match, and how
to decode them. This page is the field-by-field reference; for the meaning of
discriminators, IDLs and argument types see Decoding & IDLs.
Add this line at the top of the file for editor autocompletion and validation:
# yaml-language-server: $schema=./node_modules/envio/svm.schema.json
A complete example
# yaml-language-server: $schema=./node_modules/envio/svm.schema.json
name: my-solana-indexer
description: Index Jupiter swaps and Metaplex NFT mints
ecosystem: svm
chains:
- rpc: https://api.mainnet-beta.solana.com
hypersync_config:
url: https://solana.hypersync.xyz # optional; this is the default
start_block: 417995000 # a SLOT number, not a block
programs_experimental:
# --- decoded from an Anchor IDL ---
- name: Jupiter
program_id: JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4
idl: idls/jupiter.json
instructions:
- name: sharedAccountsRoute
discriminator: "0xc1209b3341d69c81"
field_selection:
token_balance_fields: true
# --- decoded from an inline schema (no IDL) ---
- name: Raydium
program_id: 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
instructions:
- name: swap
discriminator: "0x09"
args:
- { name: amountIn, type: u64 }
- { name: minAmountOut, type: u64 }
accounts:
- tokenProgram
- amm
- userSourceTokenAccount
- userDestTokenAccount
field_selection:
token_balance_fields: true
Top-level fields
| Field | Required | Default | Notes |
|---|---|---|---|
name | ✅ | — | Project name. |
ecosystem | ✅ | — | Must be svm. |
chains | ✅ | — | One or more chains to index (see below). |
description | — | — | Free-text description. |
schema | — | schema.graphql | Path to your GraphQL schema. |
full_batch_size | — | 5000 | Batch size for processing. |
storage | — | postgres: true | Storage backends (postgres, clickhouse). |
For Solana, several EVM top-level fields don't apply: contracts,
rollback_on_reorg, save_full_history, raw_events, a global
field_selection, and address_format. Reorg-related options are fixed off
(Solana indexes finalized data). Field selection is per-instruction only
(see field selection).
chains
Each entry is one Solana cluster.
| Field | Required | Default | Notes |
|---|---|---|---|
rpc | ✅ | — | RPC URL. Used by slot handlers and the Effect API. |
start_block | ✅ | — | The slot to start indexing from. |
hypersync_config.url | — | https://solana.hypersync.xyz | The HyperSync endpoint that serves historical instructions. |
end_block | — | — | Stop at this slot (inclusive of the range processed). Useful for finite backfills and tests. |
block_lag | — | — | Stay this many slots behind the head. |
skip | — | false | Skip this chain. |
programs_experimental | — | — | Programs to index (see below). |
idEVM chains require an id (the public chain ID). Solana chains have no id —
the cluster is identified by the rpc / hypersync_config you point at. Inside
handlers the Solana chain id is 0.
programs_experimental
The list of Solana programs to index on this chain. The YAML key is
programs_experimental to signal that this shape is still evolving.
| Field | Required | Default | Notes |
|---|---|---|---|
name | ✅ | — | A unique name you choose. Used in handlers (onInstruction({ program: "<name>" })) and generated types. |
program_id | ✅ | — | The base58 program address. |
instructions | ✅ | — | Instructions to match within this program (see below). |
idl | — | — | Path to an Anchor IDL JSON. If set, HyperIndex derives each instruction's args + accounts from it. Mutually exclusive with per-instruction inline args/accounts. |
handler | — | auto | Path to the file that registers this program's handlers. By default handler files are auto-loaded. |
instructions
Each entry selects one instruction of the program to index. Only name is
required, but in practice you'll add a discriminator so HyperIndex can tell your
instruction apart from the program's others.
| Field | Required | Default | Notes |
|---|---|---|---|
name | ✅ | — | The instruction name. For Anchor IDL programs this should match the IDL instruction (the snake_cased name is used to derive the default discriminator). Also the key in onInstruction({ instruction: "<name>" }). |
discriminator | — | — | Hex bytes that identify the instruction (e.g. "0xc1209b3341d69c81"). See discriminators. Without it, the instruction matches purely on program + filters and isn't decoded by discriminator. |
is_inner | — | unset | true = inner (CPI) only, false = top-level only, omitted = matches both. |
args | — | — | Inline argument schema (Borsh), { name, type } per arg. Requires accounts too. Mutually exclusive with the program's idl. See supported types. |
accounts | — | — | Inline ordered list of account names. The Nth name labels the Nth account. Requires args too. |
account_filters | — | — | Restrict matches by the pubkey in specific account positions (see below). |
field_selection | — | — | Opt into extra data on the event (see below). |
Field selection
By default a handler receives only the instruction itself. Opt into more data per instruction:
| Toggle | Adds to the event |
|---|---|
transaction_fields: true | event.transaction — signatures, fee payer, fee, compute units, success, account keys. |
token_balance_fields: true | event.transaction.tokenBalances — pre/post SPL Token balances. Implies transaction_fields. |
log_fields: true | event.logs — program logs scoped to this instruction. |
field_selection:
token_balance_fields: true # also gives you transaction fields
log_fields: true
true only, for nowEach toggle currently accepts true (all fields) only. Per-field name lists are
not yet supported.
Account filters
Match an instruction only when specific account positions hold specific pubkeys —
useful to index, say, only swaps that touch a particular pool or mint. Positions
are 0–5; within a position values are OR-ed, and across positions they are
AND-ed.
instructions:
- name: swap
discriminator: "0x09"
account_filters:
- position: 1
values:
- 58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2 # only this pool
Use any_of to OR several AND-groups together:
account_filters:
any_of:
- [ { position: 0, values: [So11111111111111111111111111111111111111112] } ]
- [ { position: 1, values: [EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v] } ]
Choosing what to index
Solana's highest-frequency programs (SPL Token, System) produce enormous volumes of instructions. Matching them directly can swamp a backfill. Two practical patterns:
- Index DeFi/protocol instructions and read value flow from token balances.
Enabling
token_balance_fieldson a protocol instruction gives you the transaction's net token movements without indexing everyTransfer. - Scope high-volume instructions with
account_filtersor a tight slot window (start_block/end_block) when you do need them.
Related
- Decoding & IDLs — discriminators, IDLs, inline schemas, argument types.
- Instruction Handlers — what arrives in the handler.
- Schema file — defining the entities you write to (same as EVM).