Skip to content

IPNS — Mutable Names for IPFS

IPNS (InterPlanetary Name System) gives you stable, shareable addresses that can be updated to point to different content over time. While IPFS CIDs change every time content changes, an IPNS name stays the same — you just update where it points.

Available on Bodhi (3 names, 100 publishes/mo) and Nirvana (10 names, 1,000 publishes/mo) plans.

Learn more about IPNS

For a deep dive into how IPNS works at the protocol level, see the official IPFS documentation on IPNS.

IPNS Names management page

Why use IPNS?

The problem: Every time you upload a new version of a file to IPFS, you get a different CID. If you shared the old CID with users, they still see the old content. You'd have to share a new link every time.

The solution: Create an IPNS name once, share it, and update what it points to whenever your content changes. Anyone with the IPNS address always gets the latest version.

Common use cases

  • Websites on IPFS — Deploy your site, get a CID, publish it to your IPNS name. Redeploy → new CID → update the IPNS name. The URL never changes.
  • NFT metadata that evolves — Point your NFT's tokenURI to an IPNS address. Update the metadata (e.g., game item levels up) without changing the smart contract.
  • Configuration files — Your app reads config from an IPNS address. Update the config without redeploying the app.
  • Data feeds — Publish daily datasets or price feeds under a stable IPNS address.
  • DNSLink — Connect your domain to IPNS so https://yourdomain.com always serves the latest IPFS content.

Using the Dashboard

1. Create an IPNS name

  1. Go to IPNS in the sidebar under Hosting.
  2. Click Create name.
  3. Enter a label (e.g., "my-website") and click Create.
  4. Copy the IPNS address (starts with k51...) — this is your permanent, shareable address.
IPNS page with created keys

2. Publish a CID to your IPNS name

  1. Find the IPNS name in the list and click Publish.
  2. Enter the CID you want it to point to (e.g., QmXk7VRz... or bafybei...).
  3. Click Publish. This propagates to the IPFS network and may take up to 60 seconds.
  4. Once published, the content is accessible at:
    • IPFS gateway: https://ipfs.ninja/ipns/{your-ipns-name}
    • Any public gateway: https://dweb.link/ipns/{your-ipns-name}
    • IPFS native: ipns://{your-ipns-name}
IPNS page with published CID

3. Update your content

When your content changes:

  1. Upload the new version to IPFS (via dashboard or API) → get a new CID.
  2. Go back to IPNS, click Publish on the same name, enter the new CID.
  3. The IPNS address stays the same — anyone using it automatically gets the new content.

4. Resolve an IPNS name

Use the Resolve section at the bottom of the page to look up the current CID for any IPNS name — yours or anyone else's.

5. Delete an IPNS name

Click the delete button next to any name. The IPNS record will expire from the network within 48 hours.

You can point your own domain name to an IPNS address using DNSLink. This lets users access your IPFS content through a regular URL like https://yourdomain.com.

  1. Create an IPNS name and publish your content CID to it (steps above).

  2. Add a DNS TXT record at your domain's DNS provider:

    _dnslink.yourdomain.com  TXT  "dnslink=/ipns/{your-ipns-name}"

    Example: If your IPNS name is k51qzi5uqu5djcpbukxs...:

    _dnslink.myapp.com  TXT  "dnslink=/ipns/k51qzi5uqu5djcpbukxs..."
  3. Verify the record using dig or nslookup:

    bash
    dig +short TXT _dnslink.myapp.com
    # Should return: "dnslink=/ipns/k51qzi5uqu5djcpbukxs..."
  4. Access via any IPFS gateway that supports DNSLink:

    https://ipfs.ninja/ipns/myapp.com

    Or via a browser with IPFS support (like Brave):

    ipns://myapp.com

DNS propagation

DNS changes can take up to 24 hours to propagate globally. After adding the TXT record, wait a few hours before testing.

TIP

You only need to set up DNSLink once. When you publish a new CID to your IPNS name, the domain automatically resolves to the new content — no DNS changes needed.

If you use Cloudflare:

  1. Go to DNSRecords.
  2. Add a new record: Type: TXT, Name: _dnslink, Content: dnslink=/ipns/k51...
  3. Set proxy status to DNS only (gray cloud).
  1. Go to your hosted zone in Route 53.
  2. Create a record: Name: _dnslink.yourdomain.com, Type: TXT, Value: "dnslink=/ipns/k51..."

Usage Examples

Example 1: Static website deployment

bash
# 1. Build your site
npm run build

# 2. Upload the build output to IPFS
CID=$(curl -s -X POST https://api.ipfs.ninja/upload/new \
  -H "X-Api-Key: bws_your_api_key" \
  -H "Content-Type: application/json" \
  -d "{\"content\": $(cat dist/index.html | base64 -w0 | jq -Rs .), \"description\": \"Website v2.1\"}" \
  | jq -r '.cid')

echo "Uploaded: $CID"

# 3. Update your IPNS name to point to the new build
curl -X POST https://api.ipfs.ninja/ipns/publish \
  -H "X-Api-Key: bws_your_api_key" \
  -H "Content-Type: application/json" \
  -d "{\"ipnsName\": \"k51qzi5uqu5dlvj2bv6...\", \"cid\": \"$CID\"}"

# Your site at ipns://k51... now serves the new version

Example 2: Mutable NFT metadata

javascript
// Smart contract points tokenURI to IPNS address:
// tokenURI = "ipns://k51qzi5uqu5dlvj2bv6..."

// When the NFT evolves (e.g., game item levels up):
const newMetadata = {
  name: "Dragon Sword",
  description: "A legendary weapon — Level 5",
  image: "ipfs://QmNewImageCID...",
  attributes: [
    { trait_type: "Level", value: 5 },
    { trait_type: "Damage", value: 150 }
  ]
};

// Upload new metadata
const uploadRes = await fetch("https://api.ipfs.ninja/upload/new", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": "bws_your_api_key"
  },
  body: JSON.stringify({ content: newMetadata, description: "Dragon Sword v5" })
});
const { cid } = await uploadRes.json();

// Update the IPNS pointer — tokenURI stays the same!
await fetch("https://api.ipfs.ninja/ipns/publish", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": "bws_your_api_key"
  },
  body: JSON.stringify({ ipnsName: "k51qzi5uqu5dlvj2bv6...", cid })
});

Example 3: CI/CD integration

yaml
# GitHub Actions: auto-publish to IPNS on every push
- name: Upload to IPFS and publish IPNS
  run: |
    CID=$(curl -s -X POST https://api.ipfs.ninja/upload/new \
      -H "X-Api-Key: ${{ secrets.IPFS_NINJA_API_KEY }}" \
      -H "Content-Type: application/json" \
      -d '{"content": '"$(cat build/output.json)"', "description": "Deploy ${{ github.sha }}"}' \
      | jq -r '.cid')

    curl -X POST https://api.ipfs.ninja/ipns/publish \
      -H "X-Api-Key: ${{ secrets.IPFS_NINJA_API_KEY }}" \
      -H "Content-Type: application/json" \
      -d '{"ipnsName": "${{ vars.IPNS_NAME }}", "cid": "'"$CID"'"}'

API Reference

All API examples use the X-Api-Key header. Get your API key from the API Keys page.

List IPNS Keys

bash
curl https://api.ipfs.ninja/ipns/keys \
  -H "X-Api-Key: bws_your_api_key_here"

Response:

json
[
  {
    "ipnsName": "k51qzi5uqu5dlvj2bv6...",
    "keyName": "my-website",
    "currentCid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
    "lastPublishedAt": 1711123200000,
    "publishCountMonth": 12,
    "status": "active",
    "createdAt": 1711036800000
  }
]

Create IPNS Key

bash
curl -X POST https://api.ipfs.ninja/ipns/keys \
  -H "X-Api-Key: bws_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"name": "my-website"}'

Response 201:

json
{
  "ipnsName": "k51qzi5uqu5dlvj2bv6...",
  "keyName": "my-website",
  "createdAt": 1711036800000
}

Publish to IPNS

Publishing updates the IPNS name to point to a new CID. This propagates to the IPFS DHT and may take up to 60 seconds.

bash
curl -X POST https://api.ipfs.ninja/ipns/publish \
  -H "X-Api-Key: bws_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"ipnsName": "k51qzi5uqu5dlvj2bv6...", "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"}'

Response:

json
{
  "ipnsName": "k51qzi5uqu5dlvj2bv6...",
  "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi",
  "published": true
}

Resolve IPNS Name

Look up the current CID for any IPNS name.

bash
curl https://api.ipfs.ninja/ipns/resolve/k51qzi5uqu5dlvj2bv6... \
  -H "X-Api-Key: bws_your_api_key_here"

Response:

json
{
  "ipnsName": "k51qzi5uqu5dlvj2bv6...",
  "cid": "bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi"
}

Delete IPNS Key

bash
curl -X DELETE https://api.ipfs.ninja/ipns/keys/k51qzi5uqu5dlvj2bv6... \
  -H "X-Api-Key: bws_your_api_key_here"

Response:

json
{ "success": true }

How IPNS Works

  1. Key generation: When you create an IPNS name, a cryptographic keypair (Ed25519) is generated. The public key hash becomes your IPNS address (k51...).
  2. Publishing: When you publish, you sign a record saying "this name points to CID X" and broadcast it to the IPFS DHT (Distributed Hash Table).
  3. Resolution: When someone looks up your IPNS name, IPFS nodes query the DHT for the latest signed record and follow it to the CID.
  4. Republishing: IPNS records expire after 48 hours. IPFS Ninja automatically republishes your records every 12 hours to keep them alive.
  5. Security: Only the private key holder (you) can update what an IPNS name points to. No one else can hijack your name.

Plan Limits

PlanIPNS NamesPublishes / Month
Dharma (Free)Not available
Bodhi ($5/mo)3100
Nirvana ($29/mo)101,000
  • Records are automatically republished every 12 hours to keep them alive on the IPFS network.
  • Names not published to for 90 days are marked as inactive and stop being republished.
  • Inactive names can be reactivated by publishing a new CID to them.

Further Reading