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

Getting Started on Solana

This guide takes you from nothing to a running Solana indexer with a live GraphQL API. If you've used HyperIndex on EVM the workflow is identical: only the config and handlers differ.

Prerequisites

  • Node.js v22+ and pnpm. The commands below use pnpm/pnpx; npm, Yarn, and Bun work too if you swap the equivalents
  • Docker Desktop (for the local Postgres + GraphQL stack)
  • A HyperSync API token: the CLI's login flow sets this up for you, or generate one in the Envio Cloud portal. See API tokens.

1. Scaffold a project

pnpx envio init

Choose Solana at the ecosystem prompt, then pick the USDC Transfers (SPL Token instructions) template: a working indexer of every USDC transfer through the SPL Token program, with tests.

Non-interactive equivalent:

pnpx envio init svm template --template usdc-transfers --name my-indexer

The template scaffolds:

my-indexer/
├── config.yaml # chains + programs/instructions
├── schema.graphql # the entities you index into
├── src/
│ ├── handlers/…ts # your onInstruction / onSlot handlers
│ └── indexer.test.ts # tests, with simulated instructions
├── .env # ENVIO_API_TOKEN
└── package.json

envio init also runs codegen, installs dependencies, and initializes git.

2. Pick a start slot

start_slot in config.yaml is a slot number, not a block number. Three common choices:

start_slotIndexes from
latestThe head when the indexer is first deployed. Fastest way to see live data.
A few tens of thousands of slots below the headA short backfill, good for trying things out.
The slot your program was deployed atIts full history.

Check the current head to pick a number:

curl -s https://solana.hypersync.xyz/height
# => 440067639
History doesn't reach genesis yet

Mainnet goes back to around slot 403,000,000 (September 2026). A start_slot before that doesn't error - the indexer starts from the earliest indexed slot instead. See choosing a start slot.

3. Run it

pnpm install            # if you didn't let init do it
pnpm envio codegen # regenerate types from config.yaml + schema.graphql
pnpm envio dev # start Postgres + the indexer + GraphQL (Docker)

envio dev brings up the local stack and runs the indexer with hot reload. The GraphQL playground (Hasura) is at http://localhost:8080 (default admin secret testing). See Navigating Hasura.

To run the pieces separately:

pnpm envio local docker up   # start Postgres + Hasura
pnpm envio codegen
pnpm envio start # run the indexer against the running stack
Re-run codegen after config/schema changes

Editing config.yaml or schema.graphql (including adding a program, instruction, or IDL) requires pnpm envio codegen to regenerate the typed envio module and the entity types in .envio/.

4. Add your own program

Add an entry to the top-level programs list, then write a handler for it:

config.yaml
programs:
- name: MyProgram
program_id: MyPr0gram11111111111111111111111111111111111
idl: ./idls/my-program.json

With an idl (Anchor, Shank or Codama) every instruction it declares is indexable and you select them by name. Without one, declare the discriminator, accounts and args yourself - see Decoding Instructions.

src/handlers/MyProgram.ts
import { indexer } from "envio";

indexer.onInstruction(
{
program: "MyProgram",
instruction: "swap",
fields: { instruction: ["args", "accounts"], block: ["time"] },
},
async ({ instruction, context }) => {
// instruction.args and instruction.accounts are typed after codegen
},
);

A registration reads only the fields it lists in fields, and can narrow what it indexes with where - both are covered in Instruction Handlers. Re-run pnpm envio codegen after editing config.yaml.

Next steps