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 Instructions.
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 SPL Token transfers
ecosystem: svm
chains:
- id: solana
start_slot: 437000000 # a SLOT number, not a block number
programs:
# --- decoded from an IDL ---
- name: Jupiter
program_id: JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4
idl: ./idls/jupiter.json # every usable instruction of the IDL is indexable
# --- decoded from an inline layout (no IDL) ---
- name: SplToken
program_id: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
instructions:
- name: transfer
discriminator: "0x03"
accounts: [source, destination, authority]
args:
- name: amount
type: u64
Handlers then select what they index and which fields they read - see Instruction Handlers.
Top-level fields
| Field | Required | Default | Notes |
|---|---|---|---|
name | ✅ | - | Project name. |
ecosystem | ✅ | - | Must be svm. |
chains | ✅ | - | One or more Solana clusters to index (see below). |
programs | - | - | Programs to index. Declared once for the whole project, not per chain. |
description | - | - | Free-text description. |
schema | - | schema.graphql | Path to your GraphQL schema. |
handlers | - | src/handlers | Directory that handler files are auto-loaded from. |
full_batch_size | - | 5000 | Target number of instructions processed per batch. |
storage | - | postgres: true | Storage backends (postgres, clickhouse). |
disable_default_cross_chain | - | false | Make entities and effect caches per-chain instead of shared. |
For Solana, several EVM top-level fields don't apply: contracts,
rollback_on_reorg, save_full_history, raw_events, field_selection,
address_format and bytes_type. Reorgs are handled automatically on the
HyperSync source (it rolls back on reorg), field selection is per handler (the
fields option),
addresses are base58, and Bytes is always a Uint8Array.
chains
Each entry is one Solana cluster.
| Field | Required | Default | Notes |
|---|---|---|---|
id | ✅ | - | The cluster: the label solana (7565164), solana-devnet (7565165), or an explicit number for another cluster. SVM has no native numeric chain id, so Envio assigns the label ids. |
start_slot | ✅ | - | The slot to start indexing from, or latest to start from the current head (see below). |
end_slot | - | - | Stop at this slot. Useful for finite backfills. |
block_lag | - | - | Stay this many slots behind the head. |
hypersync_config | - | the chain id's public endpoint | Block containing url. Optional for solana and solana-devnet; required for any other chain id. |
rpc | - | - | Accepted but unused: instruction sync is served by HyperSync. |
skip | - | false | Exclude the chain from indexing and migrations. |
chains:
- id: solana
start_slot: 437000000
- id: solana-devnet
start_slot: latest
EVM chains use the public numeric chain ID. Solana clusters have no such id, so
you write solana or solana-devnet and HyperIndex maps them to 7565164 /
7565165 - the values you see as context.chain.id in handlers and as the key
in test indexer chain
overrides. Before v3.8 the Solana chain id was 0.
Starting from the head
start_slot: latest resolves the current head once, when the indexer is first
deployed, and persists the concrete slot. A normal resume (a crash or a process
restart) picks up from the stored slot, so downtime is backfilled rather than
skipped; envio dev/envio start with -r re-resolves it against the head at
that time.
Choosing an endpoint and a start slot
The endpoint follows the chain id, so the only real decision is the start slot:
| Chain | Chain id | Endpoint |
|---|---|---|
| Mainnet | solana (7565164) | https://solana.hypersync.xyz |
| Devnet | solana-devnet (7565165) | https://solana-devnet.hypersync.xyz |
Each endpoint serves history back to its earliest indexed slot, not to genesis -
mainnet is around slot 403,000,000 as of September 2026, and we keep
extending it backwards. GET <endpoint>/height returns the current head.
start_slot before the earliest indexed slot doesn't errorThe indexer starts from the earliest indexed slot instead, so a backfill can
look healthy while silently skipping every slot before that. To test a candidate
slot, send a one-slot bounded query and compare next_slot to from_slot:
equal means the slot isn't indexed yet, from_slot + 1 means served (see the
HyperSync curl examples). Need history
further back? Tell us on Discord.
programs
Programs are defined once for the whole project; program_id says where each one
lives on every chain.
| Field | Required | Default | Notes |
|---|---|---|---|
name | ✅ | - | A unique name you choose. Used in handlers (onInstruction({ program: "<name>" })) and in generated types. |
program_id | ✅ | - | Base58 program address. A single value is allowed only when the config defines one chain; with several, give a mapping keyed by chain id, naming every one of them and writing _ for a chain the program isn't deployed on. |
idl | - | - | Path to an IDL JSON (Anchor 0.30+, legacy Anchor, Shank or Codama), relative to config.yaml. Every usable instruction becomes indexable, and onInstruction selects by name. |
instructions | - | - | Instructions to index. Required when there's no idl; with an idl, use it only to override or add instructions (see below). |
programs:
- name: SplToken
program_id:
solana: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
solana-devnet: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
- name: MyProgram
program_id:
solana: MyPr0gram11111111111111111111111111111111111
solana-devnet: _ # not deployed there
instructions
Each entry declares one instruction of the program.
| Field | Required | Default | Notes |
|---|---|---|---|
name | ✅ | - | The instruction name, unique per program. It's the key in onInstruction({ instruction: "<name>" }) and in the generated types. |
discriminator | ✅ | - | 0x-prefixed hex prefix of the instruction data to dispatch on, of any whole number of bytes; an 8-byte value is the standard Anchor discriminator. The empty prefix "0x" matches every instruction of the program. See discriminators. |
accounts | - | - | Positional account slots, in the order the program expects them. The Nth entry names slot N and surfaces it as instruction.accounts.<name>. |
args | - | - | Borsh argument layout. Setting it attaches a decoder that also filters - see args is also a filter. |
With an idl, both accounts and args are required on a row whose name the
IDL declares (that row replaces the IDL's version of it); a row with a new name
adds an instruction the IDL didn't declare.
instructions:
- name: transferChecked
discriminator: "0x0c"
accounts: [source, mint, destination, authority]
args:
- name: amount
type: u64
- name: decimals
type: u8
Account slots
Entries in accounts are positional, and three forms are accepted:
| Form | Meaning |
|---|---|
payer | A slot the call always carries. Surfaces as instruction.accounts.payer. |
?authority | An optional slot. The key is absent from instruction.accounts when the call omits the slot or fills it with the program id. |
_ | Holds a position without naming it, so the slots after it keep theirs. Never surfaced, never filterable, and the list may not end with one. |
Naming a slot is what makes it filterable from a handler's
where.accounts;
the raw positional addresses are available either way through
instruction.accountArguments.
Choosing what to index
Solana's highest-frequency programs (SPL Token, System) produce enormous volumes
of instructions, and matching them unfiltered can swamp a backfill. Narrow a
registration with a
where
filter on account keys, or read value flow from
account activity
on a protocol instruction instead of indexing every transfer.
Related
- Decoding Instructions: IDLs, discriminators, inline layouts, argument types.
- Instruction Handlers: what arrives in the handler, field selection, and filters.
- Schema file: defining the entities you write to (same as EVM).