Metadata & Storage
NFT metadata combines on-chain fields (name, uri) with off-chain JSON and media files. Storage choices (Arweave, IPFS, centralized HTTPS) affect permanence, cost, and trust.
Recipe
{
"name": "My NFT",
"symbol": "MNFT",
"description": "Example asset",
"image": "ar://HASH",
"attributes": [{ "trait_type": "Rarity", "value": "Gold" }],
"properties": { "files": [{ "uri": "ar://HASH", "type": "image/png" }] }
}# Sugar upload -> Arweave bundlr typical path
sugar uploadWhen to reach for this:
- Preparing collection assets before on-chain mint
- Choosing permanent vs mutable hosting
- Validating metadata schema for marketplaces
- Linking animation_url and external_url fields
Working Example
# Directory per item: assets/0.json, assets/0.png, ...
sugar validate
sugar upload # uploads images + metadata to Arweave via Bundlr
sugar deploy// After upload, JSON uri in on-chain metadata points to Arweave gateway or ar://
const metadata = {
name: "Item #0",
symbol: "DEMO",
description: "Stored on Arweave",
image: "https://arweave.net/TX_ID",
attributes: [
{ trait_type: "Background", value: "Blue" },
{ trait_type: "Eyes", value: "Laser" },
],
};
// On-chain uri field -> same JSON location// Client fetch with cache bust on reveal
const res = await fetch(uri.replace("ar://", "https://arweave.net/"));
const json = await res.json();What this demonstrates:
- Standard JSON schema compatible with major marketplaces
imagefield required for gallery displayattributesarray powers trait filters and rarity tools
Deep Dive
How It Works
- On-chain account stores short
uristring pointing to JSON - JSON references media via
image,animation_url,properties.files - Arweave: one-time pay, content-addressed permanence
- IPFS: CID-based; pinning service required for availability
Storage Comparison
| Storage | Permanence | Cost model |
|---|---|---|
| Arweave | High | Upfront per MB |
| IPFS + pin | Depends on pin | Ongoing pin fees |
| HTTPS | Low (mutable) | Server hosting |
TypeScript Notes
// Validate JSON schema in CI before upload
// Hash files and compare to on-chain commitment if using verifiable NFT patternGotchas
- HTTP uri only - metadata swap if server compromised. Fix: Arweave/IPFS for production collections.
- Oversized images - slow loads and marketplace reject. Fix: compress; follow marketplace size limits.
- Mismatch token id vs filename - wrong image shown. Fix:
sugar validateand hash checks. - Reveal leak - final JSON uploaded too early. Fix: hidden settings + delayed reveal upload.
- Broken
ar://resolver - some clients lack gateway. Fix: provide https://arweave.net fallback in UI.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
| Arweave via Bundlr | Production NFT art | Quick throwaway test only |
| IPFS NFT.Storage | IPFS ecosystem preference | Need Arweave permanence guarantee |
| On-chain SVG (small) | Tiny generative art | Large media files |
FAQs
What goes on-chain vs off-chain?
Name/uri on-chain; image and attributes typically off-chain JSON.
Arweave vs IPFS?
Arweave: pay-once permanence. IPFS: CID with pinning responsibility.
What is Bundlr?
Upload layer funding Arweave transactions - used by Sugar.
Required JSON fields?
name, image minimum for most marketplaces; attributes for traits.
animation_url?
Optional field for video/html interactive media.
Can metadata change?
Yes if on-chain update authority can change uri to new JSON.
Immutable metadata?
Revoke update authority after final uri set; use permanent storage.
Generative collections?
Pre-render all images or on-chain SVG; JSON per index with matching traits.
Validate before mint?
sugar validate checks json/image pairs and schema issues.
DAS image field?
DAS resolves content.links.image from indexed metadata.
Centralized storage risk?
Server can swap image - undermines NFT permanence narrative.
File size limits?
Marketplace-specific - commonly a few MB for images.
Related
- Candy Machine - Sugar upload flow
- Metaplex Core - on-chain uri field
- Reading NFTs (DAS API) - resolved metadata
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.