# Conflicts: # .github/workflows/gateway-conformance.yml # docs/changelogs/v0.40.md # docs/examples/kubo-as-a-library/go.mod # docs/examples/kubo-as-a-library/go.sum # go.mod # go.sum # test/dependencies/go.mod # test/dependencies/go.sum
18 KiB
Kubo changelog v0.40
This release was brought to you by the Shipyard team.
v0.40.0
- Overview
- 🔦 Highlights
- 🔢 UnixFS CID Profiles (IPIP-499)
- 🧹 Automatic cleanup of interrupted imports
- Routing V1 HTTP API now exposed by default
- Track total size when adding pins
- IPIP-523:
?format=takes precedence overAcceptheader - IPIP-524: Gateway codec conversion disabled by default
- Improved IPNS over PubSub validation
- New
ipfs diag datastorecommands - 🚇 Improved
ipfs p2ptunnels with foreground mode - Improved
ipfs dag statoutput - 🔑
ipfs keyimprovements - Accelerated DHT Client and Provide Sweep now work together
- 🌐 No unnecessary DNS lookups for AutoTLS addresses
- ⏱️ Configurable gateway request duration limit
- 🔧 Recovery from corrupted MFS root
- 📡 RPC
Content-Typeheaders for binary responses - 🔖 New
ipfs name get|putcommands - 📋 Long listing format for
ipfs ls - 🖥️ WebUI Improvements
- 📦️ Dependency updates
- 📝 Changelog
- 👨👩👧👦 Contributors
Overview
🔦 Highlights
🔢 UnixFS CID Profiles (IPIP-499)
IPIP-499 CID Profiles are presets that pin down how files get split into blocks and organized into directories. Useful when you need the same CID for the same data across different software or versions.
New configuration profiles
unixfs-v1-2025: modern CIDv1 profile with improved defaultsunixfs-v0-2015(aliaslegacy-cid-v0): best-effort legacy CIDv0 behavior
Apply with: ipfs config profile apply unixfs-v1-2025
The test-cid-v1 and test-cid-v1-wide profiles have been removed. Use unixfs-v1-2025 or manually set specific Import.* settings instead.
New Import.* options
Import.UnixFSHAMTDirectorySizeEstimation: estimation mode (links,block, ordisabled)Import.UnixFSDAGLayout: DAG layout (balancedortrickle)
New ipfs add CLI flags
--dereference-symlinksresolves all symlinks to their target content, replacing the deprecated--dereference-argswhich only resolved CLI argument symlinks--empty-dirs/-Econtrols inclusion of empty directories (default: true)--hidden/-Hincludes hidden files (default: false)--trickleimplicit default can be adjusted viaImport.UnixFSDAGLayout
ipfs files write fix for CIDv1 directories
When writing to MFS directories that use CIDv1 (via --cid-version=1 or ipfs files chcid), single-block files now produce raw block CIDs (like bafkrei...), matching the behavior of ipfs add --raw-leaves. Previously, MFS would wrap single-block files in dag-pb even when raw leaves were enabled. CIDv0 directories continue to use dag-pb.
HAMT Threshold Fix
HAMT directory sharding threshold changed from >= to > to match the Go docs and JS implementation (ipfs/boxo@6707376). A directory exactly at 256 KiB now stays as a basic directory instead of converting to HAMT. This is a theoretical breaking change, but unlikely to impact real-world users as it requires a directory to be exactly at the threshold boundary. If you depend on the old behavior, adjust Import.UnixFSHAMTShardingSize to be 1 byte lower.
🧹 Automatic cleanup of interrupted imports
If you cancel ipfs add or ipfs dag import mid-operation, Kubo now automatically cleans up incomplete data on the next daemon start. Previously, interrupted imports would leave orphan blocks in your repository that were difficult to identify and remove without pins and running explicit garbage collection.
Batch operations also use less memory now. Block data is written to disk immediately rather than held in RAM until the batch commits.
Under the hood, the block storage layer (flatfs) was rewritten to use atomic batch operations via a temporary staging directory. See go-ds-flatfs#142 for details.
Routing V1 HTTP API now exposed by default
The Routing V1 HTTP API is now exposed by default at http://127.0.0.1:8080/routing/v1. This allows light clients in browsers to use Kubo Gateway as a delegated routing backend instead of running a full DHT client. Support for IPIP-476: Delegated Routing DHT Closest Peers API is included. Can be disabled via Gateway.ExposeRoutingAPI.
Track total size when adding pins
Adds total size progress tracking of pinned nodes during ipfs pin add --progress. The output now shows the total size of the pinned dag.
Example output:
Fetched/Processed 336 nodes (83 MB)
IPIP-523: ?format= takes precedence over Accept header
IPIP-523 simplifies HTTP content negotiation by making the ?format= URL query parameter always take priority over the Accept HTTP header when both are present.
This ensures deterministic HTTP caching behavior and protects against CDNs that commingle different response types under the same cache key. It also allows browsers to use ?format= reliably even when they send Accept headers with specific content types.
The only breaking change is for edge cases where a client sends both a specific Accept header and a different ?format= value for an explicitly supported format (tar, raw, car, dag-json, dag-cbor, etc.). Previously Accept would win. Now ?format= always wins.
IPIP-524: Gateway codec conversion disabled by default
Codec conversion is now disabled by default per IPIP-524.
Requests for a format that differs from the block's codec will return 406 Not Acceptable.
Migration: Clients should fetch raw blocks (?format=raw or Accept: application/vnd.ipld.raw)
and convert client-side using libraries like @helia/verified-fetch.
This change removes gateways from a gatekeeping role: new codecs can now be adopted by clients
immediately without waiting for gateway operator updates. Set Gateway.AllowCodecConversion
to true to restore previous behavior.
Improved IPNS over PubSub validation
IPNS over PubSub implementation in Kubo is now more reliable. Duplicate messages are rejected even in large networks where messages may cycle back after the in-memory cache expires.
Kubo now persists the maximum seen sequence number per peer to the datastore (go-libp2p-pubsub#BasicSeqnoValidator), providing stronger duplicate detection that survives node restarts. This addresses message flooding issues reported in #9665.
Kubo's pubsub is optimized for IPNS use case. For custom pubsub applications requiring different validation logic, use go-libp2p-pubsub directly in a dedicated binary.
New ipfs diag datastore commands
New experimental commands for low-level datastore inspection:
ipfs diag datastore get <key>- Read raw value at a datastore key (use--hexfor hex dump)ipfs diag datastore count <prefix>- Count entries matching a datastore prefix
The daemon must not be running when using these commands. Run ipfs diag datastore --help for usage examples.
🚇 Improved ipfs p2p tunnels with foreground mode
P2P tunnels can now run like SSH port forwarding: start a tunnel, use it, and it cleans up automatically when you're done.
The new --foreground (-f) flag for ipfs p2p listen and ipfs p2p forward keeps the command running until interrupted. When you Ctrl+C, send SIGTERM, or stop the service, the tunnel is removed automatically:
$ ipfs p2p listen /x/ssh /ip4/127.0.0.1/tcp/22 --foreground
Listening on /x/ssh, forwarding to /ip4/127.0.0.1/tcp/22, waiting for interrupt...
^C
Received interrupt, removing listener for /x/ssh
Without --foreground, commands return immediately and tunnels persist until explicitly closed (existing behavior).
See docs/p2p-tunnels.md for usage examples.
Improved ipfs dag stat output
The ipfs dag stat command has been improved for better terminal UX:
- Progress output now uses a single line with carriage return, avoiding terminal flooding
- Progress is auto-detected: shown only in interactive terminals by default
- Human-readable sizes are now displayed alongside raw byte counts
Example progress (interactive terminal):
Fetched/Processed 84 blocks, 2097152 bytes (2.1 MB)
Example summary output:
Summary
Total Size: 2097152 (2.1 MB)
Unique Blocks: 42
Shared Size: 1048576 (1.0 MB)
Ratio: 1.500000
Use --progress=true to force progress even when piped, or --progress=false to disable it.
🔑 ipfs key improvements
ipfs key ls is now the canonical command for listing keys, matching ipfs pin ls and ipfs files ls. The old ipfs key list still works but is deprecated.
Listing also became more resilient: bad keys are now skipped with an error log instead of failing the entire operation.
Accelerated DHT Client and Provide Sweep now work together
Previously, provide operations could start before the Accelerated DHT Client discovered enough peers, causing sweep mode to lose its efficiency benefits. Now, providing waits for the initial network crawl (about 10 minutes). Your content will be properly distributed across DHT regions after initial DHT map is created. Check ipfs provide stat to see when providing begins.
🌐 No unnecessary DNS lookups for AutoTLS addresses
Kubo no longer makes DNS queries for AutoTLS addresses like 1-2-3-4.peerid.libp2p.direct. Since the IP is encoded in the hostname (1-2-3-4 means 1.2.3.4), Kubo extracts it locally. This reduces load on the public good DNS servers at libp2p.direct run by Shipyard, reserving them for web browsers which lack direct DNS access and must rely on the browser's resolver.
To disable, set AutoTLS.SkipDNSLookup to false.
⏱️ Configurable gateway request duration limit
Gateway.MaxRequestDuration sets an absolute deadline for gateway requests. Unlike RetrievalTimeout (which resets on each data write and catches stalled transfers), this is a hard limit on the total time a request can take.
The default 1 hour limit (previously hardcoded) can now be adjusted to fit your deployment needs. This is a fallback that prevents requests from hanging indefinitely when subsystem timeouts are misconfigured or fail to trigger. Returns 504 Gateway Timeout when exceeded.
🔧 Recovery from corrupted MFS root
If your daemon fails to start because the MFS root is not a directory (due to misconfiguration, operational error, or disk corruption), you can now recover without deleting and recreating your repository in a new IPFS_PATH.
The new ipfs files chroot command lets you reset the MFS (Mutable File System) root or restore it to a known valid CID:
# Reset MFS to an empty directory
$ ipfs files chroot --confirm
# Or restore from a previously saved directory CID
$ ipfs files chroot --confirm QmYourBackupCID
See ipfs files chroot --help for details.
📡 RPC Content-Type headers for binary responses
HTTP RPC endpoints that return binary data now set appropriate Content-Type headers, making it easier to integrate with HTTP clients and tooling that rely on MIME types. On CLI these commands behave the same as before, but over HTTP RPC you now get proper headers:
| Endpoint | Content-Type |
|---|---|
/api/v0/get |
application/x-tar or application/gzip |
/api/v0/dag/export |
application/vnd.ipld.car |
/api/v0/block/get |
application/vnd.ipld.raw |
/api/v0/name/get |
application/vnd.ipfs.ipns-record |
/api/v0/diag/profile |
application/zip |
🔖 New ipfs name get|put commands
You can now backup, restore, and share IPNS records without needing the private key.
$ ipfs name get /ipns/k51... > record.bin
$ ipfs name get /ipns/k51... | ipfs name inspect
$ ipfs name put k51... record.bin
These are low-level tools primarily for debugging and testing IPNS.
The put command validates records by default. Use --force to skip validation and test how routing systems handle malformed or outdated records. Note that --force only bypasses this command's checks; the routing system may still reject invalid records.
📋 Long listing format for ipfs ls
The ipfs ls command now supports --long (-l) flag for displaying Unix-style file permissions and modification times. This works with files added using --preserve-mode and --preserve-mtime. See ipfs ls --help for format details and examples.
🖥️ WebUI Improvements
IPFS Web UI has been updated to v4.11.0.
Search and filter files
You can now search and filter files directly in the Files screen. Type a name, CID, or file extension and the list narrows down in real time. Works in both list and grid view.
DHT Provide diagnostic screen
New screen under Diagnostics that shows the health of DHT Provide operations. You can see reprovide cycle progress, worker utilization, queue status, and network throughput at a glance, without having to use the ipfs provide stat CLI.
Better path handling in Files
The Inspect button now resolves /ipfs/ and /ipns/ paths to their final CID before opening the IPLD Explorer. The Explore form also accepts ipfs:// and ipns:// protocol URLs. Previously, these would show a blank screen or an infinite spinner. Path resolution errors now also show better error pages:
📦️ Dependency updates
- update
go-libp2pto v0.47.0 (incl. v0.46.0)- Reduced WebRTC log noise by using debug level for pion errors (go-libp2p#3426).
- Fixed mDNS discovery on Windows and macOS by filtering addresses to reduce packet size (go-libp2p#3434).
- AutoTLS addresses no longer get marked unreachable when peers lack WebSockets support. Swarm heals over time (go-libp2p#3435).
- Fixed
stream.Close()blocking indefinitely on unresponsive peers (go-libp2p#3448).
- update
quic-goto v0.59.0 (incl. v0.58.0 + v0.57.0) - update
p2p-forgeto v0.7.0 - update
go-ds-pebbleto v0.5.9- updates
github.com/cockroachdb/pebbleto v2.1.4 to enable Go 1.26 support
- updates
- update
go-libp2p-pubsubto v0.15.0 - update
boxoto v0.36.0 - update
go-libp2p-kad-dhtto v0.37.1 (includes v0.37.0) - update
ipfs-webuito v4.11.0 - update
gateway-conformancetests to v0.9