Understanding Generated Indexing Files
Overview
In V3, the local generated package is gone. Code generation now writes a single ambient declaration file at .envio/types.d.ts (git-ignored by .envio/.gitignore) and wires it into your project through a small envio-env.d.ts file at the project root. Everything you used to import from generated is now exported from the envio package.
These generated declarations form the type-level backbone of your blockchain indexer, translating your configuration, schema, and event handlers into the strongly-typed runtime values exposed by envio.
Important: The contents of
.envio/should never be manually edited. Any changes will be overwritten the next time code generation runs.
What V3 Emits
| File / location | Purpose |
|---|---|
.envio/types.d.ts | Ambient TypeScript declarations describing your contracts, events, entities, enums, and chains. |
envio-env.d.ts (root) | Tiny shim that references .envio/types.d.ts so the compiler picks it up. |
.envio/.gitignore | Written once and never overwritten. Ignores types.d.ts only. |
src/Indexer.res | ReScript projects only. Exposes the indexer to ReScript handlers. |
.envio/cache/ (optional) | Local cache of Effect API results, populated via the dev console. |
The generated/ directory used by V2 (with ReScript sources, JS shims, and a per-project package.json) is no longer produced.
Purpose of Generated Files
Generated files serve several critical functions:
- Type-Safe Data Access - They provide strongly-typed interfaces to interact with your defined entities through
envio. - Event Processing - They describe each contract's events so
indexer.onEvent({ contract, event }, ...)is fully type-checked. - Database Interactions - They generate the entity types and helper signatures used by
context.<Entity>andindexer.<Entity>. - Runtime Orchestration - They feed into the
indexervalue (chains, contracts, entities) that orchestrates indexing.
Real-World Example: Uniswap V4 Indexer
Let's examine how specific elements from a real Uniswap V4 indexer translate into generated declarations.
From Schema to Generated Types
For a schema entity like this:
type Pool {
id: ID!
chainId: BigInt!
currency0: String!
currency1: String!
fee: BigInt!
tickSpacing: BigInt!
hooks: String!
numberOfSwaps: BigInt! @index
createdAtTimestamp: BigInt!
createdAtBlockNumber: BigInt!
}
The codegen process emits a TypeScript type you can import from envio:
import type { Entity } from "envio";
// Equivalent to importing the `Pool` named type directly.
type Pool = Entity<"Pool">;
// Shape of the generated entity:
// {
// id: string;
// chainId: bigint;
// currency0: string;
// currency1: string;
// fee: bigint;
// tickSpacing: bigint;
// hooks: string;
// numberOfSwaps: bigint;
// createdAtTimestamp: bigint;
// createdAtBlockNumber: bigint;
// }
You read and write Pool entities through the type-safe context and indexer APIs:
// Inside a handler
const pool = await context.Pool.get(id);
context.Pool.set({ id, chainId, currency0, currency1, fee, tickSpacing, hooks, numberOfSwaps, createdAtTimestamp, createdAtBlockNumber });
// Inside a test, on a test indexer from createTestIndexer()
indexer.Pool.set({ /* ... */ });
const stored = await indexer.Pool.getOrThrow(id);
From Config to Generated Event Handlers
Given a contract event in config.yaml:
contracts:
- name: PoolManager
events:
- event: Swap(bytes32 indexed id, address indexed sender, int128 amount0, int128 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick, uint24 fee)
Codegen widens the indexer.onEvent overloads so that the following call is fully typed end-to-end (event params, return type, context.chain, etc.):
import { indexer } from "envio";
import type { EvmEvent } from "envio";
indexer.onEvent(
{ contract: "PoolManager", event: "Swap" },
async ({ event, context }) => {
const { id, sender, amount0, amount1, sqrtPriceX96, liquidity, tick, fee } = event.params;
// ...
},
);
// The full event payload type is also available as a generic:
type PoolManagerSwapEvent = EvmEvent<"PoolManager", "Swap">;
type PoolManagerSwapBlock = EvmEvent<"PoolManager", "Swap">["block"];
From Multi-Chain Config to Generated Chain Handlers
Your config has multiple chains:
chains:
- id: 1 # Ethereum Mainnet
# ...
- id: 10 # Optimism
# ...
- id: 42161 # Arbitrum
# ...
Codegen turns the chain set into a literal EvmChainId union (FuelChainId and SvmChainId on other ecosystems) and exposes per-chain helpers under indexer.chains:
import { indexer } from "envio";
import type { EvmChainId } from "envio";
// EvmChainId is `1 | 10 | 42161`
const mainnet = indexer.chains[1];
const optimism = indexer.chains[10];
const arbitrum = indexer.chains[42161];
// `chain.id` is also typed inside handler/where callbacks:
indexer.onBlock(
{
name: "Heartbeat",
where: ({ chain }) => {
// chain.id is narrowed to the configured EvmChainId union
return chain.id === 1;
},
},
async ({ block, context }) => {
// context.chain.id is typed as well
},
);
getGeneratedByChainId(...) from V2 has been replaced by indexer.chains[chainId].
When to Run Code Generation
You should run code generation using the Envio CLI whenever you:
pnpm envio codegen
Codegen should be run after:
- Modifying your
config.yamlfile - Changing your GraphQL schema
- Switching to a new contract or ABI
- After pulling changes from version control
Handler files are not an input to codegen, so editing them doesn't need it.
Note: changes to handler files in V3 no longer trigger automatic codegen on
pnpm dev.
Troubleshooting Generation Errors
When code generation fails, the error points to an issue in config.yaml, schema.graphql or an ABI. It reads Failed parsing config, followed by the specific cause.
Configuration Errors
A YAML syntax error, a missing required field, an unknown field or a malformed address in config.yaml stops codegen. Add the # yaml-language-server: $schema=./node_modules/envio/evm.schema.json comment at the top of the file so your editor flags these as you type. See the Configuration File guide for every field.
Schema Errors
Schema errors name the entity and field. Common ones:
No 'id' field found on entity Pool- every entity needs anid.The [Swap!]! field type requires an explicit @derivedFrom- a list of entities needs@derivedFrom.No type definition 'Int8' exists in schema- the type isn't a supported scalar, an entity or an enum.Schema contains the following reserved keywords: ...- rename the entity, enum or enum value.
See the Schema guide for the full rules.
Handler Errors
Codegen doesn't read your handlers. Mistakes in them, such as a wrong entity field or an unselected event.transaction field, are TypeScript errors. Run pnpm tsc --noEmit to see them. From v3.14 the indexer also runs this check on start and won't start until handler files type-check. If typescript or a tsconfig.json is missing, it logs a warning and skips the check. Import everything from envio.
Relationship with Setup Files
The generated declarations directly reflect the structure defined in your setup files:
- config.yaml → Determines which chains, contracts, and events are indexed
- schema.graphql → Defines the entities and relationships that are generated
- handlers in
src/handlers/→ Provide the business logic that the generated types describe
Best Practices
- Never modify generated files directly - Always change the source files
- Run codegen before starting your indexer - Ensure all declarations are up to date
- Check error messages carefully - They often pinpoint issues in your setup files
- Commit
envio-env.d.tsand.envio/.gitignore- The shim is part of the project. The.gitignorecodegen writes keeps.envio/types.d.tsout of git and leaves.envio/cache/trackable, so you choose whether to commit a saved effect cache.
Summary
Generated declarations form the critical bridge between your indexing specifications and the actual runtime execution. While you shouldn't modify them directly, understanding their structure and purpose can help you debug issues and optimize your indexing process.
If you encounter persistent errors related to generated files, ensure your configuration, schema, and handlers follow Envio's best practices, or contact support for assistance.