
If you have gone looking for how IPFS handles a folder with thousands of files in it, you have probably run into the term "b-tree" somewhere along the way. That is not what is actually happening. IPFS shards large directories using a HAMT, a Hash Array Mapped Trie, a different structure with a different set of tradeoffs. This covers what a HAMT actually is, why IPFS reaches for it specifically, and what happens inside AIOZ Pin when a folder you pin crosses that threshold.
TL;DR:
pinFolderToIPFS() triggers this same sharding transparently once the folder is large enough; nothing about the call changesA Hash Array Mapped Trie is a tree where each node holds a fixed-size table of slots, and which slot an entry lands in is decided by hashing its key and reading off a few bits of that hash per level. Look up an entry by hashing its name, use the first chunk of bits to pick a slot at the root, and either find the entry there or follow a pointer down to a child node keyed by the next chunk of bits. It is a trie in the classical sense (a lookup structure keyed by pieces of an identifier, one level per chunk) built out of hash-derived indices instead of literal character-by-character keys.
This is a different structure from a B-tree. A B-tree balances itself by splitting and merging nodes to keep entries in sorted order and the tree's depth even; a HAMT does not sort anything and does not rebalance, it simply routes by hash, and its depth is bounded by how many bits of hash it takes before entries stop colliding. Both are tree structures used to make lookups faster than scanning a list, but they get there in genuinely different ways, and IPFS's own specs and codebase describe this structure specifically as a HAMT, never as a B-tree.
A small IPFS directory is stored as one DAG node, essentially a list of (name, CID) pairs for its entries. That works fine until the directory gets big enough that listing every entry in one node stops being practical, at which point IPFS reshapes the directory into a HAMT automatically, without you doing anything differently on the client side. The reshaping is transparent: you still add files to the directory and read them back by name, the sharded structure is an internal representation, not something you interact with directly.
IPFS's implementation (the hamt package inside go-unixfs, and its JavaScript counterpart js-hamt-sharding) makes a few concrete choices worth knowing:
Without sharding, a directory with tens of thousands of entries would either need one enormous DAG node listing every entry (slow to fetch and slow to update, since adding one file means re-hashing and re-transmitting the whole list) or a flat structure that gets linearly slower to search as entries pile up. A HAMT avoids both problems: looking up a single file by name touches only as many nodes as the tree is deep, a handful of hops rather than a scan through every entry, regardless of whether the directory holds a hundred files or a hundred thousand. That is the actual payoff of choosing a hash-keyed tree over a flat list: lookup cost stays roughly constant as the directory grows, instead of degrading with it.
AIOZ Pin's Node.js SDK exposes pinFolderToIPFS() for pinning an entire directory in one call. Nothing about calling it changes based on folder size, but what happens underneath does: a folder small enough to list directly stays a flat DAG node, and one that grows past the sharding threshold gets represented as a HAMT automatically, the same mechanism any IPFS implementation uses. This matters practically if you are pinning something like a large NFT collection's asset folder or a dataset with thousands of files: the CID you get back for the folder is still one identifier either way, the sharding is invisible from the API, but it is the reason lookups inside a folder with 50,000 files stay fast instead of degrading linearly.
Does IPFS use a B-tree for directories? No. Large IPFS directories are sharded using a HAMT (Hash Array Mapped Trie), a hash-keyed tree structure, not a B-tree.
What triggers a directory to become a HAMT on IPFS? Directory size. A small directory stays a single flat DAG node listing its entries; once it grows past IPFS's internal size threshold, it gets automatically reshaped into a HAMT.
Do I need to do anything differently to pin a large folder on AIOZ Pin? No. pinFolderToIPFS() works the same way regardless of folder size; sharding happens transparently underneath the same API call.
Why does IPFS use a table size of 256 instead of the standard 32? A wider table means fewer levels of nesting are needed for a given number of entries, trading a small amount of extra space per node for shallower, faster lookups.
Is Murmur3 a secure hash function? No, and IPFS does not need it to be for this purpose. Murmur3 is fast, not cryptographically secure, and directory sharding does not need tamper-resistance since the surrounding Merkle DAG already provides that at the content level.
Does sharding change a folder's CID? No. The folder still resolves to one CID either way; the HAMT is purely an internal representation of how that folder's entries are organized on disk and over the network.
pinFolderToIPFS() fits among AIOZ Pin's other SDK methods
IPFS defaults to 256 KiB fixed-size chunks, but also ships Rabin and Buzhash content-defined chunkers. Here is why the choice affects deduplication.

An IPFS CID is not a random string. It encodes a version, a codec, and a hash algorithm plus digest. Here is how to decode a real CID piece by piece.

IPFS does not use a B-tree for large directories. It uses a HAMT, a Hash Array Mapped Trie. Here is exactly how it shards a folder once it outgrows one block.

AIOZ Pin image resizing happens straight in the gateway URL, no upload step or separate service. Here is every img- parameter, with real srcset examples.

x402 payments let ERC-8004 weight a paid AI agent interaction more heavily than free work in its reputation score. Here is exactly how that link works.

AIOZ Pin NFT API calls pin an asset and its metadata as two tracked pins under one record. Here is how to automate it directly over REST, no SDK needed.