> For the complete documentation index, see [llms.txt](https://docs.envio.dev/llms.txt).

# 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](https://nodejs.org) 22.15.0 or newer and [pnpm](https://pnpm.io). The commands below use `pnpm`/`pnpx`; npm, Yarn, and Bun work too if you swap the equivalents
- [Docker Desktop](https://www.docker.com/products/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](https://envio.dev/app/api-tokens). See [API tokens](/docs/HyperSync/api-tokens).

## 1. Scaffold a project

```bash
pnpx envio init
```

Choose **Svm** 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.

The non-interactive equivalent needs an Envio API token, so create one at [envio.dev/app/api-tokens](https://envio.dev/app/api-tokens) and export it first, or pass `--api-token <token>`.

```bash
export ENVIO_API_TOKEN=your_token_here
pnpx envio init svm template --template usdc-transfers --name my-indexer -d my-indexer
```

The template scaffolds:

```text
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_slot` | Indexes from |
| --- | --- |
| `latest` | The head when the indexer is first deployed. Fastest way to see live data. |
| A few tens of thousands of slots below the head | A short backfill, good for trying things out. |
| The slot your program was deployed at | Its full history. |

Check the current head to pick a number:

```bash
curl -s https://solana.hypersync.xyz/height
# => 450012618
```

:::note History doesn't reach genesis yet
As of September 2026, mainnet goes back to around slot 391,000,000. A `start_slot`
before that doesn't error - the indexer starts from the earliest indexed slot
instead. See
[choosing a start slot](/docs/HyperIndex/solana/configuration#choosing-an-endpoint-and-a-start-slot).
:::

## 3. Run it

```bash
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. It doesn't watch files, so restart it after changes. The
GraphQL playground (Hasura) is at **http://localhost:8080** (default admin
secret `testing`). See [Navigating Hasura](/docs/HyperIndex/navigating-hasura).

To run the pieces separately:

```bash
pnpm envio local docker up   # start Postgres + Hasura
pnpm envio codegen
pnpm envio start             # run the indexer against the running stack
```

:::tip 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:

```yaml title="config.yaml"
programs:
  - name: MyProgram
    program_id: MyProgram1111111111111111111111111111111111
    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](/docs/HyperIndex/solana/decoding).

```typescript title="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](/docs/HyperIndex/solana/instruction-handlers). Re-run
`pnpm envio codegen` after editing `config.yaml`.

## Next steps

- [Configuration](/docs/HyperIndex/solana/configuration): every `config.yaml` field for Solana.
- [Instruction Handlers](/docs/HyperIndex/solana/instruction-handlers): the full instruction object, account activity, CPIs, and testing.
- [Decoding Instructions](/docs/HyperIndex/solana/decoding): IDLs, discriminators, inline layouts, supported types.
- [Deploy to Envio Cloud](/docs/HyperIndex/hosted-service): host your Solana indexer the same way as EVM.
- [How to Index and Track Stablecoin Transfers on Solana](/blog/index-solana-stablecoin-transfers): a tested tutorial that tracks USDC, USDT, PYUSD and USDG across both token programs, including inner transfers.
