This is the golden path: from a bare contract address to a decoded, tip-following, queryable API - on your own machine, with no external data service.
1. Install the binary
curl -fsSL https://nuthatch-indexer.com/install.sh | sh
Or build it with cargo:
cargo install --git https://github.com/nightswatchhq/nuthatch nuthatch
2. Scaffold a nest from an address
init detects the chain, resolves the ABI (Sourcify first, then an Etherscan-class API), vendors it
locally, and generates the schema, views, and AI surface - no API key required.
nuthatch init 0xA0b86991c6218b36c1D19D4a2e9Eb0cE3606eB48 --alias usdc --chain mainnet
You now have a nest directory: nuthatch.toml, abis/, schema.json, views/, llms.txt.
--alias is the table prefix, so this contract’s events land in usdc__transfer, usdc__approval,
and so on. Leave it out and the contract is called c0, giving you c0__transfer - which works
identically, just reads worse in a query.
3. Run it
dev backfills from the deployment block, follows the tip, decodes every declared event, and serves an
HTTP API - all in one process.
nuthatch dev
# ✓ indexing USDC on mainnet - serving http://127.0.0.1:8288
Note - the default endpoints are free public RPCs. nuthatch ships them so this page works with zero setup, and they are fine for trying it out or following a low-traffic contract. They are shared and rate-limited, and under load they often return nothing rather than an error - so a deep backfill will crawl or stall. For anything you care about, point at your own node or a paid provider with
--rpc. See free public RPCs.
4. Query it
Point-read an entity, run analytical SQL over the hot tip ∪ sealed history, or read a derived view.
nuthatch sql 'SELECT "to", value FROM usdc__transfer ORDER BY block_number DESC LIMIT 5'
to and from are SQL reserved words, so double-quote them. nuthatch spots this one and tells you
so rather than just failing.
…or over HTTP:
curl 'http://127.0.0.1:8288/sql?q=SELECT+count(*)+FROM+usdc__transfer'
curl 'http://127.0.0.1:8288/balances?limit=5' # top holders - derived, no eth_call
curl http://127.0.0.1:8288/balance/0xSomeHolder # one address
Balances are derived from the Transfers you have indexed, so an address answers no balance until it
appears in that range - start from /balances if you want an address that definitely does.
What you just got
- A decoded database. Every declared event becomes a table
{alias}__{event}, with implicit columns (block_number,tx_hash,log_index,address, …) alongside the decoded fields. - Hot + cold storage. A redb tip store for point-reads, sealed content-addressed Parquet past finality, unified behind DuckDB SQL. See Storage & sealing.
- Derived state, no
eth_call. Addnuthatch recipe add total_supplyfor an ERC-20’s supply derived from Transfers - no archive node. See Recipes. - An admin UI and metrics at
/_admin/and/metrics. - An MCP server so an agent can drive it offline. See MCP.
Under two minutes. That’s the whole demo - install,
init,dev, query. Everything after this page is about going deeper: authored logic, factories, runtimes, upgrades, and operating it in production.
A word on the free public RPCs
nuthatch ships free public endpoints per chain so that init → dev works with zero setup. That is
the two-minute demo above, and it is deliberate. They are fine for trying it out, following the tip of
a quiet contract, or a modest recent-history backfill.
They are not fine for real work, and it’s better to hear that here than at 3am:
- They are rate-limited and shared. You queue behind everyone else on the same free tier from the same IP range; throughput varies by the hour.
- They fail intermittently, and not always loudly. A rate-limited endpoint may return an empty
result rather than an error. nuthatch fails over across the pool and retries, but a window every
endpoint refuses will stall -
/readyreportsstalledwhen that happens. - Deep backfills will crawl or stop. Full history over a busy contract is millions of
eth_getLogscalls. Expect a free endpoint to throttle you long before that finishes. - No archive guarantees. Many free endpoints prune old state, so a backfill from a 2020 deploy block can fail partway.
Use your own endpoint for anything you care about - your own node, or a paid provider:
nuthatch init 0xADDR --chain arbitrum-one --rpc https://your-endpoint.example/arbitrum
nuthatch dev --rpc https://your-endpoint.example/arbitrum # or set rpc_urls in nuthatch.toml
--rpc is repeatable and nuthatch round-robins across the pool with per-endpoint health tracking, so
listing two or three gets you failover as well as throughput. Every endpoint in a pool must be on the
same chain - nuthatch verifies this at startup and refuses a mixed pool, since indexing against
the wrong chain corrupts state silently.
Next
-
Run it in production - the whole path from a fresh box to a nest serving unattended, ending in a pre-flight checklist. Start here if this is going anywhere real.
-
Deploy it - systemd, Docker, and putting a proxy in front.
-
Performance - what it measures at, and the three things that decide your backfill’s wall clock.
-
Security - read this before exposing
/sqlto anyone you do not trust. -
Verifying a deployment - prove it works on your own hardware.
-
What is a nest? - the mental model
-
Build a nest -
nuthatch.toml, views, factories, recipes -
Run many nests - one runtime, one or more chains, tenancy included