Buy an NFT, open your wallet, and a picture appears. It feels like the picture is the NFT. It almost never is. What the blockchain actually holds is a token and a short string of text — a pointer. The picture lives at the other end of that pointer, on a server or a network that may or may not still be there in ten years. Whether your NFT renders a decade from now depends less on the blockchain and more on what that pointer points to.
This is Part 2 of the NFTs 101 series. In Part 1 we established that the token is just a ledger entry on-chain — a row saying "address X owns token #42 in contract Y." Here we follow the trail from that row to the image you actually see, and look at why different storage choices age very differently.
The tokenURI: a string, not a picture
The ERC-721 standard defines a function called tokenURI(uint256 _tokenId) that returns a string. The spec says this string "may point to a JSON file that conforms to the ERC721 Metadata JSON Schema." That's it. The contract itself stores no pixels, usually no filenames — just one URL-like pointer per token. ERC-1155, the multi-token standard, extends the idea with an {id} placeholder: clients substitute a 64-character lowercase hex token ID into a shared URI template to fetch per-token metadata.
The URI scheme is deliberately unconstrained. It can be https://, ipfs://, ar://, or even a data: URI with the metadata embedded inline. When a wallet or marketplace "shows you the NFT," it is really resolving that URI, fetching a JSON file, and then fetching the image the JSON names. Three hops, three chances to break.
Inside the metadata JSON
The JSON schema itself is minimal. ERC-721 metadata has three fields: name (a string), description (a string), and image (a URI). ERC-1155 adds decimals and a flexible properties object for traits. OpenSea and others then extended this de facto with attributes arrays, animation_url, external_url, and background_color — none of which are in the original EIPs, but most wallets now expect them.
The JSON file sits wherever tokenURI pointed, typically the same host as the image. That coupling matters: if the JSON vanishes, even a perfectly preserved image is orphaned, because nothing ties it back to a name, description, or trait list. Some contracts sidestep this by returning the JSON inline as a data:application/json;base64,... URI — the metadata is then on-chain, even if the image it references is not. And note: nothing on-chain checks that the file at a given URL stays the same. Issuers can quietly swap it, or lose control of it.
IPFS: content-addressed, but only if someone keeps it pinned
IPFS (the InterPlanetary File System) replaces location-based URLs with Content Identifiers, or CIDs. A CID is a cryptographic label derived from the content itself: identical files produce the same CID on every node in the world. CIDv0 hashes start with Qm and run 46 base58 characters; CIDv1 adds multibase, version, and codec prefixes and looks different, but serves the same role.
Because the address is the hash of the content, an ipfs:// link is tamper-evident. Flip one byte and the CID changes. That is the immutability guarantee NFT collections usually point to when they say "stored on IPFS."
The catch is storage, not addressing. IPFS nodes have finite disk space and garbage-collect data they haven't been told to keep. "Pinning" is the instruction to keep a CID indefinitely. If every pinning node goes offline, the CID still exists mathematically — but there are no bytes left to serve. Most users don't run their own node; they fetch through HTTPS gateways like ipfs.io, cf-ipfs.com, dweb.link, or a marketplace's own gateway. Gateways can go down, rate-limit, or disappear. Services like Pinata, Filebase, and Web3.Storage offer paid pinning to harden this, but the IPFS documentation itself warns there is "no guarantee that these third party companies will continue to maintain their pinning service." Relying on one pinning provider to stay in business is a lot like trusting a host is a lot like trusting an exchange — convenient, not sovereign.
Arweave and the permaweb: pay once, store forever
Arweave takes a different approach. It sells itself as the "permaweb" — a layer where data, once uploaded, is intended to be retrievable permanently. You pay a single upfront fee, and most of it goes into a long-term endowment rather than to miners directly; the network then pays miners out of that endowment over time.
The economics rest on a simple bet: that storage cost per byte keeps falling faster than the endowment is drawn down, so a one-time payment today can fund replicated storage far into the future. Arweave links look like https://arweave.net/<tx-id> or ar://<tx-id>; the transaction ID is a cryptographic hash, so like IPFS, the address is content-bound. Pay-once is more expensive upfront than a free IPFS pin, but there's no one you have to keep paying the bill to.
The two extremes: centralized hosting and fully on-chain
At one end of the spectrum, a tokenURI like https://api.somecollection.io/nft/42 is cheap, fast, and flexible. It also depends on a single domain, a single cloud bill, and a single company continuing to exist. Many early NFT projects — and plenty of current free mints and game items — still use https:// URIs. When their host shuts down, wallets render "image not available" for tokens that may still trade.
Even "IPFS" NFTs are often centralized in practice. If the tokenURI is https://<company>-gateway.io/ipfs/<CID> rather than ipfs://<CID>, only that company's gateway is contractually promising to serve it. The CID is fine; the link is brittle.
At the other extreme sit fully on-chain NFTs. Autoglyphs, released by Larva Labs in 2019, is widely credited as the first art project generated and stored entirely on-chain — the generation algorithm lives inside the ERC-721 contract itself and renders each glyph on demand. Later projects like Chain Runners, Blitmap, Nouns, and OnChainMonkey return base64-encoded SVG or JSON directly from tokenURI; the whole image lives in Ethereum state. This is the most durable option available, since it survives as long as what a blockchain actually is keeps surviving. It is also the most expensive to mint — every byte on-chain costs gas — and artistically constrained: small SVGs and generative code fit; a 4K PNG does not.
How to check where your NFT actually lives
You can do this yourself in a few minutes. Open the NFT's contract on Etherscan (or the relevant chain's explorer), find the tokenURI read function, pass it your token ID, and look at what comes back. The prefix tells you most of the story:
ipfs://<CID>— content-addressed. Good. Then ask: is anyone besides the original team pinning it?ar://<tx>orarweave.net/<tx>— the permaweb. Probably the most durable off-chain option.https://<project-domain>/...— depends on that company keeping the lights on. Fine short-term, fragile long-term.https://<gateway>/ipfs/<CID>— the bytes are content-addressed, but the link isn't. Copy the CID out and treat it as anipfs://link in your own head.data:application/json;base64,...— the metadata is on-chain. Often the image (as an inline SVG data URI) is too. Strongest durability guarantee.
A three-question checklist covers most cases: Is the pointer content-addressed? Is more than one party storing the bytes? Could you personally re-pin or re-host it if the issuer vanished tomorrow? A "yes" to all three means the NFT's picture is likely to outlive the project that minted it.
Key takeaways
- An ERC-721 contract stores a
tokenURIstring, not a picture — wallets follow that pointer to a JSON file, and the JSON points to an image. - IPFS addresses are content hashes, so they're tamper-evident, but the bytes only stay reachable as long as someone keeps pinning them.
- Arweave's one-time upload fee funds a long-term endowment that pays miners over time, trading higher upfront cost for no recurring bill.
https://links on a project's own domain are the most fragile option; fully on-chain SVGs are the most durable but expensive and format-limited.- You can audit any NFT's storage in minutes by calling
tokenURIon a block explorer and reading the prefix.



