abx.
Using ABXGuides

Storage

Storage is where a project's source bytes live. The chain commits to those bytes by hash, and a backend holds them. Storage is stateless in the CLI: there is no config file, so you select a backend per command with a flag, or set it in the environment.

Backends

BackendWhat it isNotes
fslocal disk (the default)no public URL; for local development
cloudS3, R2, or a CDNneeds a public read base (--public-base or ABX_S3_PUBLIC_BASE)
ipfsIPFSPinata, or a local Kubo node
arweaveArweavepermanent; uses Turbo by default

Select a backend with --backend, or set ABX_STORAGE_BACKEND. The order is the flag, then the environment, then the fs default. Secrets are read from the environment only, for example ABX_S3_ACCESS_KEY_ID and ABX_S3_SECRET_ACCESS_KEY for cloud, or PINATA_JWT for IPFS.

Commands

  • abx storage show: the resolved backend, and where each setting came from.
  • abx storage upload <path>: upload one file and print its locator, which is the URI that abx attach takes.
  • abx storage balance: Arweave upload credits and the funded address.
  • abx storage topup --usd <n>: buy Arweave upload credits.
  • abx storage backup-key --out <path>: copy the managed storage key to a path you choose.

Arweave and Turbo

Arweave uploads go through Turbo by default. Uploads under 100 KB are free and need no setup. Larger uploads use prepaid credits. On the first upload, a managed Arweave key is created at .abx-self-host/arweave-key.json; it signs uploads and holds the credits, and it is reused across projects. Read paths such as serve and verify never create a key.

Credits attach to an identity. --storage-signer selects it: arweave, the default, uses the managed key; eth uses your EVM signing key as the Turbo identity, so credits sit on that address. With eth and --sign, a browser wallet signs each upload with no gas.

Check credits with abx storage balance before concluding that an upload needs funding, since both the managed key and the ETH wallet can hold credits. Back up the managed key with abx storage backup-key before topping up. A gateway or provider is swappable, because the on-chain hash is the anchor.

A fresh Arweave URL can 404 for a few minutes

arweave.net — the default gateway, and the one baked into the locator — indexes new uploads on a delay, so a just-published render can 404 there for several minutes after Turbo has already confirmed it. The bytes are fine; only that gateway is behind, and other ar.io gateways typically serve them sooner. This is propagation, not a failed render: do not re-run abx render --force, which re-uploads everything and fixes nothing. abx render prints this reminder after an Arweave publish.

The gateway is fixed at publish time, because the locator is what gets registered with the resolver — a redirect can't repair it afterwards. To bake a different one, set ABX_ARWEAVE_GATEWAY before you render (abx storage show prints the gateway in effect).

Is it retrievable yet?

"Accepted" and "retrievable" are different states, and an upload result only tells you the first. abx storage status <locator> tells you the second:

abx storage status ar://<txid>
abx storage status ipfs://<cid>/0.png --json    # exits non-zero until ready

It probes the gateway your project actually uses plus two others, because propagation is per-gateway — so it can distinguish three states rather than two:

VerdictMeansWhat to do
readyYour gateway serves the bytes.Safe to reference in a token.
propagatingAnother gateway serves them, so the data provably exists on the network; yours is behind.Wait. Do not re-upload — you would pay twice for bytes that are already stored.
unreachableNo probed gateway serves them.Either still settling or the locator is wrong. The check says so rather than guessing, because from outside those look identical.

The exit code is the verdict, so waiting is a one-liner rather than a retry ladder you write yourself:

until abx storage status ar://<txid> --json > /dev/null; do sleep 10; done

Anything programmatic should call locatorStatus() from @artblocks/abx-storage directly instead of spawning the CLI per check.

Never upload on the display path during a mint

The failure this exists to prevent: upload during a mint, write the locator into the token, and the token renders broken for the first minutes of its life. Publish first, confirm ready, then reference. Two separate integrations hit this before the check existed, and both independently built their own version of it.

On this page