# Understanding Swarm Manifests and How to Manipulate Them with Mantaray-js

> Learn to create and manipulate Swarm manifests using Mantaray-js. Understand Merkle-DAG structures and map paths to content-addressed chunks in JavaScript.

- Repository: [Ethersphere/awesome-swarm](https://github.com/ethersphere/awesome-swarm)
- Tags: deep-dive
- Published: 2026-03-01

---

**Swarm manifests are Merkle-DAG structures that map human-readable paths to content-addressed chunks, and Mantaray-js is the low-level JavaScript library that enables direct creation, serialization, and manipulation of these manifests in Node.js or browser environments.**

Swarm organizes data as immutable chunks addressed by their hash, but serving websites or directories requires a mapping layer called a **manifest**. The `ethersphere/awesome-swarm` repository lists Mantaray-js as the primary tool for manipulating these structures, providing a pure JavaScript implementation of the manifest data format without network-layer dependencies.

## What Are Swarm Manifests?

Swarm manifests are **Merkle-DAGs** (Directed Acyclic Graphs) that bridge human-readable file paths with content-addressed storage. Each manifest node contains a list of **entries**, where every entry records four critical fields:

- **path**: A UTF-8 string representing the filename or directory component
- **hash**: The Swarm hash of the referenced chunk or sub-manifest  
- **metadata**: Optional JSON-serializable data such as MIME type or file size
- **mode**: Unix-like permission bits used by Swarm's POSIX compatibility layer

Because manifests themselves are content-addressed, any modification produces a new root hash while preserving unchanged sub-trees. This immutability enables version-control-style properties and content-addressable URLs in the format `bzz:/<root-hash>/path`.

## The Mantaray-js Architecture

[Mantaray-js](https://github.com/ethersphere/mantaray-js) implements the manifest data structure and serialization logic required to interact with Swarm manifests directly. According to the `ethersphere/awesome-swarm` source code, this library is referenced as the primary resource for low-level manifest manipulation.

### Core Components

The library centers on two primary classes:

**`MantarayNode`** (implemented in [`src/node.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/node.ts)) represents a single manifest node. It maintains a map of entries (`path → MantarayFork`) and provides methods for **adding**, **removing**, and **looking up** entries.

**`MantarayFork`** (defined in [`src/fork.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/fork.ts)) wraps the raw Swarm hash alongside entry metadata and mode permissions. This is the atomic unit written to and read from the Swarm network.

### Serialization and Traversal

The `serialize` and `deserialize` functions (located in [`src/serialization.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/serialization.ts)) convert between the in-memory `MantarayNode` representation and the binary format expected by Swarm's HTTP gateway. The **`walk`** utility (in [`src/walk.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/walk.ts)) provides depth-first traversal for generating file lists or applying transformations across all entries.

Mantaray-js deliberately avoids network concerns—higher-level tools like `bee-js` handle uploading the binary blobs produced by this library.

## Working with Manifests: A Practical Workflow

Manipulating manifests follows a consistent four-step pattern: create, populate, serialize, and upload. Because manifests are Merkle-DAGs, only changed branches require re-uploading during updates.

### Creating a New Manifest and Adding Files

Start with an empty `MantarayNode` and add file entries wrapped in `MantarayFork` instances:

```javascript
import { MantarayNode, MantarayFork } from 'mantaray-js';

// Helper – placeholder for actual Swarm hashing
async function hashChunk(data) {
  return '0x' + Buffer.from(data).toString('hex').slice(0, 64);
}

// Initialize empty manifest
const root = new MantarayNode();

// Prepare file content and compute hash
const fileContent = new TextEncoder().encode('<!DOCTYPE html><html>…</html>');
const fileHash = await hashChunk(fileContent);

// Create fork with metadata
const fork = new MantarayFork({
  hash: fileHash,
  metadata: { mime: 'text/html' },
  mode: 0o644,
});

// Add entry to manifest
await root.addEntry('index.html', fork);

// Serialize for upload
const manifestBinary = root.serialize();

```

The resulting `Uint8Array` can be POSTed to a Swarm node's `/bzz:/` endpoint to obtain the manifest root hash.

### Loading and Listing Entries

To inspect an existing manifest, deserialize the binary payload and traverse the tree:

```javascript
import { MantarayNode } from 'mantaray-js';

// manifestBinary retrieved from Swarm via GET /bzz:/<rootHash>
const root = MantarayNode.deserialize(manifestBinary);

const entries = [];
root.walk((path, fork) => {
  entries.push({ 
    path, 
    hash: fork.hash, 
    mime: fork.metadata?.mime 
  });
});

console.log('Manifest contents:', entries);

```

### Updating Files in Existing Manifests

Manifest immutability means "updating" creates a new version. Modify the node, then re-serialize:

```javascript
import { MantarayFork } from 'mantaray-js';

const newContent = new TextEncoder().encode('Updated content');
const newHash = await hashChunk(newContent);

const updatedFork = new MantarayFork({
  hash: newHash,
  metadata: { mime: 'text/plain' },
  mode: 0o644,
});

// Overwrites existing path if present
await root.addEntry('readme.txt', updatedFork);
const updatedManifest = root.serialize();

```

### Removing Entries

Delete paths using `removeEntry`, which returns `true` if the path existed:

```javascript
const removed = await root.removeEntry('old-file.jpg');
if (removed) {
  console.log('Entry removed – re-upload manifest to finalize.');
}

```

## Key Implementation Files

The Mantaray-js source structure reflects its architectural separation of concerns as catalogued in the `ethersphere/awesome-swarm` repository:

- **[`src/node.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/node.ts)** – Implements `MantarayNode` with entry management methods
- **[`src/fork.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/fork.ts)** – Defines `MantarayFork`, the hash-plus-metadata wrapper used in manifest entries
- **[`src/serialization.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/serialization.ts)** – Contains binary encoding/decoding logic for Swarm HTTP API compatibility
- **[`src/walk.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/walk.ts)** – Provides tree traversal utilities for manifest inspection and transformation

## Summary

- **Swarm manifests** are Merkle-DAGs that map paths to content-addressed chunks, storing `path`, `hash`, `metadata`, and `mode` in each entry.
- **Mantaray-js** provides the low-level JavaScript implementation for creating and manipulating these structures without network dependencies.
- Key classes include **`MantarayNode`** (entry container) and **`MantarayFork`** (hash wrapper with metadata), implemented in [`src/node.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/node.ts) and [`src/fork.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/fork.ts) respectively.
- The **`serialize`** and **`deserialize`** functions handle binary conversion for Swarm HTTP API compatibility.
- Only modified branches require re-uploading due to the Merkle-DAG structure, making updates efficient for large datasets.

## Frequently Asked Questions

### How does Mantaray-js differ from bee-js?

Mantaray-js handles only the data structure and binary serialization of Swarm manifests, while bee-js manages network operations, chunk uploading, and node communication. Use Mantaray-js to build manifest binaries, then use bee-js or `swarm-cli` to upload them to a Swarm node.

### What is the binary format produced by Mantaray-js?

The `serialize` method produces a `Uint8Array` containing the compact binary representation of the manifest Merkle-DAG. This format is recognized by Swarm's HTTP gateway at endpoints like `POST /bzz:/` and `GET /bzz:/<root-hash>/path`.

### Can Mantaray-js handle large directory structures?

Yes. The Merkle-DAG structure means Mantaray-js can represent deeply nested directories efficiently. The `walk` utility in [`src/walk.ts`](https://github.com/ethersphere/awesome-swarm/blob/main/src/walk.ts) performs depth-first traversal without loading the entire tree into memory at once, enabling processing of large manifests.

### What metadata can be stored in a MantarayFork?

The `metadata` field accepts any JSON-serializable object, commonly used for `mime` (MIME type), `size` (file size), and custom application data. The `mode` field stores Unix-style permission bits for POSIX compatibility.