Store and mint NFTs using custom metadata

If your metadata conforms to the popular ERC-721 or ERC-1155 standards, you can upload all your NFT assets and prepare your metadata all in one HTTP request.

If you want to customize your metadata in a way that's not compatible with ERC-1155, or if you know you'll be using the same off-chain assets in many NFTs, you can store your files separately and get their IPFS URIs. You can then use these IPFS URIs and put them into a JSON file however you'd like to create your metadata. This metadata can then be stored, resulting in an IPFS URI that you can store in your token's on-chain record.


Check your metadata URI

It's important to make sure you are using a properly formatted IPFS URL (i.e., ipfs://bafy...) for the metadata URL you use when minting your NFT, as well as the URLs referenced within the metadata. This way, any IPFS-compatible browser can retrieve the right data directly using these URLs, and your NFT follows this universal standard. Click here to read more about IPFS URLs.

Here's an example on how to do this to mint your own NFT!

Uploading your images, assets, and metadata

Before you can create the blockchain record for your NFT, you'll need to store all of the off-chain resources that comprise the NFT "package". Once everything has been stored, you can use the IPFS URI for the metadata to link from the on-chain token to everything else.

Storing asset files

The JavaScript client library provides three methods that you can use to store arbitrary files for your NFT assets and metadata.

The storeBlob method accepts a single Blob or File object and returns the CID of the uploaded file. Note that the original filename and content type information will not be preserved, and the CID returned by storeBlob will point directly to the file data.

To preserve filenames, or to upload multiple related files at once, use the storeDirectory method. storeDirectory takes multiple File objects and wraps them with an IPFS directory listing. This allows you to link to the files using human-readable names as the "path" component of your IPFS URIs or gateway links.

It's important to note that storeDirectory returns the CID of the directory listing, and you'll need to append the filename to the CID to construct links to the files themselves.

For example, storing an image named pinpie.jpg using storeDirectory might return the CID bafybeiajdopsmspomlrpaohtzo5sdnpknbolqjpde6huzrsejqmvijrcea. If you view this CID on an HTTP gateway, you should see a directory listing page with a link to the file pinpie.jpg.

To link to the image, you'll need to add /pinpie.jpg to the CID to create a valid IPFS URI:


The final method for storing arbitrary data is storeCar, which stores data that has been packaged into the IPFS Content Archive format. This method gives you precise control over how the IPFS object graph is structured and may be a good fit if you already have data in IPFS. See the CAR file guide to learn how to work with CARs and prepare them for upload.

Preparing your metadata

Once you have all of your assets stored, you can update your metadata to include IPFS URIs to the images and other files that are part of your NFT.

For each file that you uploaded, prepare an IPFS URI of the form ipfs://<CID>/<filename>.

In some cases you may also want to include HTTP gateway URLs, but it's best to add those as an optimization or fallback for compatibility with browsers or wallets that don't support IPFS natively. See the IPFS documentation about web addresses for more details on IPFS URIs and the tradeoffs involved in using HTTP gateways.

Once the metadata is ready, you can serialize it to a file (usually in JSON format), and upload it by sending a POST request to /upload with the metadata as the request body. Set the Content-Type header to the type appropriate for your metadata, e.g. application/json.

You can use the CID from your metadata upload to link from your on-chain record to the metadata on IPFS.

Need to use CIDv0?
There are two versions of IPFS Content Identifiers (CIDs) in use today. The legacy "CIDv0" format is more compact, but it lacks several important features of CIDv1 and is generally discouraged for new projects.

If you need to work with a system that only supports CIDv0 (for example, because of a hard size constraint in a smart contract), you can prepare a CAR file containing IPFS objects that are compatible with CIDv0. The NFT.Storage APIs will still return a CIDv1 result, but this can be converted to CIDv0 using the CID tooling for your programming language.

See this pull request for an example.

Minting your NFT

Now that your metadata is stored with NFT.Storage, you can mint tokens using the blockchain platform of your choice.

We won't attempt to illustrate the minting process here, because the details depend on which chain and development language you're using, as well as the contract and standards you're targeting.

Instead, we'll offer some advice that applies to any blockchain when linking to assets stored using NFT.Storage.

To see an example of NFT.Storage being used with custom metadata, take a look at the Flow tutorial on NFT School.

Avoid storing HTTP URLs on-chain

Although in many cases the most convenient way to retrieve NFT data from IPFS may involve using an IPFS HTTP gateway, you should avoid storing HTTP gateway links in a smart contract or other blockchain record.

Instead, store the ipfs:// URI, which doesn't depend on a single gateway provider. You can rewrite this URL into a gateway link at the "last mile" when displaying the NFT on the web. This ensures that the blockchain link is always valid as long as any IPFS peer is providing the data, and doesn't tie your NFT to any specific gateway host.

If you do include HTTP links, use them in addition to IPFS URIs, as an optimization or fallback. Wherever possible, the IPFS URI should be the canonical link, or "source of truth".

Prefer IPFS URIs to raw CIDs or hashes

There are several different ways to refer to data on IPFS, all of which involve a Content Identifier or CID.

If you're writing your own contract, you may be tempted to store IPFS CIDs in their binary form, which uses a bit less storage space than a string-encoded CID like bafkreigfvngoydofemwj5x5ioqsaqarvlprzgxinkcv3am3jpv2sysqobi`

While it's true that a binary CID uses a bit less memory than the equivalent string encoding, in many cases it doesn't actually matter in practice. On platforms like the Ethereum Virtual Machine where the minimum storage allocation is 256 bits, both forms of CID require the same amount of actual on-chain storage space. In some cases it can be more expensive to store binary CIDs, for example, if you need to convert to the string form inside a contract.

We recommend using URIs of the form ipfs://<cid>/<path> when linking from on-chain records to IPFS data. This gives you flexible addresses that can include human-friendly filenames in the path, and using strings instead of binary links makes debugging a lot simpler.