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
| Path | What lives there |
|---|---|
schema.graphql | The entity shapes consumers query |
config.yaml | Which 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.yaml | The 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.idstays the bare garden account address for GraphQL compatibility; don't convert it. - When a relationship changes, update both sides of it.
envio devpreserves the local database.bun run --cwd packages/indexer dev --restartis a destructive local replay; use it only when that's explicitly intended.- Envio v3 registrations use
indexer.onEventandindexer.contractRegister; the v2 patterns (generated imports,MockDb) are gone and must not come back.
Go deeper
packages/indexer/AGENTS.mdis the full package contract.- Envio's documentation covers the indexing framework itself.