For AI agents: the documentation index is at /llms.txt. Markdown versions of pages are available by appending .md to the URL.
Skip to main content

Configuration File (config.yaml)

The config.yaml file defines your indexer's behavior, including which blockchain events to index, contract addresses, which chains to index, and various advanced indexing options. It is a crucial step in configuring your HyperIndex setup.

tip

Whenever you make changes in config.yaml that should affect generated types (e.g. adding events, contracts, or chains), run pnpm codegen to regenerate types and code for your event handlers.


Example

This is a basic ERC-20 config.yaml — it's enough on its own to get an indexer running across Ethereum Mainnet and Gnosis, tracking Approval and Transfer events on the UNI token.

# yaml-language-server: $schema=./node_modules/envio/evm.schema.json
name: erc20-indexer
description: ERC-20 Indexer
contracts:
- name: ERC20
events:
- event: "Approval(address indexed owner, address indexed spender, uint256 value)"
- event: "Transfer(address indexed from, address indexed to, uint256 value)"
chains:
- id: 1 # Ethereum Mainnet
start_block: 0
contracts:
- name: ERC20
address: "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" # UNI
- id: 100 # Gnosis Mainnet
start_block: 0
contracts:
- name: ERC20
address: "0x4537e328Bf7e4eFA29D05CAeA260D7fE26af9D74" # UNI

Next steps:

  • Define how each event updates your data → src/handlers
  • Shape the entities you'll query → schema.graphql
  • Need more than the basics? Keep reading for the full set of configuration options below.

Contracts Definition

The top-level contracts block defines each contract once — its events and per-event options. Each chain then references these contracts by name and supplies chain-specific values like the on-chain address (see Contracts (per chain)).

contracts:
- name: Greeter
events:
- event: "NewGreeting(address user, string greeting)"
- event: "ClearGreeting(address user)"

chains:
- id: 1
start_block: 0
contracts:
- name: Greeter
address: "0x9D02A17dE4E68545d3a58D3a20BbBE0399E05c9c"

Events Selection

The recommended way to declare events is by their human-readable signature directly under events:

contracts:
- name: Greeter
events:
- event: "NewGreeting(address user, string greeting)"
- event: "ClearGreeting(address user)"

Only the events listed here are indexed. To stop indexing an event, remove its entry.

Custom Event Names

You can assign custom names to events in config.yaml. This is handy when two events share the same name but have different signatures, or when you want a more descriptive name in your Envio project.

events:
- event: Assigned(address indexed recipientId, uint256 amount, address token)
- event: Assigned(address indexed recipientId, uint256 amount, address token, address sender)
name: AssignedWithSender

Using an ABI File

If you'd rather reference a JSON ABI file (e.g. when you have one already and want to pick a subset of events from it), use abi_file_path and refer to events by name:

contracts:
- name: Greeter
abi_file_path: ./abis/greeter.json
events:
- event: NewGreeting # signature comes from the ABI file

Event signatures are still the recommended default — they keep config.yaml self-contained and easier to review.

Field Selection

To improve indexing performance and reduce credits usage, the block and transaction fields on events contain only a subset of the fields available on the blockchain.

To access fields that are not provided by default, specify them using the field_selection option for your event:

events:
- event: "Assigned(address indexed user, uint256 amount)"
field_selection:
transaction_fields:
- transactionIndex
block_fields:
- timestamp

See all possible options in the Config File Reference or use IDE autocomplete for your help.

Global Field Selection

You can also specify fields globally for all events in the root of the config file:

field_selection:
transaction_fields:
- hash
- gasUsed
block_fields:
- parentHash

Try to use this option sparingly as it can cause redundant Data Source calls and increased credits usage.


Chains

Everything under the top-level chains field configures the networks your indexer connects to — data sources, start/end blocks, reorg behavior, and multichain semantics.

RPC

The rpc option configures an RPC data source per chain. It supports multiple URLs with explicit roles via the for field:

  • sync – use this RPC for historical sync.
  • realtime – use this RPC for low-latency head tracking once the indexer enters realtime mode. WebSocket endpoints (wss://...) are supported here.
  • fallback – use as a fallback when the primary source is unavailable.
Optional for HyperSync chains

For chains supported by HyperSync, rpc is not required — HyperSync is used as the primary data source out of the box. You can still add an RPC entry as a fallback for extra reliability. For chains without HyperSync, rpc is required and acts as the primary data source.

chains:
- id: 1
rpc:
- url: https://eth-mainnet.your-rpc-provider.com
for: sync
- url: wss://eth-mainnet.your-rpc-provider.com
for: realtime
- url: https://fallback.example.com
for: fallback

A short form is also supported when you only need a single RPC URL:

chains:
- id: 1
rpc: https://eth-mainnet.your-rpc-provider.com

After switching to a fallback source, HyperIndex automatically attempts to recover to the primary source 60 seconds later.

See the Rpc reference for advanced tuning options such as initial_block_interval, polling_interval, query_timeout_millis, and backoff parameters.

WebSocket Height Streaming

Pair wss:// URLs with for: realtime to improve head latency by streaming new block heights over a WebSocket connection.

chains:
- id: 1
rpc:
url: ${ENVIO_RPC_ENDPOINT}
ws: ${ENVIO_WS_ENDPOINT}
for: realtime
Experimental

WebSocket support for RPC sources is experimental. Please open a GitHub issue if you hit any problems.

Start Block

Set start_block on a chain to control the block at which the indexer begins ingesting data. Setting it to 0 is a safe default for HyperSync — it will automatically skip ahead to the first block that contains data for your configured contracts.

chains:
- id: 1
start_block: 0 # HyperSync will fast-forward to the first relevant block
contracts:
- name: Greeter
address: "0x9D02A17dE4E68545d3a58D3a20BbBE0399E05c9c"

For finer-grained control, see Per-Contract Start Block Override and the per-event start block tip below it.

End Block

Set end_block on a chain to stop indexing once that block is reached. Useful for backfills with a known cutoff or one-off snapshots.

chains:
- id: 1
start_block: 18000000
end_block: 19000000
contracts:
- name: Greeter
address: "0x9D02A17dE4E68545d3a58D3a20BbBE0399E05c9c"
Don't use this for tests

If you're capping the range to make a deterministic test run, prefer the built-in testing framework instead — it lets you pin block ranges or feed synthetic events without spinning up a real indexer.

Contracts (per chain)

Inside each chain you list the contracts you want to index on that chain — referenced by name from your top-level Contracts Definition. The chain-level entry is where you pin the on-chain address (or list of addresses) and, optionally, a per-contract start_block.

note

Addresses can be provided in checksum format or in lowercase. Envio accepts both and normalizes them internally.

Addresses

Single address:

chains:
- id: 1
start_block: 0
contracts:
- name: MyContract
address: "0xContractAddress"

Multiple addresses for the same contract:

chains:
- id: 1
start_block: 0
contracts:
- name: MyContract
address:
- "0xAddress1"
- "0xAddress2"
tip

If using a proxy contract, always use the proxy address, not the implementation address.

Per-Contract Start Block Override

By default, contracts use the chain start_block. You can also set a per-contract start_block to override it. Handy when:

  • Contracts were deployed at different blocks
  • You only need data from a contract starting at a specific block
  • You want to skip unnecessary historical data for some contracts
  • Works nicely with Dynamic Contract Registration
chains:
- id: 1 # ethereum-mainnet
start_block: 18000000 # Default start block for all contracts on this chain
contracts:
- name: ERC20
address:
- "0x1111111111111111111111111111111111111111"
- "0x2222222222222222222222222222222222222222"
start_block: 18500000 # Override for this contract
- name: Greeter
address: "0x9D02A17dE4E68545d3a58D3a20BbBE0399E05c9c"
# Uses chain default (18000000)
Per-event start block

For even finer control, you can also specify a start block per event from your handler using the where.block.number._gte filter on indexer.onEvent. See Event Handlers for the full API.

Indexer Without Contracts

The contracts field is optional in V3. You can run an indexer that only uses block handlers (indexer.onBlock) without declaring any contracts:

name: BlockHandlerOnly
chains:
- id: 1
start_block: 18000000

Storage

How indexed data is persisted — which backends to use and whether to keep raw event records around.

Storage Backends

By default, HyperIndex writes entities to Postgres. In V3 you can additionally enable ClickHouse as a second storage backend (experimental):

storage:
postgres: true
clickhouse: true

When both backends are enabled, you must route each entity explicitly via the @storage directive in schema.graphql:

# Stored in both Postgres and ClickHouse
type Transfer @storage(postgres: true, clickhouse: true) {
id: ID!
from: String!
to: String!
value: BigInt!
}

# Stored only in ClickHouse
type Snapshot @storage(clickhouse: true) {
id: ID!
blockNumber: BigInt!
}

envio dev automatically spins up a ClickHouse Docker container for local development. For envio start, provide the connection via the environment variables ENVIO_CLICKHOUSE_HOST, ENVIO_CLICKHOUSE_DATABASE, ENVIO_CLICKHOUSE_USERNAME, and ENVIO_CLICKHOUSE_PASSWORD.

warning

Do not run multiple indexers writing to the same ClickHouse database at the same time.

Envio Cloud currently supports ClickHouse on the Dedicated Plan.


Address Format

Use address_format to control how every address surfaced by the indexer (event fields like event.srcAddress / event.transaction.from, chain.<Contract>.addresses, addresses embedded in entity ids, etc.) is formatted.

address_format: lowercase # default: checksum
  • checksum (default) – EIP-55 checksummed mixed-case addresses.
  • lowercase – every address is lowercased globally. Useful when joining against another data source that stores addresses in lowercase, or when you want byte-for-byte deterministic ids without per-handler .toLowerCase() calls.

You can still call .toLowerCase() ad-hoc inside a handler when you only need a single value lowercased.


Ecosystem

ecosystem selects which chain family your indexer targets. EVM is the default and what every example above assumes, but the same config.yaml schema is shared with Fuel and Solana (SVM).

ecosystem: evm # default — also: fuel, svm

Most projects don't set this field explicitly. Use pnpx envio init fuel or pnpx envio init svm to scaffold non-EVM indexers — the generated config.yaml will already have ecosystem set correctly. See the Fuel and Solana guides for the ecosystem-specific options.


Environment Variables

Environment variable interpolation is supported anywhere in config.yaml, which is useful for keeping RPC URLs, addresses, or chain IDs out of source control.

chains:
- id: ${ENVIO_CHAIN_ID:-ethereum-mainnet}
contracts:
- name: Greeter
address: "${ENVIO_GREETER_ADDRESS}"

Run your indexer with custom environment variables:

ENVIO_CHAIN_ID=optimism ENVIO_GREETER_ADDRESS=0xYourContractAddress pnpm dev

Interpolation syntax:

  • ${ENVIO_VAR} – Use the value of ENVIO_VAR
  • ${ENVIO_VAR:-default} – Use ENVIO_VAR if set, otherwise use default

For more detailed information about environment variables, see our Environment Variables Guide.


Advanced

note

In ~95% of cases you don't need to touch any of these — the defaults are tuned for the common path. Reach for them only when you have a specific reason.

Handler File Path

Handlers are auto-discovered from src/handlers/. Override the directory with the top-level handlers option, or set a per-contract handler path when needed:

handlers: ./src/my-handlers # optional override of src/handlers
contracts:
- name: Greeter
handler: ./src/GreeterHandler.ts # optional per-contract path

Schema File Path

You can customize the path to the schema file using the schema option:

schema: ./path/to/schema.graphql

By default, the schema.graphql is expected to be in the root directory of your project.

Block Lag

Set block_lag on a chain to keep the indexer a fixed number of blocks behind the chain head. Defaults to 0.

chains:
- id: 1
start_block: 0
block_lag: 5
warning

Only set block_lag if you understand the trade-off — it intentionally trades head latency for additional reorg safety.

Rollback on Reorg

HyperIndex automatically handles blockchain reorganizations by default. To disable or customize this behavior, set the rollback_on_reorg flag in your config.yaml:

rollback_on_reorg: true # default is true

See detailed configuration options here.

Full Batch Size

Set full_batch_size to control how many events are processed in a single batch.

full_batch_size: 5000

Raw Events Storage

By default, HyperIndex doesn't store raw event data in the database to optimize performance and reduce storage requirements. However, you can enable this feature for debugging purposes or if you need to access the original event data.

To enable storage of raw events, add the following to your config.yaml:

raw_events: true

When enabled, all indexed events will be stored in the raw_events table in the database, which you can view through the Hasura interface. This is particularly useful for:

  • Debugging event processing issues
  • Verifying that events are being captured correctly
  • Creating custom queries against raw blockchain data

Note that enabling this option will increase database storage requirements and may slightly impact indexing performance.


Configuration Schema Reference

Explore detailed configuration schema parameters here:

For AI/LLM Systems

Recommended: Use the Config Schema Reference for programmatic access to schema information. The interactive viewer below is optimized for human users.

📋 Hierarchical Interactive Schema Explorer (Click to expand - For human reference only)
Loading ....

Now your configuration file is set, you're ready to start indexing with HyperIndex!