Self-host
Run the ABX resolver and effects worker on your own infrastructure.
ABX ships two reference services. The resolver serves metadata. The effects worker renders derived images and traits for code projects. Neither service holds an onchain signing key.
Local data directory
Every command that reads or writes local state — the SQLite projection, the managed Arweave key, the content index — resolves ONE data directory per invocation. Predicting which one a command uses comes down to three rules, checked in order:
ABX_DATA_DIR, if set, always wins. No other rule below runs. Set it to pin a command at a specific node regardless of where you run it from.- Otherwise,
<current directory>/.abx-self-host, if it already exists, wins. Running a command from the same directory you deployed a project from always finds that project. - Otherwise, a handful of read-only commands —
abx status,abx state,abx verify,abx doctor,abx capabilities,abx tokens,abx tokenuri,abx contracturi,abx inspect, andabx minter show— search upward for an existing.abx-self-host, the waygitfinds a repository root from a subdirectory. The search stops at (but still checks) your home directory, a directory containing.git, or the filesystem root — it never wanders into an unrelated directory tree, and it never merges two data directories: the first one it finds wins outright. When one of these commands answers from a directory other than the one you ran it from, it prints which directory that was.
Every other command — anything that deploys, mints, registers, indexes, or otherwise writes —
skips step 3 entirely and resolves to <current directory>/.abx-self-host, creating it there if it
doesn't exist yet. A write never lands in a directory you didn't cd into.
cd my-project/contracts/src # a subdirectory of where you ran `abx deploy`
abx status # finds my-project/.abx-self-host and says so
abx add 0xSomeOtherContract # writes to ./.abx-self-host here instead — a NEW, empty nodeResolver
Run it locally:
abx serveDeploy it to a supported host:
abx deploy-resolver --provider <fly|render|vps>The resolver replays contract events, stores the reconstructed state, and watches for new blocks. Its main public routes are:
| Route | Result |
|---|---|
/t/{chainId}/{address}/{tokenId} | Token metadata |
/c/{chainId}/{address} | Collection metadata |
/api/project/{address} | Reconstructed project state |
/d/{chainId}/{address} | Project dashboard |
/health | Service health |
Set ABX_RESOLVER_ADMIN_TOKEN on the host to enable registration and reindexing. That token controls
the index only. It cannot sign transactions.
Check progress with abx status. The five states are queued, backfilling, live, stale, and
failed.
abx status
abx status 0xYourContractThe reference resolver assumes one trusted operator. Add tenant isolation, quotas, and rate limits before sharing a node with unrelated customers.
SQLite maintenance
The projection lives in one SQLite file (.abx-self-host/index.db). A long-running node — one you
leave abx serveing for weeks, re-registering and dropping projections along the way — accumulates
pages that a delete frees internally but never returns to the filesystem on its own. abx vacuum
inspects and reclaims that space:
abx vacuum # status: auto_vacuum mode, page count, freelist size
abx vacuum convert # one-time, EXPLICIT full VACUUM for an older store
abx vacuum incremental [--pages n] # one bounded reclaim pass, on demandabx serve already runs a bounded reclaim pass automatically, between chain-watch ticks — never
inline with a request, and never more than a small number of pages per pass, so it can't add latency
to metadata being served concurrently. abx vacuum incremental runs that same bounded pass by hand,
for a node not running abx serve's watcher, or right after convert.
abx vacuum convert is the one part of this that is never automatic. A store created before this
maintenance shipped reports auto_vacuum: none — space still frees on delete, but only a full
VACUUM (which rewrites the ENTIRE file, and can briefly need up to ~2x its on-disk size) converts it
to the mode that lets incremental reclaim it in small passes going forward. Run it once, deliberately,
when abx vacuum tells you your store needs it — not on a schedule.
Effects worker
Code projects can produce still images and traits offchain. The effects worker uses Playwright and Chromium to render them.
abx effects
abx effects --once
abx render 0xYourContract
abx deploy-effects --resolver-url https://metadata.example.comSet ABX_EFFECTS_URL on the resolver for immediate notifications. A periodic sweep remains the
fallback.
For separate hosted services, use storage both processes can reach, such as S3/R2, IPFS, or Arweave. Local filesystem storage works only when the processes share that disk. See Storage.
Move hosts
abx migrate 0xYourContract --from <old-resolver> --to <new-resolver>The migration copies offchain values, verifies content hashes, and compares the two results. It does not change DNS or send an onchain transaction.