ipfs/kubo - v0.43.1 New

Published: Sep 15, 2026
OTHER Deadline: Sep 30, 2026

Release Summary

Kubo v0.43.1 has been released, delivering important bug fixes, performance enhancements, and a few new configuration options. This is a significant maintenance release that node operators will want to adopt.

This version also marks the final Kubo release from the Shipyard team, as their work on IPFS concludes on September 30, 2026.

Performance and Stability Fixes

A key fix addresses a performance regression from v0.43.0. Provider record writes are now batched again (256 at a time), which significantly reduces the constant disk activity and high I/O rates that some operators experienced. This restores the disk write performance from before v0.43.0.

Another notable improvement is that Bitswap no longer sends constant background pings to HTTP providers, cutting down on idle network traffic. Daemons started with `--enable-gc` will also now shut down correctly via the RPC command.

Configuration and Control

Operators now have more precise control over peer connections. Setting the `Bootstrap` list to an empty array (`[]`) now correctly disables all bootstrap dialing, including connections to stale backup peers saved from previous runs. This ensures a node only connects to peers explicitly configured via `Peering.Peers` or `ipfs swarm connect`.

For new nodes, an experimental `flatfs-pebbleds` profile is available (`ipfs init --profile=flatfs-pebbleds`). It uses PebbleDB for metadata (pins, MFS, etc.), which is more efficient at reclaiming disk space after bulk deletions, making it a good choice for nodes with high metadata churn.

Gateway and API Updates

This release implements IPIP-548. Gateway responses now use the new `Ipfs-Uri` header instead of the deprecated `X-Ipfs-Path` header. `Ipfs-Uri` correctly handles all file names, including those with non-ASCII or special characters. The old header is no longer sent by default, but can be temporarily re-enabled with `Gateway.DeprecatedXIpfsPath` to ease client migration.

FUSE and CLI Improvements

Filesystem (FUSE) mounts are now more stable. Files on mounts now have stable inode numbers, fixing issues where tools like `vim` or `find` would fail. A critical bug where writes could be lost after renaming a file on `/mfs` or `/ipns` has also been resolved.

The `ipfs ls` command gains two useful flags: `--human` (`-H`) to print human-readable file sizes and `--sort-size` (`-S`) to list the largest entries first.

Other Notable Changes

Telemetry is now off by default, and Kubo no longer ships with a pre-configured telemetry endpoint. For security, `ipfs key export` now ensures exported key files are created with owner-only permissions (`0600`), even when overwriting an existing file.

Release Notes

<a href="https://ipshipyard.com/"><img align="right" src="https://github.com/user-attachments/assets/39ed3504-bb71-47f6-9bf8-cb9a1698f272" /></a>

> [!NOTE]
> This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.

> [!IMPORTANT]
> v0.43 is the last Kubo by the Shipyard. Our IPFS work [ends on September 30, 2026](https://ipshipyard.com/blog/2026-the-end-of-ipfs-at-shipyard/). Bring your support and transition questions to the [community forum](https://discuss.ipfs.tech/).

[<img align="right" width="256px" src="https://github.com/user-attachments/assets/b1e9f70a-a22e-406d-bc5b-e2c337c14400" />](https://github.com/user-attachments/assets/b1e9f70a-a22e-406d-bc5b-e2c337c14400)

- [๐Ÿ”ฆ Highlights](#-highlights)
  - [๐Ÿ”‡ Empty `Bootstrap` list disables all bootstrap dialing](#-empty-bootstrap-list-disables-all-bootstrap-dialing)
  - [๐Ÿ—„๏ธ Improved datastore profiles and docs](#-improved-datastore-profiles-and-docs)
  - [๐Ÿ—‚๏ธ Setting the flatfs shard depth is less error-prone](#-setting-the-flatfs-shard-depth-is-less-error-prone)
  - [๐Ÿ“ `ipfs ls` can print readable sizes and sort by size](#-ipfs-ls-can-print-readable-sizes-and-sort-by-size)
  - [๐Ÿ“Œ Files on FUSE mounts keep their inode number](#-files-on-fuse-mounts-keep-their-inode-number)
  - [๐Ÿงน FUSE mounts keep what you write after a rename](#-fuse-mounts-keep-what-you-write-after-a-rename)
  - [๐Ÿ” `ipfs key export` writes are owner-only](#-ipfs-key-export-writes-are-owner-only)
  - [๐Ÿ›‘ `ipfs shutdown` exits a daemon started with `--enable-gc`](#-ipfs-shutdown-exits-a-daemon-started-with---enable-gc)
  - [๐Ÿ”— Gateway `Ipfs-Uri` header replaces `X-Ipfs-Path` (IPIP-548)](#-gateway-ipfs-uri-header-replaces-x-ipfs-path-ipip-548)
  - [๐Ÿ”„ Bitswap sees peers connected before it starts](#-bitswap-sees-peers-connected-before-it-starts)
  - [๐Ÿคซ No more background pings to HTTP providers](#-no-more-background-pings-to-http-providers)
  - [๐Ÿ”• Telemetry is off by default](#-telemetry-is-off-by-default)
  - [๐ŸŒ Future-proofing browser retrieval: WebTransport fix for Safari 26](#-future-proofing-browser-retrieval-webtransport-fix-for-safari-26)
  - [๐Ÿ’พ Provider record writes are batched again](#-provider-record-writes-are-batched-again)
  - [๐Ÿ”’ Hardened CID profiles, new low-level knob](#-hardened-cid-profiles-new-low-level-knob)
  - [๐Ÿ“ฆ๏ธ Dependency updates](#-dependency-updates)
- [๐Ÿ“ Changelog](#-changelog)
- [๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Contributors](#-contributors)

This is mostly a bugfix release. It also carries a few small, opt-in configuration options and profiles that landed since v0.43.0.

### ๐Ÿ”ฆ Highlights

#### ๐Ÿ”‡ Empty `Bootstrap` list disables all bootstrap dialing

Setting `Bootstrap` to `[]` now stops the node from dialing bootstrap peers of any kind, including the backup peers it saved from earlier runs. Until now, a node that had once run with the default bootstrappers kept dialing those saved peers every 30 seconds, even with an empty list and `Routing.Type=none`.

The result is a node that connects only to peers you chose: [`Peering.Peers`](https://github.com/ipfs/kubo/blob/master/docs/config.md#peeringpeers), `ipfs swarm connect`, and peers found on the local network through [mDNS](https://github.com/ipfs/kubo/blob/master/docs/config.md#discoverymdnsenabled). For no outbound traffic at all, also set [`Routing.Type`](https://github.com/ipfs/kubo/blob/master/docs/config.md#routingtype) to `none` and disable [`AutoConf`](https://github.com/ipfs/kubo/blob/master/docs/config.md#autoconfenabled).

Backup peers still work when `Bootstrap` has at least one entry: the node dials the configured peers first and falls back to saved peers only while it stays below the minimum peer count.

#### ๐Ÿ—„๏ธ Improved datastore profiles and docs

Kubo keeps blocks in flatfs and everything else (pins, MFS root, IPNS and DHT provider records) in leveldb. leveldb is slow to reclaim space after bulk deletes, so on nodes that churn that metadata all day, `datastore/` grows far past the live data. `ipfs init --profile=flatfs-pebbleds` keeps flatfs for blocks and puts the rest in pebble, which compacts deleted keys promptly. This works for new repos only. The profile is experimental, and pebble has less production use in Kubo than leveldb, so report problems in [kubo issues](https://github.com/ipfs/kubo/issues). Details in the [profile docs](https://github.com/ipfs/kubo/blob/master/docs/config.md#flatfs-pebbleds-profile).

The default layout is unchanged. Its profile is now named `flatfs-levelds`, and `flatfs` and `flatfs-measure` stay as aliases. The [datastore docs](https://github.com/ipfs/kubo/blob/master/docs/datastores.md#flatfs) say which data lives in which store and why flatfs holds only blocks.

#### ๐Ÿ—‚๏ธ Setting the flatfs shard depth is less error-prone

The flatfs shard depth (`shardFunc`) can only be set when a repo is created, by passing a config file to `ipfs init`. That route had traps. Fixed:

- `ipfs init <file>` and `ipfs daemon --init --init-config` refuse a config without a private key, such as `ipfs config show` output, which used to produce a repo that crashed on start.
- `ipfs init` checks `Datastore.Spec` before writing anything, so a typo in `shardFunc` no longer leaves a half-made repo.
- `ipfs config profile apply` refuses a profile that would change the datastore layout of an existing repo instead of writing a config the repo can no longer open.
- The `Datastore.Spec` vs `datastore_spec` mismatch error labels the two values correctly and says what to do.

[`docs/datastores.md`](https://github.com/ipfs/kubo/blob/master/docs/datastores.md#choosing-a-shardfunc-for-large-blockstores) has the steps for setting `next-to-last/3` on a new repo, when it is worth it, and how to move an existing repo. Defaults are unchanged.

#### ๐Ÿ“ `ipfs ls` can print readable sizes and sort by size

Two new flags on `ipfs ls`, both off by default. `--human` (`-H`) prints sizes in SI units such as `3.0 kB` and `2.0 MB`, matching `ipfs repo stat -H`. `--sort-size` (`-S`) lists the biggest entries first, so you can find what fills a directory without piping through `sort`. Run `ipfs ls --help` for how they combine with `--stream`, `--size`, and the JSON response.

#### ๐Ÿ“Œ Files on FUSE mounts keep their inode number

A file on a mount made by `ipfs mount` used to get a new inode number roughly every second, whenever the kernel dropped and re-read its directory entry. Programs that check whether a file is still the same file read that as the file being replaced under them. Saving a file on `/mfs` with vim could fail with `E949: File changed while writing`, and `pwd`, `find` and backup tools could misbehave for the same reason.

All three mounts now hand out stable numbers. On `/ipfs` the number comes from the CID, so the same content is the same object whichever path reaches it, and the same number comes back after a remount. On `/ipns` and `/mfs` an entry keeps its number for as long as it exists, including across a rename, while a name that is deleted and created again is numbered afresh; those numbers are assigned per mount and start over on the next one. Deleting through `ipfs files` rather than through the mount is the exception: the mount does not see it, so the name keeps its old number if it comes back.

Smaller fixes come with it: mount points report an inode number instead of `0`, `ls -i` agrees with `stat`, the link count is `1` rather than the `0` POSIX gives to a deleted file, and `/ipns/<key>` directories show their real permissions instead of `d---------`.

#### ๐Ÿงน FUSE mounts keep what you write after a rename

Renaming on a mounted `/mfs` or `/ipns` left the kernel writing into the entry the rename had just taken away. `mv a b` followed by a write to `b` reported success and then quietly went back to the old contents a second later. A file created in a directory that had just been renamed vanished the same way, and the directory reappeared under the name it had been moved away from. Renaming over a directory that was not empty deleted everything in it, where POSIX asks for `ENOTEMPTY`.

On `/ipfs`, a listing no longer fails in its entirety when one child's block is missing, an entry in a codec the mount cannot decode reads back the block rather than refusing, and the `ipfs.cid` xattr answers with the CID from the path instead of a re-encoded form of it.

#### ๐Ÿ” `ipfs key export` writes are owner-only

`ipfs key export` now writes the key file with owner-only permissions (`0600`), including when it overwrites an existing file with looser permissions. The export goes to a temporary file renamed over the target, so a failed export leaves the previous contents intact; character devices and pipes such as `/dev/null` are streamed to directly.

#### ๐Ÿ›‘ `ipfs shutdown` exits a daemon started with `--enable-gc`

A daemon started with `--enable-gc` closed its repo on `ipfs shutdown` (`POST /api/v0/shutdown`) but the process never exited, because the periodic garbage collection loop only stopped on a signal. Supervisors that stop Kubo over the RPC API waited forever. The loop now also stops when the node closes; `SIGINT` and `SIGTERM` behave as before.

#### ๐Ÿ”— Gateway `Ipfs-Uri` header replaces `X-Ipfs-Path` (IPIP-548)

Gateway responses now include an [`Ipfs-Uri` header](https://specs.ipfs.tech/http-gateways/path-gateway/#ipfs-uri-response-header) with a canonical [`ipfs://`](https://specs.ipfs.tech/ipfs-uri/) or [`ipns://`](https://specs.ipfs.tech/ipns-uri/) address of the requested content path ([IPIP-548](https://github.com/ipfs/specs/pull/548)). Every path segment is percent-encoded, so the address survives any file name, including names with spaces, `%`, `#`, and non-ASCII characters.

> [!IMPORTANT]
> Kubo no longer sends the deprecated `X-Ipfs-Path` header. HTTP header values cannot carry non-ASCII bytes, so a path with such a file name arrives garbled. Clients that read `X-Ipfs-Path` must migrate to `Ipfs-Uri`; decoding it back into a content path takes a single percent-decode of each path segment. Operators who need time can temporarily restore the legacy header with [`Gateway.DeprecatedXIpfsPath`](https://github.com/ipfs/kubo/blob/master/docs/config.md#gatewaydeprecatedxipfspath); even then Kubo omits it when the value contains bytes that cannot appear in an HTTP header.

#### ๐Ÿ”„ Bitswap sees peers connected before it starts

A peer that was already connected when the node started stayed invisible to Bitswap: libp2p reports only connections opened after a notifier registers, so no want request was ever sent over such a connection. Nodes with other ways to find content usually masked it; a node relying on an already-connected peer could wait forever. Fixed in [boxo v0.42.2](https://github.com/ipfs/boxo/releases/tag/v0.42.2).

#### ๐Ÿคซ No more background pings to HTTP providers

Bitswap over HTTP no longer probes every connected HTTP provider with `GET/HEAD /ipfs/bafkqaaa` every 5 seconds for the lifetime of the process. Idle HTTP peers now generate no background traffic; latency is measured from the connection probe and from real retrieval responses instead ([boxo v0.42.2](https://github.com/ipfs/boxo/releases/tag/v0.42.2)).

#### ๐Ÿ”• Telemetry is off by default

Kubo no longer ships with a telemetry endpoint. The collector at `telemetry.ipshipyard.dev` shuts down with [the end of Shipyard's IPFS work](https://ipshipyard.com/blog/2026-the-end-of-ipfs-at-shipyard/), so a node now collects nothing and sends nothing unless you point it at your own collector with `Plugins.Plugins.telemetry.Config.Endpoint`. A node that reported under an earlier version removes its stored `telemetry_uuid` on the next daemon start. The opt-outs (`IPFS_TELEMETRY=off`, `DO_NOT_TRACK=1`, the config `Mode`) keep working for builds that set an endpoint. See [docs/telemetry.md](https://github.com/ipfs/kubo/blob/master/docs/telemetry.md).

#### ๐ŸŒ Future-proofing browser retrieval: WebTransport fix for Safari 26

Kubo's WebTransport listener now supports session flow control from [WebTransport over HTTP/3 draft-16](https://datatracker.ietf.org/doc/draft-ietf-webtrans-http3/16/). Safari 26 opens no stream on a session unless the server advertises session limits, so Kubo advertises them. The limits are set so high they never apply; the QUIC per-connection limits and the [libp2p resource manager](https://github.com/ipfs/kubo/blob/master/docs/libp2p-resource-management.md) remain the effective caps.

#### ๐Ÿ’พ Provider record writes are batched again

`go-libp2p-kad-dht` v0.42.0, first shipped in Kubo v0.43.0, turned every DHT provider record write, and every delete made by the provider's garbage collection, into an individual, fsynced datastore operation. On nodes announcing many CIDs this showed up as constant disk activity. This release batches these writes and deletes again, 256 records at a time, restoring the disk write rate from before v0.43.0. Nothing changes on the wire or in the datastore layout; upgrading is all that is needed.

#### ๐Ÿ”’ Hardened CID profiles, new low-level knob

The `unixfs-v0-2015` and `unixfs-v1-2025` profiles now pin the `PBNode` field order (`links-first`) explicitly, and regression tests lock in the exact bytes and CIDs they produce. Reading blocks in either field order is formalized in [IPIP-550](https://github.com/ipfs/specs/pull/550) and tested by [gateway-conformance v0.14.1](https://github.com/ipfs/gateway-conformance/releases/tag/v0.14.1). Nothing changes by default.

For writers that need `Data`-first output (streaming readers can then parse HAMT shards without buffering all links first), there is a new opt-in [`Import.UnixFSPBNodeFieldOrder`](https://github.com/ipfs/kubo/blob/master/docs/config.md#importunixfspbnodefieldorder) option. No profile enables it. Opting in changes the CIDs of newly added directories, HAMT shards, and multi-chunk files, and MFS re-encodes the directories that `ipfs files` operations rewrite; enable it only when consumers of your CIDs expect the new order.

#### ๐Ÿ“ฆ๏ธ Dependency updates

- update `boxo` to [v0.43.0](https://github.com/ipfs/boxo/releases/tag/v0.43.0) (includes [ipfs/boxo#1212](https://github.com/ipfs/boxo/pull/1212) and [ipfs/boxo#1213](https://github.com/ipfs/boxo/pull/1213)); also pulls in `go.opentelemetry.io/otel` [v1.46.0](https://github.com/open-telemetry/opentelemetry-go/releases/tag/v1.46.0)
- update `go-libp2p-kad-dht` to [v0.42.2](https://github.com/libp2p/go-libp2p-kad-dht/releases/tag/v0.42.2)
- update `go-ds-pebble` to [v0.5.13](https://github.com/ipfs/go-ds-pebble/releases/tag/v0.5.13)
- update `gateway-conformance` to [v0.14.1](https://github.com/ipfs/gateway-conformance/releases/tag/v0.14.1)
- update `quic-go` to [v0.62.0](https://github.com/quic-go/quic-go/releases/tag/v0.62.0) and `webtransport-go` to [v0.13.0](https://github.com/quic-go/webtransport-go/releases/tag/v0.13.0)

### ๐Ÿ“ Changelog

<details><summary>Full Changelog</summary>

- github.com/ipfs/kubo:
  - fix(webtransport): keep Safari 26 sessions working
  - chore: upgrade to boxo v0.43.0 (#11467) ([ipfs/kubo#11467](https://github.com/ipfs/kubo/pull/11467))
  - chore: ship without a telemetry endpoint
  - docs: clearer datastore layouts and init errors (#11449) ([ipfs/kubo#11449](https://github.com/ipfs/kubo/pull/11449))
  - fix(daemon): exit on RPC shutdown with --enable-gc (#11447) ([ipfs/kubo#11447](https://github.com/ipfs/kubo/pull/11447))
  - fix: empty Bootstrap list no longer dials stale backup peers (#11453) ([ipfs/kubo#11453](https://github.com/ipfs/kubo/pull/11453))
  - test(unixfs): lock in CID profile behavior (IPIP-550) (#11439) ([ipfs/kubo#11439](https://github.com/ipfs/kubo/pull/11439))
  - chore: bump go-libp2p-kad-dht to v0.42.2 (#11436) ([ipfs/kubo#11436](https://github.com/ipfs/kubo/pull/11436))
  - chore: maintenance disclaimer
  - fix: Ipfs-Uri gateway header (IPIP-548) (#11437) ([ipfs/kubo#11437](https://github.com/ipfs/kubo/pull/11437))
  - fix(fuse): keep what you write after a rename (#11430) ([ipfs/kubo#11430](https://github.com/ipfs/kubo/pull/11430))
  - fix(fuse): give mounts stable inode numbers (#11429) ([ipfs/kubo#11429](https://github.com/ipfs/kubo/pull/11429))
  - fix(key): restrict overwritten key exports to owner-only permissions (#11428) ([ipfs/kubo#11428](https://github.com/ipfs/kubo/pull/11428))
  - chore(ci): remove self-hosted runners [skip changelog] (#11426) ([ipfs/kubo#11426](https://github.com/ipfs/kubo/pull/11426))
  - docs: guide for running on low-memory devices (#11427) ([ipfs/kubo#11427](https://github.com/ipfs/kubo/pull/11427))
  - docs: drop expired pgp key from security notes (#11422) ([ipfs/kubo#11422](https://github.com/ipfs/kubo/pull/11422))
  - docs: fix private networks setup wording (#11388) ([ipfs/kubo#11388](https://github.com/ipfs/kubo/pull/11388))
  - feat(cli): add --human and --sort-size to ipfs ls (#11408) ([ipfs/kubo#11408](https://github.com/ipfs/kubo/pull/11408))
- github.com/ipfs/boxo (v0.42.1 -> v0.43.0):
  - Release v0.43.0 ([ipfs/boxo#1218](https://github.com/ipfs/boxo/pull/1218))
  - upgrade opentelemetry to v1.44 (#1216) ([ipfs/boxo#1216](https://github.com/ipfs/boxo/pull/1216))
  - chore: upgrade go-libp2p-kad-dht to v0.42.2 ([ipfs/boxo#1214](https://github.com/ipfs/boxo/pull/1214))
  - refactor: update go version to 1.26 and apply modernizers ([ipfs/boxo#1211](https://github.com/ipfs/boxo/pull/1211))
  - fix(bootstrap): skip backup peer list when no bootstrap peers configured (#1213) ([ipfs/boxo#1213](https://github.com/ipfs/boxo/pull/1213))
  - test(unixfs): lock in PBNode field order behavior (IPIP-550) (#1212) ([ipfs/boxo#1212](https://github.com/ipfs/boxo/pull/1212))
  - fix(gateway): IPIP-548 Ipfs-Uri response header (#1209) ([ipfs/boxo#1209](https://github.com/ipfs/boxo/pull/1209))
  - chore: remove @lidel from CODEOWNERS
  - Release v0.42.2 ([ipfs/boxo#1207](https://github.com/ipfs/boxo/pull/1207))
  - fix(bitswap/httpnet): bound probe traffic (#1205) ([ipfs/boxo#1205](https://github.com/ipfs/boxo/pull/1205))
  - docs: describe bitswap broadcast control for broadcast reduction ([ipfs/boxo#1203](https://github.com/ipfs/boxo/pull/1203))
  - fix(bitswap): see peers connected before startup (#1201) ([ipfs/boxo#1201](https://github.com/ipfs/boxo/pull/1201))
  - docs: spec guardrails (#1204) ([ipfs/boxo#1204](https://github.com/ipfs/boxo/pull/1204))
  - chore: refresh issue templates and docs links
  - chore: small correction to changelog ([ipfs/boxo#1202](https://github.com/ipfs/boxo/pull/1202))
- github.com/ipfs/go-ds-pebble (v0.5.12 -> v0.5.13):
  - update version for release v0.5.13 (#92) ([ipfs/go-ds-pebble#92](https://github.com/ipfs/go-ds-pebble/pull/92))
  - refactor: update go version to 1.26 and apply modernizers (#91) ([ipfs/go-ds-pebble#91](https://github.com/ipfs/go-ds-pebble/pull/91))
- github.com/libp2p/go-libp2p-kad-dht (v0.42.1 -> v0.42.2):
  - chore: release v0.42.2 (#1294) ([libp2p/go-libp2p-kad-dht#1294](https://github.com/libp2p/go-libp2p-kad-dht/pull/1294))
  - fix(records): batch provider datastore writes and GC deletes (#1293) ([libp2p/go-libp2p-kad-dht#1293](https://github.com/libp2p/go-libp2p-kad-dht/pull/1293))
  - docs: spec guardrails (#1292) ([libp2p/go-libp2p-kad-dht#1292](https://github.com/libp2p/go-libp2p-kad-dht/pull/1292))
  - fix(provider): pass lifecycle context to local record callback (#1288) ([libp2p/go-libp2p-kad-dht#1288](https://github.com/libp2p/go-libp2p-kad-dht/pull/1288))

</details>

### ๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ Contributors

| Contributor | Commits | Lines ยฑ | Files Changed |
|-------------|---------|---------|---------------|
| [@lidel](https://github.com/lidel) | 24 | +5265/-515 | 106 |
| [@guillaumemichel](https://github.com/guillaumemichel) | 3 | +1058/-148 | 10 |
| [@questfever](https://github.com/questfever) | 1 | +450/-41 | 5 |
| [@capricornusx](https://github.com/capricornusx) | 1 | +444/-12 | 5 |
| [@gammazero](https://github.com/gammazero) | 10 | +138/-100 | 29 |
| [@karawitan](https://github.com/karawitan) | 2 | +150/-7 | 7 |
| [@galargh](https://github.com/galargh) | 1 | +5/-1 | 1 |
| [@weifanglab](https://github.com/weifanglab) | 1 | +2/-2 | 1 |

Links

Back to ipfs/kubo releases