ponder
Skill7 starsChanged 4 months agoMITView on GitHub
Build EVM blockchain data indexers using Ponder (ponder.sh) - an open-source TypeScript framework for indexing smart contract events, transactions, and traces into custom database schemas with type-safe APIs. Use when the user mentions ponder, blockchain/EVM indexing, onchain data pipelines, subgraph replacement, or wants to index smart contract events into a queryable database.
- Reads credentials
4 other projects use a version of this.
Adopted by
Most recently taken up by
- Quinnod345/pondertheir own version, first seen Nov 8, 2026
- github/awesome-copilottheir own version, first seen Nov 8, 2026
- 0xvikram/backboard-skillstheir own version, first seen Oct 20, 2026
- scaffold-eth/scaffold-eth-2their own version, first seen Oct 8, 2026
Other versions4 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 4
- github/awesome-copilot★ 41ksame name
- scaffold-eth/scaffold-eth-2★ 2.1ksame name
- Quinnod345/ponder★ 6same name
- 0xvikram/backboard-skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository2 other files it gives its agents.
- review-workflowSkill
- shortcutSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
22 rules. 0 are common, 3 are distinctive, and 19 are very specific to this project.
0
Common
Most of the 4 edited versions we read keep these.
3
Distinctive
This author's own choices. Worth a look.
19
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 63
Must exist at project root.
- Distinctive: line 175
Events: Default choice for most indexing use cases.
- Very specific: line 180
Only enable when you need gasUsed, logs from other contracts, or tx status.
- Distinctive: line 209
All addresses are lowercase since v0.12.
- Very specific: line 210
Use t.hex() for addresses and byte data, t.bigint() for uint256/int256.
- Distinctive: line 211
Always add indexes on columns used in GraphQL filters or API WHERE clauses.
- Very specific: line 248
Run pnpm create ponder and select template
- Very specific: line 249
Add RPC URL to .env.local as PONDER_RPC_URL_<CHAIN_ID>
- Very specific: line 250
Update ponder.config.ts with contract address, ABI, and startBlock
- Very specific: line 252
Write indexing functions in src/index.ts, then run ponder dev
- Very specific: line 256
Add ABI file with as const assertion
- Very specific: line 257
Add contract entry to ponder.config.ts (abi, chain, address, startBlock)
- Very specific: line 258
Add tables to ponder.schema.ts for the data you want to store
- Very specific: line 259
Write handler in src/ using ponder.on("ContractName:EventName", ...)
- Very specific: line 263
Import parseAbiItem from viem to define the creation event
- Very specific: line 264
Use factory() in config: address: factory({ address, event, parameter })
- Very specific: line 265
Write handler using event.log.address to identify the child contract
- Very specific: line 271
Import db from ponder:api and schema from ponder:schema
- Very specific: line 272
Add Hono route (app.get("/path", ...)) with Drizzle queries on db.sql
- Very specific: line 277
Add chain configs for each chain in ponder.config.ts
- Very specific: line 278
Use composite PKs with chainId if using experimental_isolated
- Very specific: line 279
Use context.chain.id in handlers when chain-specific logic is needed
“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Ponder Skill
What is Ponder
Ponder is an open-source TypeScript framework that indexes EVM blockchain data into Postgres with type-safe APIs. It replaces subgraphs with 10-15x faster indexing, hot reloading, and zero-codegen type safety.
Architecture flow:
ponder.config.ts (what to index) -> ponder.schema.ts (where to store) -> src/*.ts (how to transform) -> src/api/index.ts (how to query)
Stack: v0.16.x, Drizzle ORM, Hono for HTTP, viem for Ethereum.
Quick Start
Scaffold
pnpm create ponder # also: npm, yarn, bunRequirements
- Node >= 18.18, TypeScript >= 5.0.4, viem >= 2, hono >= 4.5
tsconfig.json (exact)
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "bundler",
"esModuleInterop": true,
"skipLibCheck": true
}
}ponder-env.d.ts
Must exist at project root. Run ponder codegen to generate it.
Environment Variables
PONDER_RPC_URL_<CHAIN_ID>- RPC endpoint per chain (e.g.,PONDER_RPC_URL_1for mainnet)DATABASE_URL- Postgres connection string (production)DATABASE_SCHEMA- Schema isolation name (production)
Minimal Working Example
ponder.config.ts:
import { createConfig } from "ponder";
import { http } from "viem";
import { ERC20Abi } from "./abis/ERC20Abi";
export default createConfig({
chains: {
mainnet: { id: 1, rpc: process.env.PONDER_RPC_URL_1 },
},
contracts: {
USDC: {
abi: ERC20Abi,
chain: "mainnet",
address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
startBlock: 6082465,
},
},
});ponder.schema.ts:
import { onchainTable } from "ponder";
export const transfers = onchainTable("transfers", (t) => ({
id: t.text().primaryKey(),
from: t.hex().notNull(),
to: t.hex().notNull(),
amount: t.bigint().notNull(),
timestamp: t.integer().notNull(),
}));src/index.ts:
import { ponder } from "ponder:registry";
import { transfers } from "ponder:schema";
ponder.on("USDC:Transfer", async ({ event, context }) => {
await context.db.insert(transfers).values({
id: event.id,
from: event.args.from,
to: event.args.to,
amount: event.args.value,
timestamp: Number(event.block.timestamp),
});
});src/api/index.ts:
import { Hono } from "hono";
import { db } from "ponder:api";
import { graphql } from "ponder";
import * as schema from "ponder:schema";
const app = new Hono();
app.use("/graphql", graphql({ db, schema }));
export default app;CLI Commands
| Command | Purpose |
ponder dev | Development with hot reload, PGlite, port 42069 |
ponder start --schema <name> | Production with Postgres |
ponder serve --schema <name> | API only (no indexing), for horizontal scaling |
ponder codegen | Regenerate types and ponder-env.d.ts |
ponder db list | List schemas in database |
ponder db prune | Remove unused schemas |
Exit codes: 75 = retryable (safe to auto-restart), 1 = fatal (check logs).
Decision Heuristics
Ordering Mode
| Mode | When to Use |
multichain (default) | Per-chain ordering, low latency. Most projects. |
omnichain | Cross-chain consistency needed (bridges, aggregators, cross-chain protocols). |
experimental_isolated | Max performance. Requires chainId in ALL table primary keys. |
Table vs View
- Table (
onchainTable): Data written by indexing functions. Source of truth. - View (
onchainView): Aggregations/rollups computed at query time. No writes, no store API.
Store API vs Raw SQL
- Store API (
context.db): Always prefer in indexing functions. 100-1000x faster (batched writes). - Raw SQL (
db.sql): Only for complex multi-table updates that Store API cannot express.
Factory vs Explicit Addresses
factory(): Contract instances created dynamically at runtime (Uniswap pools, token clones).- Explicit
address: Known addresses at config time. Use array for multiple fixed addresses.
Call Traces vs Events
- Events: Default choice for most indexing use cases.
- Call traces (
includeCallTraces: true): Only when you need function inputs/outputs not emitted as events. Requiresdebug_traceBlockByNumberRPC support.
includeTransactionReceipts
Only enable when you need gasUsed, logs from other contracts, or tx status. Adds significant RPC overhead.
PGlite vs Postgres
- PGlite: Dev only (
ponder devuses it automatically). - Postgres: Any shared or production environment.
GraphQL vs Custom Routes
- GraphQL middleware: Standard CRUD with built-in filtering, sorting, pagination.
- Custom Hono routes: Complex joins, aggregations, non-standard responses, or non-GraphQL APIs.
Gotchas and Anti-Patterns
Setup
- ABIs MUST use
as constassertion for type inference:export const MyAbi = [...] as const; // REQUIRED ponder-env.d.tsmust exist and be current. Runponder codegenafter config changes.- Set
startBlockto the contract deployment block, NOT0. Setting0scans entire chain history (hours vs seconds). - Local dev nodes (Anvil/Hardhat): set
disableCache: truein chain config. - Table/schema names:
snake_case, max 45 characters.
Schema
- ANTI-PATTERN: String concatenation for composite keys (
${owner}-${spender}). USE:primaryKey({ columns: [table.owner, table.spender] }). - All addresses are lowercase since v0.12. Never use checksummed addresses.
- Use
t.hex()for addresses and byte data,t.bigint()for uint256/int256. - Always add indexes on columns used in GraphQL filters or API WHERE clauses.
Indexing
- Virtual module imports:
ponder:registry,ponder:schema,ponder:api. NOT regular file paths. context.db(indexing functions, read-write) vsdbfromponder:api(API routes, read-only).- ANTI-PATTERN: Writing to database in API routes.
dbfromponder:apiis read-only. onConflictDoUpdatecallback receives the EXISTING row, not the values you passed to.values().context.client.readContractautomatically scopes reads to the current event's block number.- Factory contracts: use
event.log.addressto get which child contract emitted the event. - Multi-chain shared handlers: use
context.chain.idto distinguish chains. - Execution order per chain: block number -> tx index -> log index (deterministic).
event.idis a 75-digit string, globally unique across chains.
Deployment
ponder startrequires--schemaflag (orDATABASE_SCHEMAenv var).experimental_isolatedordering requireschainIdin ALL table primary keys.
Reference Navigation
Load the appropriate reference based on the task:
| Task | Reference |
| Configure chains, contracts, factory, accounts, blocks | references/config.md |
| Define tables, columns, relations, views, enums | references/schema.md |
| Write event handlers, DB operations, contract reads | references/indexing.md |
| Set up GraphQL, SQL over HTTP, custom API routes | references/api.md |
| Build frontend with @ponder/client, React, Next.js, tRPC | references/frontend.md |
| Deploy, scale, debug, monitor, configure RPC | references/production.md |
| Need a complete working example to start from | references/recipes.md |
Common Task Checklists
Scaffold a New Project
- Run
pnpm create ponderand select template - Add RPC URL to
.env.localasPONDER_RPC_URL_<CHAIN_ID> - Update
ponder.config.tswith contract address, ABI, andstartBlock - Define schema in
ponder.schema.ts - Write indexing functions in
src/index.ts, then runponder dev
Add a New Contract to Index
- Add ABI file with
as constassertion - Add contract entry to
ponder.config.ts(abi, chain, address, startBlock) - Add tables to
ponder.schema.tsfor the data you want to store - Write handler in
src/usingponder.on("ContractName:EventName", ...)
Add a Factory Contract
- Import
parseAbiItemfrom viem to define the creation event - Use
factory()in config:address: factory({ address, event, parameter }) - Write handler using
event.log.addressto identify the child contract - Schema tables may need composite PKs including the child contract address
Add a Custom API Endpoint
- Open
src/api/index.ts - Import
dbfromponder:apiand schema fromponder:schema - Add Hono route (
app.get("/path", ...)) with Drizzle queries ondb.sql
Set Up Multi-Chain Indexing
- Choose ordering mode (see Decision Heuristics above)
- Add chain configs for each chain in
ponder.config.ts - Use composite PKs with
chainIdif usingexperimental_isolated - Use
context.chain.idin handlers when chain-specific logic is needed
Deploy to Production
- Provision Postgres v14-17 with <50ms latency to app server
- Set
DATABASE_URLand choose aDATABASE_SCHEMAname - Run
ponder start --schema <name> - Health checks:
/health(always 200),/ready(503 during backfill, 200 when caught up) - For zero-downtime redeploys, use
--views-schemapattern
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

