Setting Up NFT Metadata Storage on Arweave
IPFS is not permanent storage. A file on IPFS exists as long as at least one node keeps it pinned. Paid pinning via Pinata or NFT.Storage costs money — and if the project stops paying, metadata and images disappear. "Your" NFT becomes a token pointing to 404.
Arweave solves this differently: one-time payment for permanent storage. Protocol's economics calculated for 200+ years of data storage via storage endowment mechanism. Pay once — file exists forever.
How Upload to Arweave Works
Upload via Bundlr Network (now Irys) — an L2 on top of Arweave. Main advantages: instant upload confirmation (99.9% confidence immediately, finalization on Arweave in minutes-hours), payment support in ETH/MATIC/SOL besides AR token, batch upload of thousands of files via SDK.
import Irys from "@irys/sdk";
const irys = new Irys({
url: "https://node1.irys.xyz",
token: "ethereum",
key: process.env.PRIVATE_KEY
});
// Upload one image
const response = await irys.uploadFile("./images/1.png", {
tags: [{ name: "Content-Type", value: "image/png" }]
});
const permanentUrl = `https://arweave.net/${response.id}`;
For 10k token collection: upload all images first, get array of Arweave transaction IDs, then form metadata JSON with "image": "https://arweave.net/TxId", upload metadata, get base URI.
Storage cost for one image (~50KB PNG) at time of writing — $0.001-0.005. Entire 10k collection costs $10-50 depending on file size. This is one-time payment.
URI Structure for Smart Contract
After uploading, two approaches to base URI possible:
Option 1 — Irys manifest (recommended for collections): upload all files as folder via irys.uploadFolder(), get single manifest ID. Then baseURI = "https://arweave.net/ManifestId/" and tokenURI(1) returns "https://arweave.net/ManifestId/1". Convenient, but manifest slightly slower to finalize.
Option 2 — individual txIds: each metadata JSON has its own txId, recorded in mapping mapping(uint256 => string) private _tokenURIs. More flexible (can update separate token before reveal), but more expensive per gas.
For standard generative collection with reveal — Option 1 + reveal via setBaseURI(manifestId).
Timeline and Process Reference
Setting up storage for ready collection (images + metadata JSON already generated) — 1 day:
- Irys SDK setup, balance top-up in ETH
- Batch image upload with integrity check
- Generate metadata JSON with arweave.net URLs
- Upload metadata, get manifest ID
- Update
baseURIin contract (if already deployed)
If metadata needs generation from scratch (traits not defined) — that's separate task.
Cost fixed by work volume + AR storage cost (paid by client directly or included in estimate).







