HANDS ON
Upload NFT assets

Uploading NFTs to Irys

When you use Irys to store NFT data on Arweave, you’re guaranteed your NFT will be both permanent and immutable. Here’s how you do it.

NFT assets

There are generally three parts to an NFT:

  1. Smart contract
  2. NFT metadata
  3. NFT assets

The smart contract can be on any chain, the metadata and assets are stored on an external storage provider. The smart contract stores a pointer to the NFT metadata, and then the NFT metadata contains links to the NFT assets.

In the example above for the Developer Quests NFT (opens in a new tab), there is a name and description that are shown on platforms like Opensea when the NFT is viewed. The image parameter points to a static image of the NFT. The animation_url parameter is optional and points to a video, song, or HTML animation file.

Creating an NFT

Three steps to creating an NFT:

  1. Upload your assets to Irys
  2. Embed the URLs to the assets in NFT metadata
  3. Upload metadata to Irys
  4. Use the metadata URL to mint your NFT
ℹ️

This guide does not cover the smart contract setup, if you’re unsure of how to do this, Thirdweb (opens in a new tab) has free, audited contracts available for use.

Uploading assets (SDK)

After installing the Irys SDK, use the following to upload your assets.

import Irys from "@irys/sdk";
import * as fs from "fs";
import dotenv from "dotenv";
dotenv.config();
 
// Returns a reference to an Irys node
const getIrys = async () => {
	const network = "devnet";
	// Devnet RPC URLs change often, use a recent one from https://chainlist.org/
	const providerUrl = "";
	const token = "ethereum";
	const privateKey = process.env.PRIVATE_KEY;
 
	const irys = new Irys({
		network, // "mainnet" || "devnet"
		token, // Token used for payment
		key: privateKey, // ETH or SOL private key
		config: { providerUrl }, // Optional provider URL, only required when using Devnet
	});
	return irys;
};
 
const uploadImage = async () => {
	const irys = await getIrys();
	const fileToUpload = "./myNFT.png";
 
	// Get size of file
	const { size } = await fs.promises.stat(fileToUpload);
	// Get cost to upload "size" bytes
	const price = await irys.getPrice(size);
	console.log(`Uploading ${size} bytes costs ${irys.utils.fromAtomic(price)} ${token}`);
	await irys.fund(price);
 
	// Upload metadata
	try {
		const response = await irys.uploadFile(fileToUpload);
		console.log(`File uploaded ==> https://gateway.irys.xyz/${response.id}`);
	} catch (e) {
		console.log("Error uploading file ", e);
	}
};

Uploading assets (CLI)

Alternatively, you can upload using our CLI.

irys upload myNFT.png \
  -n devnet \
  -t ethereum \
  -w bf20......c9885307 \
  --tags Content-Type image/png \
  --provider-url https://rpc.sepolia.dev

Creating metadata

Embed the URLs generated from the above script into your NFT metadata. The following example is from the Developer Quests NFT.

{
	"name": "Irys Developer Quests Quests",
	"description": "Irys Developer Quests #42",
	"image": "https://gateway.irys.xyz/737m0bA1kW4BlIJOg_kOGUpHAAI-3Ec9bdo8S_xTFKI",
	"animation_url": "https://gateway.irys.xyz/peRdpP3pjyFQ6m4Hca5fZY5zgz7RSlE86j-_5BEwnW0",
	"background_color": "FEF4EE"
}

Uploading metadata (SDK)

Finally, upload your NFT metadata to Irys and use the URL generated to mint the NFT.

import Irys from "@irys/sdk";
import * as fs from "fs";
import dotenv from "dotenv";
dotenv.config();
 
// Returns a reference to an Irys node
const getIrys = async () => {
	const network = "devnet";
	// Devnet RPC URLs change often, use a recent one from https://chainlist.org/
	const providerUrl = "";
	const token = "ethereum";
	const privateKey = process.env.PRIVATE_KEY;
 
	const irys = new Irys({
		network, // "mainnet" || "devnet"
		token, // Token used for payment
		key: privateKey, // ETH or SOL private key
		config: { providerUrl }, // Optional provider URL, only required when using Devnet
	});
	return irys;
};
 
const uploadMetadata = async () => {
	const irys = await getIrys();
 
	const fileToUpload = "./metadata.json";
	const tags = [{ name: "Content-Type", value: "application/json" }];
 
	// Get size of file
	const { size } = await fs.promises.stat(fileToUpload);
	// Get cost to upload "size" bytes
	const price = await irys.getPrice(size);
	console.log(`Uploading ${size} bytes costs ${irys.utils.fromAtomic(price)} ${token}`);
	await irys.fund(price);
 
	// Upload metadata
	try {
		const response = await irys.uploadFile(fileToUpload, { tags: tags });
		console.log(`File uploaded ==> https://gateway.irys.xyz/${response.id}`);
	} catch (e) {
		console.log("Error uploading file ", e);
	}
};

Uploading metadata (CLI)

Alternatively, you can upload using our CLI.

irys upload metadata.json \
  -n devnet \
  -t ethereum \
  -w bf20......c9885307 \
  --tags Content-Type application/json \
  --provider-url https://rpc.sepolia.dev