Back

Blog details

IPFS Garbage Collection: What Unpinning Actually Does

AIOZ Network
6 min readAugust 26, 2026
aioz-pin

IPFS garbage collection is the mechanism that actually frees disk space on a node, and it only runs on data that is not pinned. Unpinning a file does not delete it. It removes the one thing standing between that file and garbage collection, and what happens after that depends on pin types, the local blockstore, and whether the same content is pinned anywhere else on the network at all.

TL;DR:

  • Pinning does not store data twice; it marks existing blocks as "do not delete," which is the only thing that protects them from garbage collection
  • IPFS has three pin types: direct (just one block), recursive (a block and everything it links to), and indirect (a block pinned only because its parent is pinned recursively)
  • ipfs repo gc walks every local pin plus the local Mutable File System root, then deletes any block in local storage that isn't reachable from one of those
  • Unpinning a file only removes it from that reachable set on the node you unpinned it from; if other peers still have it pinned, the content is still on the network, just not guaranteed to be
  • AIOZ Pin's unpin command removes a pin request, not a guarantee that the content vanishes instantly, since the same CID may still be pinned elsewhere until nobody is left holding it

Pinning Doesn't Copy Data, It Protects It

When content gets added to an IPFS node, its blocks land in local storage regardless of pin status. Pinning does not create a second copy; it flags the blocks already there as protected, telling the node's garbage collector to leave them alone. This matters because it means "pinned" and "stored" are not the same claim, a node can have plenty of unpinned data sitting in its blockstore too, it is just fair game for deletion the next time garbage collection runs.

The Three Pin Types

IPFS tracks three distinct kinds of pins, and the distinction matters for anything that touches directories rather than single files.

Direct pins protect exactly one block and nothing connected to it. Pinning a directory's root block directly, without recursion, does not protect the files inside it.

Recursive pins protect a block and every block it links to, walked all the way down. Pinning a directory recursively protects the directory node itself plus every file and subdirectory beneath it, which is the pin type almost every practical pinning use case actually wants.

Indirect pins are not requested directly at all. A block becomes indirectly pinned purely as a side effect of some ancestor being pinned recursively. Every file inside a recursively-pinned folder holds an indirect pin, not a direct one, and that pin disappears automatically the moment the recursive pin above it is removed, no separate action needed.

ipfs pin ls --type=<direct|recursive|indirect|all> on a kubo node lists exactly which category a given pin falls into, which is the only reliable way to tell whether something is protected because it was pinned on purpose or because it happens to live inside something else that was.

What Garbage Collection Actually Deletes

ipfs repo gc is a reachability sweep, not a scheduled or automatic background process, it runs when explicitly invoked (or when a node is configured to run it automatically). It walks every pin currently registered on the node, direct, recursive, and everything recursion reaches indirectly, plus one more root: the Mutable File System (MFS), the "better way" IPFS documentation points to for keeping files and directories protected without manually managing pin lists. Anything block-level that isn't reachable from that combined set gets deleted from local storage. Nothing about content being popular, recently added, or referenced somewhere off-node saves it, reachability from a local pin or MFS is the entire test.

The MFS-and-GC interaction was genuinely fragile until recently: kubo v0.43.0 (August 2026) fixed a real race condition where a live MFS write could get collected out from under it mid-operation. The fix makes GC take the same lock an MFS write already holds and read the MFS root while that lock is active, so garbage collection can no longer sweep data a write is still in the middle of touching. Worth knowing if you're running your own kubo node directly, less relevant if you're pinning through a managed service like AIOZ Pin, where that race isn't something the client side ever has to reason about.

What Unpinning Actually Does

Removing a pin, ipfs pin rm on a raw kubo node, does exactly one thing: it takes that content out of the protected set on that specific node. It does not touch the content itself, does not notify any other peer, and does not remove the blocks from local storage immediately, they simply become eligible for deletion the next time garbage collection runs on that node. Two consequences follow directly from this. First, unpinning is reversible until GC actually runs, re-pinning the same CID before then costs nothing extra since the blocks never left local storage. Second, unpinning on one node has zero effect on any other node that independently pinned the same content, the CID keeps resolving everywhere else exactly as before.

Why This Two-Step Design Exists

Separating "stop protecting this" from "actually delete this" is a deliberate safety margin, not an accident of implementation. Immediate deletion on unpin would make an accidental unpin unrecoverable the moment it happened. The reachability-sweep design instead gives a node the entire window between one GC run and the next to catch a mistake, and it also means GC can be run on a schedule that suits the node's own disk pressure rather than firing on every single pin change.

Unpinning on AIOZ Pin: A Request, Not an Instant Deletion

AIOZ Pin's CLI removes a pin with pinning unpin --id=<pin-id>, using the pin request's own ID rather than the raw CID directly, since AIOZ Pin implements the standard Pinning Service API rather than exposing kubo's local pin commands. Running that command tells AIOZ Pin's infrastructure to stop guaranteeing that file's availability going forward. It is the same two-layer reality as raw IPFS underneath: the request to stop protecting the content is immediate, but whether the content becomes unreachable afterward depends on whether any other peer, on AIOZ Pin's infrastructure or anywhere else on the network, still has it pinned. A CID that was also pinned independently by someone else does not vanish just because one pinning service stopped guaranteeing it.

Frequently Asked Questions

Does unpinning a file on IPFS delete it immediately? No. Unpinning removes the content from the local protected set. Actual deletion only happens the next time garbage collection runs, and only if nothing else on that node still references the content.

What is the difference between a direct and recursive pin? A direct pin protects a single block only. A recursive pin protects that block and everything it links to, which is what's needed to protect an entire directory tree rather than just its root node.

What is an indirect pin? A pin that exists automatically because a parent block above it is pinned recursively. It is not requested separately and disappears automatically if the recursive pin above it is removed.

Does IPFS garbage collection run automatically? It runs when explicitly triggered via ipfs repo gc, or on a schedule if a node is configured for automatic GC. It is not tied to how recently or how often content was accessed.

If I unpin a file on AIOZ Pin, does it disappear from IPFS entirely? Only if no other peer on the network has it pinned. Unpinning stops AIOZ Pin's guarantee for that file specifically; it has no effect on independent copies pinned elsewhere.

Does MFS protect files the same way pinning does? Yes. Anything reachable from the Mutable File System root is protected from garbage collection the same way a pinned block is, without needing a separate pin entry for it.

References

We only send updates when meaningful changes ship, and you can unsubscribe anytime

Related Content

blog thumbnail

Content Moderation on IPFS: What Actually Happens

Pinning services can remove their own copy of a file. They cannot remove it from IPFS. Here is exactly what a takedown does and does not accomplish.

5 min readSeptember 12, 2026
blog thumbnail

IPFS Transports: TCP vs. QUIC Explained

libp2p connections can run over more than one transport. Here is exactly what changes with QUIC instead of TCP, and why IPFS dials both at once.

5 min readSeptember 11, 2026
blog thumbnail

GossipSub: How IPFS's PubSub Layer Actually Works

The DHT answers who has a CID. GossipSub answers a different question: how do peers push real-time updates to everyone listening, without a lookup at all.

5 min readSeptember 10, 2026
blog thumbnail

Helia: IPFS's Modern JavaScript Implementation

js-ipfs is deprecated. Helia is what replaced it: a modular, TypeScript-first IPFS implementation built for the browser and Node.js. Here is how it fits.

5 min readSeptember 09, 2026
blog thumbnail

IPLD Selectors: Fetching Part of a DAG, Not All of It

Not every retrieval needs the whole DAG. IPLD Selectors describe exactly which nodes to traverse and match, so a client can fetch a slice, not everything.

5 min readSeptember 08, 2026
blog thumbnail

ipfs:// in the Browser: How It Actually Works

Almost no browser understands ipfs:// links natively. Here is exactly why, what IPFS Companion actually does about it, and why gateway URLs took over instead.

5 min readSeptember 07, 2026