Indexing / Data·EVM · Multi-chain
Ponder
Open-source TypeScript framework for EVM data indexing. Define contracts in `ponder.config.ts`, schema in `ponder.schema.ts`, and indexing functions that write to a Postgres-backed store; serves a GraphQL and SQL API and runs anywhere Node runs.
- 01self-hosted EVM indexers
- 02type-safe indexing functions in TypeScript
- 03custom GraphQL + SQL APIs from one codebase
- 04local-first development with hot reload
- 05subgraph replacements with viem ergonomics
- pnpm create ponder@latest
- pnpm add ponder
| Variable | Scope | Description |
|---|---|---|
| PONDER_RPC_URL_1 | Server | RPC URL for chainId 1 (Ethereum mainnet). Ponder reads `PONDER_RPC_URL_<chainId>` for each network defined in `ponder.config.ts`. Use a paid provider — public endpoints will rate-limit. |
| DATABASE_URL | Server | Postgres connection string for production deployments. SQLite is used by default in dev. |
Bootstrap with `pnpm create ponder@latest`. In `ponder.config.ts` define networks (`mainnet: { chainId: 1, transport: http(process.env.PONDER_RPC_URL_1) }`) and contracts with ABIs, addresses, and `startBlock`. In `ponder.schema.ts` use `onchainTable('account', t => ({ address: t.hex().primaryKey(), balance: t.bigint().notNull() }))`. Write indexing functions in `src/index.ts`: `ponder.on('ERC20:Transfer', async ({ event, context }) => { await context.db.insert(account).values({ address: event.args.to, balance: 0n }).onConflictDoUpdate(...) })`. Run `pnpm dev` (hot reload) then deploy. Query the auto-generated `/graphql` and `/sql` endpoints, or add custom routes in `src/api/index.ts` using the provided viem `context.client`.
- ⚑Free public RPC endpoints will rate-limit a Ponder backfill within minutes — use a paid provider (Alchemy, QuickNode, Ankr) for `PONDER_RPC_URL_<chainId>` or Ponder will stall and retry forever.
- ⚑Indexing functions are NOT parallelized across events for a single contract — heavy on-chain reads (`context.client.readContract`) inside handlers are the #1 cause of slow backfills; cache or move to a precomputed table.
- ⚑Schema drift: changing `ponder.schema.ts` requires a fresh database in dev (`pnpm ponder dev` auto-resets); in production use the migration system or you'll deploy a broken indexer.
- ⚑Reorg handling is automatic up to the configured depth, but if your handler triggers external side effects (webhooks, emails) you must guard against re-execution after reorgs.
- ⚑Ponder is EVM-only — Solana, Sui, Aptos, Bitcoin are out of scope; pick a different indexer for non-EVM chains.