Skip to main content

HCS‑5: Hashinals (Tokenized HCS‑1)

HCS‑5 is the simplest way to create a “fully on‑graph” NFT on Hedera. You inscribe content to HCS‑1 (a topic), then mint an HTS NFT whose metadata is an HRL that points to that topic.

In plain English: “Put my image/text on HCS‑1, then mint an NFT that permanently points to it.”

TL;DR QuickstartDirect link to TL;DR Quickstart​

import { HCS5Client } from '@hashgraphonline/standards-sdk';

const client = new HCS5Client({
network: 'testnet',
operatorId: process.env.HEDERA_ACCOUNT_ID!,
operatorKey: process.env.HEDERA_PRIVATE_KEY!,
});

// One‑shot: inscribe an SVG and mint
const svg = Buffer.from(
'<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" width="512" height="512"><rect width="512" height="512" fill="#0d9488"/><text x="50%" y="56%" text-anchor="middle" dominant-baseline="middle" font-size="320" font-weight="700" fill="#fff">S</text></svg>'
);

const minted = await client.createHashinal({
tokenId: '0.0.123456',
inscriptionInput: { type: 'buffer', buffer: svg, fileName: 'hashinal.svg', mimeType: 'image/svg+xml' },
inscriptionOptions: {
waitForConfirmation: true,
metadata: {
name: 'Demo Hashinal',
description: 'Minted with standards‑sdk',
type: 'image/svg+xml',
attributes: [{ trait_type: 'Letter', value: 'S' }],
},
},
// supplyKey: '...' // optional if the token requires an extra signature
});

console.log(minted.metadata); // hcs://1/<topicId>

Visual OverviewDirect link to Visual Overview​

Hashinal lifecycle

What this gives you

  • The NFT’s metadata points to an immutable HCS‑1 inscription
  • No dependency on off‑chain storage
  • HIP‑412 compatible metadata (name, description, type, attributes)

How it WorksDirect link to How it Works​

  1. Inscribe your content to HCS‑1 with the Inscriber helpers
  2. Take the returned topicId
  3. Mint an HTS NFT whose metadata is hcs://1/<topicId>

The SDK does steps 1–3 for you in one call (createHashinal).

Node UsageDirect link to Node Usage​

Mint from an existing HCS‑1 topic:

await client.mint({
tokenId: '0.0.123456',
metadataTopicId: '0.0.654321',
// supplyKey: '...' // optional
});

Or inscribe and mint in one step (recommended):

await client.createHashinal({
tokenId: '0.0.123456',
inscriptionInput: { type: 'buffer', buffer: svg, fileName: 'hashinal.svg', mimeType: 'image/svg+xml' },
inscriptionOptions: {
waitForConfirmation: true,
metadata: {
name: 'Demo Hashinal',
description: 'Minted with standards‑sdk',
type: 'image/svg+xml',
attributes: [{ trait_type: 'Letter', value: 'S' }],
},
},
});

Key Handling (No Guesswork)Direct link to Key Handling (No Guesswork)​

  • Operator key type (ECDSA vs ED25519) is resolved via Mirror Node (account key._type)
  • If you pass a supplyKey string, the client fetches token info (token supply_key._type) and parses the key accordingly

Browser UsageDirect link to Browser Usage​

import { HCS5BrowserClient } from '@hashgraphonline/standards-sdk';
import { HashinalsWalletConnectSDK } from '@hashgraphonline/hashinal-wc';

const hwc = HashinalsWalletConnectSDK.getInstance();
const client = new HCS5BrowserClient({ network: 'testnet', hwc });

const res = await client.createHashinal({
tokenId: '0.0.123456',
inscriptionInput: { type: 'buffer', buffer: svg, fileName: 'hashinal.svg', mimeType: 'image/svg+xml' },
inscriptionOptions: {
waitForConfirmation: true,
metadata: {
name: 'Browser Hashinal',
description: 'Minted in the browser',
type: 'image/svg+xml',
attributes: [{ trait_type: 'Source', value: 'Browser' }],
},
},
});

Tip The SDK forces hashinal mode internally. You do not need to set a mode. In the browser the wallet must be able to sign TokenMint (and supplyKey if required by the token).

Demo (Node)Direct link to Demo (Node)​

From the standards-sdk package root:

pnpm run demo:hcs-5

Environment variables in standards-sdk/.env:

  • HEDERA_NETWORK (testnet | mainnet)
  • HEDERA_ACCOUNT_ID, HEDERA_PRIVATE_KEY
  • HCS5_TOKEN_ID (optional; if omitted, the demo creates a token)
  • Optional image overrides: HCS5_IMAGE_PATH or HCS5_IMAGE_URL
  • Optional SVG customization: HCS5_LETTER, HCS5_BG, HCS5_FG

The demo inscribes an SVG (HIP‑412 attributes included), mints an NFT, and prints the HRL (hcs://1/<topicId>).

TroubleshootingDirect link to Troubleshooting​

  • “Failed to inscribe content” → Increase waitMaxAttempts/waitIntervalMs in inscriptionOptions
  • “No topic ID from inscription” → Ensure Inscriber returns topic_id or jsonTopicId
  • “Supply key required” → Provide supplyKey with the correct key matching token supply_key._type

Who Is This For?Direct link to Who Is This For?​

  • Creators who want fully on‑chain NFTs with no off‑chain storage
  • Platforms that need deterministic, permanent references to content
  • Indexers who prefer HRL pointers over mutable URLs

When To Use (and Not Use)Direct link to When To Use (and Not Use)​

  • Use when permanence and verifiability of metadata matters
  • Don’t use if your content must remain private (HCS‑1 inscriptions are public)

Costs and LimitsDirect link to Costs and Limits​

  • Costs: inscription (HCS) + mint (HTS) fees; image size impacts inscription fees
  • Limits: prefer small/efficient media; large files → higher fees and slower confirmation

FAQDirect link to FAQ​

  • Can I update the content? Not for HCS‑5; inscribed content is immutable. For updatable content, see HCS‑6.
  • Do wallets resolve HRLs? Many indexers and tools do; you can fetch by topic id using an HRL resolver.

ReferenceDirect link to Reference​