Skip to main content

Indexer

packages/indexer runs the Envio pipeline that turns contract events into the GraphQL read models every surface queries. It exists so apps never crawl the chain: gardens, memberships, vaults, and module state arrive as queryable entities instead of raw logs.

One boundary defines this package: it indexes protocol events, not EAS attestations. Work, approval, and assessment records are read through shared's EAS data layer; keeping attestations out of Envio keeps the two truth paths independently verifiable.

Map​

PathWhat lives there
schema.graphqlThe entity shapes consumers query
config.yamlWhich contracts and events are indexed, per chain
src/EventHandlers.ts and src/handlers/Event-to-entity projection logic
.envio/Generated types; regenerate rather than edit
test/Mocha suites for handlers and contract events
docker-compose.indexer.yamlThe local stack: Postgres, the indexer, and its GraphQL endpoint

Run and test​

bun run --cwd packages/indexer check:indexing-boundary
bun run --cwd packages/indexer test
bun run --cwd packages/indexer build

After any change to schema.graphql, config.yaml, or generated types, run bun run --cwd packages/indexer codegen first; skipping it makes failures show up late. Local development runs the indexer in Docker through the team stack.

How it connects​

Contract events in, GraphQL out. The client and admin read these models through shared's data layer. The agent does not: its reporting services (packages/agent/src/services/reporting/) send their GraphQL queries straight to the indexer URL, so a schema change has two sets of readers to check. The hosted Envio service serves production. Merging an indexer change does not deploy it; the hosted deployment is a separate, deliberate step.

Conventions that will bite you​

  • Every persisted entity carries a chainId, and IDs are composite with the chain to prevent cross-chain collisions. One documented exception: Garden.id stays the bare garden account address for GraphQL compatibility; don't convert it.
  • When a relationship changes, update both sides of it.
  • envio dev preserves the local database. bun run --cwd packages/indexer dev --restart is a destructive local replay; use it only when that's explicitly intended.
  • Envio v3 registrations use indexer.onEvent and indexer.contractRegister; the v2 patterns (generated imports, MockDb) are gone and must not come back.

Go deeper​