Creating NFTs with Persistent Swarm Storage Using Available Libraries
You can create permanent NFTs by uploading assets to Swarm using Bee-JS or swarm-cli to generate immutable BZZ hashes, then referencing these hashes in your ERC-721 tokenURI field, with the SwarmNFT library providing a simplified abstraction for the entire workflow.
The ethersphere/awesome-swarm repository curates essential tools that streamline creating NFTs with decentralized, persistent storage. By leveraging Swarm's content-addressed architecture, you ensure that NFT media and metadata remain accessible indefinitely without relying on centralized servers. This guide demonstrates how to use the libraries indexed in awesome-swarm to implement a complete NFT creation pipeline.
Core Libraries from Awesome-Swarm
The awesome-swarm collection provides direct links to two primary tools for NFT development. According to the repository's [README.md](https://github.com/ethersphere/awesome-swarm/blob/master/README.md), these libraries form the foundation of the Swarm NFT ecosystem.
Bee-JS: The Official JavaScript Client
At line 24 of the README, awesome-swarm lists Bee-JS, the official high-level JavaScript client for interacting with Bee nodes. This library handles direct uploads to the Swarm network, returning immutable content hashes that serve as permanent identifiers for your NFT assets.
SwarmNFT: High-Level NFT Abstraction
As referenced at line 127 in the README, the SwarmNFT library abstracts the entire upload-and-mint workflow. It internally manages Bee-JS connections, metadata manifest creation, and URL generation, reducing the implementation to a single method call.
Uploading Assets to Swarm with Bee-JS
The first step in creating a persistent NFT involves storing your media files on Swarm. This process generates a BZZ hash—a content-addressed identifier that guarantees data immutability.
Install the required dependencies:
npm install @ethersphere/bee-js @openzeppelin/contracts ethers
Connect to your Bee node and upload the NFT image:
import { Bee } from '@ethersphere/bee-js';
import fs from 'fs';
const bee = new Bee('http://localhost:1633');
// Upload image file
const fileBuffer = fs.readFileSync('artwork.png');
const imageReference = await bee.uploadFile(fileBuffer, {
name: 'artwork.png',
contentType: 'image/png',
});
console.log('Image BZZ hash:', imageReference.reference);
// Returns: a unique, immutable Swarm hash
The uploadFile method returns a reference object containing the BZZ hash. This hash remains valid as long as the content exists on the Swarm network, ensuring your NFT artwork persists indefinitely.
Structuring ERC-721 Metadata
After uploading the media, you must create a JSON metadata file following the ERC-721 schema. This manifest points to the Swarm-stored image using either the bzz:// protocol or an HTTP gateway URL.
Create the metadata object referencing the uploaded hash:
const metadata = {
name: 'Swarm-Stored NFT',
description: 'An NFT whose image lives permanently on Swarm',
image: `bzz://${imageReference.reference}`,
attributes: [{ trait_type: 'Creator', value: 'Alice' }],
};
// Upload metadata JSON
const metaReference = await bee.uploadData(JSON.stringify(metadata), {
name: 'metadata.json',
contentType: 'application/json',
});
console.log('Metadata BZZ hash:', metaReference.reference);
Upload this JSON to Swarm to obtain a second immutable hash. This metadata hash becomes your tokenURI, permanently linking the on-chain token to its off-chain attributes and media.
Minting NFTs with Swarm References
With the metadata stored on Swarm, you can mint the NFT by writing the Swarm URL to the blockchain. The ERC-721 contract's tokenURI function will resolve to your persistent Swarm content.
Execute the minting transaction:
import { ethers } from 'ethers';
import erc721ABI from './ERC721ABI.json';
const wallet = new ethers.Wallet('YOUR_PRIVATE_KEY', ethers.getDefaultProvider('goerli'));
const nftContract = new ethers.Contract('0xYourNFTContract', erc721ABI, wallet);
// Construct gateway URL or use bzz:// scheme
const tokenURI = `https://gateway.ethswarm.org/bzz/${metaReference.reference}`;
const tx = await nftContract.mint(wallet.address, 1, tokenURI);
await tx.wait();
console.log('NFT minted with tokenURI:', tokenURI);
Because Swarm uses content-based addressing, the tokenURI resolves to exactly the data you uploaded, regardless of which gateway or Bee node serves the request. This architecture ensures your NFT remains accessible even if specific gateways fail.
Streamlined Workflow with SwarmNFT
For production environments, the SwarmNFT library consolidates the upload and mint steps into a single operation. As documented in the awesome-swarm repository at line 127, this helper eliminates boilerplate when creating multiple NFTs.
Install the helper library:
npm install swarm-nft
Implement the complete workflow:
import SwarmNFT from 'swarm-nft';
import { ethers } from 'ethers';
const swarmNFT = new SwarmNFT({ beeUrl: 'http://localhost:1633' });
async function createNFT() {
const { tokenURI } = await swarmNFT.uploadAndMint({
imagePath: 'artwork.png',
name: 'Swarm-Stored NFT',
description: 'An NFT with persistent Swarm storage',
attributes: [{ trait_type: 'Creator', value: 'Alice' }],
contractAddress: '0xYourNFTContract',
signer: new ethers.Wallet('YOUR_PRIVATE_KEY', ethers.getDefaultProvider('goerli')),
});
console.log('Minted NFT with persistent tokenURI:', tokenURI);
}
createNFT();
The uploadAndMint method internally handles file upload, metadata generation, Swarm upload, and returns the final URL ready for blockchain recording.
Summary
- Persistent storage: Swarm's content-addressed BZZ hashes ensure NFT data remains immutable and retrievable indefinitely.
- Modular architecture: Use Bee-JS for granular control over uploads or SwarmNFT for streamlined creation, as indexed in awesome-swarm at lines 24 and 127.
- Gateway flexibility: NFTs reference Swarm hashes directly (
bzz://<hash>) or via gateways, remaining accessible regardless of specific server availability. - Implementation pattern: Upload media → upload metadata JSON → mint token with metadata hash as
tokenURI.
Frequently Asked Questions
How does Swarm ensure my NFT persists permanently?
Swarm stores data using content-addressing, where the BZZ hash represents a cryptographic fingerprint of the file itself. As long as the content exists on any Swarm node, the hash resolves correctly. You can pin content to your own Bee node or rely on the network's redundancy mechanisms to maintain availability.
Can I use Swarm with existing ERC-721 contracts?
Yes. Any ERC-721 contract that accepts string URIs supports Swarm references. Simply format your tokenURI as bzz://<hash> or use a gateway URL like https://gateway.ethswarm.org/bzz/<hash>/. The contract stores this string on-chain while Swarm hosts the actual content off-chain.
What is the difference between Bee-JS and the SwarmNFT library?
Bee-JS provides low-level access to Bee node operations, requiring manual handling of file uploads, metadata creation, and URI formatting. SwarmNFT abstracts these steps into a unified interface, automatically generating metadata and managing both uploads in a single call. Choose Bee-JS for custom implementations and SwarmNFT for rapid deployment.
Do I need to run my own Bee node to create Swarm NFTs?
No. While running a local node (default port 1633) offers maximum control, you can connect to hosted Bee nodes or public gateways. The awesome-swarm repository lists multiple infrastructure options. However, pinning content on your own node ensures you control the persistence guarantees rather than relying on third-party providers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →