diff --git a/core/commands/bitswap.go b/core/commands/bitswap.go
index 6502876d197e..21e341d5305b 100644
--- a/core/commands/bitswap.go
+++ b/core/commands/bitswap.go
@@ -134,7 +134,6 @@ var bitswapStatCmd = &cmds.Command{
 			human, _ := req.Options[bitswapHumanOptionName].(bool)
 
 			fmt.Fprintln(w, "bitswap status")
-			fmt.Fprintf(w, "\tprovides buffer: %d / %d\n", s.ProvideBufLen, bitswap.HasBlockBufferSize)
 			fmt.Fprintf(w, "\tblocks received: %d\n", s.BlocksReceived)
 			fmt.Fprintf(w, "\tblocks sent: %d\n", s.BlocksSent)
 			if human {
diff --git a/core/commands/files.go b/core/commands/files.go
index 9a7ee639a2c2..9f24dde0555b 100644
--- a/core/commands/files.go
+++ b/core/commands/files.go
@@ -14,8 +14,6 @@ import (
 	"github.com/ipfs/kubo/core"
 	"github.com/ipfs/kubo/core/commands/cmdenv"
 
-	bservice "github.com/ipfs/boxo/blockservice"
-	offline "github.com/ipfs/boxo/exchange/offline"
 	dag "github.com/ipfs/boxo/ipld/merkledag"
 	ft "github.com/ipfs/boxo/ipld/unixfs"
 	mfs "github.com/ipfs/boxo/mfs"
@@ -162,11 +160,7 @@ var filesStatCmd = &cmds.Command{
 
 		var dagserv ipld.DAGService
 		if withLocal {
-			// an offline DAGService will not fetch from the network
-			dagserv = dag.NewDAGService(bservice.New(
-				node.Blockstore,
-				offline.Exchange(node.Blockstore),
-			))
+			dagserv = node.OfflineDAG
 		} else {
 			dagserv = node.DAG
 		}
diff --git a/core/commands/pin/pin.go b/core/commands/pin/pin.go
index db623a7e6c99..b8836cfe0166 100644
--- a/core/commands/pin/pin.go
+++ b/core/commands/pin/pin.go
@@ -8,8 +8,6 @@ import (
 	"os"
 	"time"
 
-	bserv "github.com/ipfs/boxo/blockservice"
-	offline "github.com/ipfs/boxo/exchange/offline"
 	dag "github.com/ipfs/boxo/ipld/merkledag"
 	verifcid "github.com/ipfs/boxo/verifcid"
 	cid "github.com/ipfs/go-cid"
@@ -702,8 +700,7 @@ type pinVerifyOpts struct {
 func pinVerify(ctx context.Context, n *core.IpfsNode, opts pinVerifyOpts, enc cidenc.Encoder) (<-chan any, error) {
 	visited := make(map[cid.Cid]PinStatus)
 
-	bs := n.Blocks.Blockstore()
-	DAG := dag.NewDAGService(bserv.New(bs, offline.Exchange(bs)))
+	DAG := n.OfflineDAG
 	getLinks := dag.GetLinksWithDAG(DAG)
 
 	var checkPin func(root cid.Cid) PinStatus
diff --git a/core/core.go b/core/core.go
index 0c9333e0683a..1ebd2a6523b6 100644
--- a/core/core.go
+++ b/core/core.go
@@ -81,7 +81,9 @@ type IpfsNode struct {
 	BaseBlocks                  node.BaseBlocks           // the raw blockstore, no filestore wrapping
 	GCLocker                    bstore.GCLocker           // the locker used to protect the blockstore during gc
 	Blocks                      bserv.BlockService        // the block service, get/add blocks.
+	OfflineBlocks               bserv.BlockService        `name:"offlineBlockService"` // blockservice which doesn't try to fetch from the network
 	DAG                         ipld.DAGService           // the merkle dag service, get/add objects.
+	OfflineDAG                  ipld.DAGService           `name:"offlineDagService"`    // merkle dag service which doesn't try to fetch from the network
 	IPLDFetcherFactory          fetcher.Factory           `name:"ipldFetcher"`          // fetcher that paths over the IPLD data model
 	UnixFSFetcherFactory        fetcher.Factory           `name:"unixfsFetcher"`        // fetcher that interprets UnixFS data
 	OfflineIPLDFetcherFactory   fetcher.Factory           `name:"offlineIpldFetcher"`   // fetcher that paths over the IPLD data model without fetching new blocks
diff --git a/core/coreapi/coreapi.go b/core/coreapi/coreapi.go
index 3efe0377862e..988c65aaa36e 100644
--- a/core/coreapi/coreapi.go
+++ b/core/coreapi/coreapi.go
@@ -244,7 +244,7 @@ func (api *CoreAPI) WithOptions(opts ...options.ApiOption) (coreiface.CoreAPI, e
 
 	if settings.Offline || !settings.FetchBlocks {
 		subAPI.exchange = offlinexch.Exchange(subAPI.blockstore)
-		subAPI.blocks = bserv.New(subAPI.blockstore, subAPI.exchange)
+		subAPI.blocks = bserv.New(subAPI.blockstore, nil, bserv.WithProvider(subAPI.provider))
 		subAPI.dag = dag.NewDAGService(subAPI.blocks)
 	}
 
diff --git a/core/coreapi/dht.go b/core/coreapi/dht.go
index 7b5d4eb84619..c8df9afbf56f 100644
--- a/core/coreapi/dht.go
+++ b/core/coreapi/dht.go
@@ -6,9 +6,9 @@ import (
 
 	blockservice "github.com/ipfs/boxo/blockservice"
 	blockstore "github.com/ipfs/boxo/blockstore"
-	offline "github.com/ipfs/boxo/exchange/offline"
 	dag "github.com/ipfs/boxo/ipld/merkledag"
 	"github.com/ipfs/boxo/path"
+	"github.com/ipfs/boxo/provider"
 	cid "github.com/ipfs/go-cid"
 	cidutil "github.com/ipfs/go-cidutil"
 	coreiface "github.com/ipfs/kubo/core/coreiface"
@@ -99,7 +99,7 @@ func (api *DhtAPI) Provide(ctx context.Context, path path.Path, opts ...caopts.D
 	}
 
 	if settings.Recursive {
-		err = provideKeysRec(ctx, api.routing, api.blockstore, []cid.Cid{c})
+		err = provideKeysRec(ctx, api.routing, api.blockstore, api.provider, []cid.Cid{c})
 	} else {
 		err = provideKeys(ctx, api.routing, []cid.Cid{c})
 	}
@@ -120,12 +120,13 @@ func provideKeys(ctx context.Context, r routing.Routing, cids []cid.Cid) error {
 	return nil
 }
 
-func provideKeysRec(ctx context.Context, r routing.Routing, bs blockstore.Blockstore, cids []cid.Cid) error {
+func provideKeysRec(ctx context.Context, r routing.Routing, bs blockstore.Blockstore, prov provider.Provider, cids []cid.Cid) error {
 	provided := cidutil.NewStreamingSet()
 
 	errCh := make(chan error)
 	go func() {
-		dserv := dag.NewDAGService(blockservice.New(bs, offline.Exchange(bs)))
+		// FIXME: we are recreating a blockservice, maybe offline blockservice should be shared ?
+		dserv := dag.NewDAGService(blockservice.New(bs, nil, blockservice.WithProvider(prov)))
 		for _, c := range cids {
 			err := dag.Walk(ctx, dag.GetLinksDirect(dserv), c, provided.Visitor(ctx))
 			if err != nil {
diff --git a/core/coreapi/pin.go b/core/coreapi/pin.go
index 5cb92a819242..9e8c4bd355fe 100644
--- a/core/coreapi/pin.go
+++ b/core/coreapi/pin.go
@@ -5,7 +5,6 @@ import (
 	"fmt"
 
 	bserv "github.com/ipfs/boxo/blockservice"
-	offline "github.com/ipfs/boxo/exchange/offline"
 	"github.com/ipfs/boxo/ipld/merkledag"
 	"github.com/ipfs/boxo/path"
 	pin "github.com/ipfs/boxo/pinning/pinner"
@@ -195,7 +194,8 @@ func (api *PinAPI) Verify(ctx context.Context) (<-chan coreiface.PinStatus, erro
 
 	visited := make(map[cid.Cid]*pinStatus)
 	bs := api.blockstore
-	DAG := merkledag.NewDAGService(bserv.New(bs, offline.Exchange(bs)))
+	// FIXME: we are recreating a dag and blockservice, maybe offline varients should be shared ?
+	DAG := merkledag.NewDAGService(bserv.New(bs, nil, bserv.WithProvider(api.provider)))
 	getLinks := merkledag.GetLinksWithDAG(DAG)
 
 	var checkPin func(root cid.Cid) *pinStatus
diff --git a/core/coreapi/unixfs.go b/core/coreapi/unixfs.go
index 452e6017bc13..40587c42543b 100644
--- a/core/coreapi/unixfs.go
+++ b/core/coreapi/unixfs.go
@@ -106,6 +106,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options
 	}
 	exch := api.exchange
 	pinning := api.pinning
+	prov := api.provider
 
 	if settings.OnlyHash {
 		node, err := getOrCreateNilNode()
@@ -115,9 +116,10 @@ func (api *UnixfsAPI) Add(ctx context.Context, files files.Node, opts ...options
 		addblockstore = node.Blockstore
 		exch = node.Exchange
 		pinning = node.Pinning
+		prov = nil
 	}
 
-	bserv := blockservice.New(addblockstore, exch) // hash security 001
+	bserv := blockservice.New(addblockstore, exch, blockservice.WithProvider(prov)) // hash security 001
 	dserv := merkledag.NewDAGService(bserv)
 
 	// add a sync call to the DagService
diff --git a/core/corehttp/gateway.go b/core/corehttp/gateway.go
index a2567d8f0fdd..1f0d2fe8fc44 100644
--- a/core/corehttp/gateway.go
+++ b/core/corehttp/gateway.go
@@ -9,8 +9,6 @@ import (
 	"net/http"
 	"time"
 
-	"github.com/ipfs/boxo/blockservice"
-	"github.com/ipfs/boxo/exchange/offline"
 	"github.com/ipfs/boxo/files"
 	"github.com/ipfs/boxo/gateway"
 	"github.com/ipfs/boxo/namesys"
@@ -79,7 +77,7 @@ func VersionOption() ServeOption {
 
 func Libp2pGatewayOption() ServeOption {
 	return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
-		bserv := blockservice.New(n.Blocks.Blockstore(), offline.Exchange(n.Blocks.Blockstore()))
+		bserv := n.OfflineBlocks
 
 		backend, err := gateway.NewBlocksBackend(bserv,
 			// GatewayOverLibp2p only returns things that are in local blockstore
@@ -118,7 +116,7 @@ func newGatewayBackend(n *core.IpfsNode) (gateway.IPFSBackend, error) {
 	pathResolver := n.UnixFSPathResolver
 
 	if cfg.Gateway.NoFetch {
-		bserv = blockservice.New(bserv.Blockstore(), offline.Exchange(bserv.Blockstore()))
+		bserv = n.OfflineBlocks
 
 		cs := cfg.Ipns.ResolveCacheSize
 		if cs == 0 {
diff --git a/core/node/bitswap.go b/core/node/bitswap.go
index 1c4c1df21577..5b6cb2e47d44 100644
--- a/core/node/bitswap.go
+++ b/core/node/bitswap.go
@@ -5,11 +5,11 @@ import (
 	"time"
 
 	"github.com/ipfs/boxo/bitswap"
+	"github.com/ipfs/boxo/bitswap/client"
 	"github.com/ipfs/boxo/bitswap/network"
 	blockstore "github.com/ipfs/boxo/blockstore"
 	exchange "github.com/ipfs/boxo/exchange"
 	"github.com/ipfs/kubo/config"
-	irouting "github.com/ipfs/kubo/routing"
 	"github.com/libp2p/go-libp2p/core/host"
 	"go.uber.org/fx"
 
@@ -31,17 +31,16 @@ type bitswapOptionsOut struct {
 	BitswapOpts []bitswap.Option `group:"bitswap-options,flatten"`
 }
 
-// BitswapOptions creates configuration options for Bitswap from the config file
-// and whether to provide data.
-func BitswapOptions(cfg *config.Config, provide bool) interface{} {
-	return func() bitswapOptionsOut {
+// BitswapOptions creates configuration options for Bitswap from the config file.
+func BitswapOptions(cfg *config.Config) fx.Option {
+	return fx.Provide(func(routing client.ContentSearcher) bitswapOptionsOut {
 		var internalBsCfg config.InternalBitswap
 		if cfg.Internal.Bitswap != nil {
 			internalBsCfg = *cfg.Internal.Bitswap
 		}
 
 		opts := []bitswap.Option{
-			bitswap.ProvideEnabled(provide),
+			bitswap.WithContentSearch(routing),
 			bitswap.ProviderSearchDelay(internalBsCfg.ProviderSearchDelay.WithDefault(DefaultProviderSearchDelay)), // See https://github.com/ipfs/go-ipfs/issues/8807 for rationale
 			bitswap.EngineBlockstoreWorkerCount(int(internalBsCfg.EngineBlockstoreWorkerCount.WithDefault(DefaultEngineBlockstoreWorkerCount))),
 			bitswap.TaskWorkerCount(int(internalBsCfg.TaskWorkerCount.WithDefault(DefaultTaskWorkerCount))),
@@ -50,7 +49,7 @@ func BitswapOptions(cfg *config.Config, provide bool) interface{} {
 		}
 
 		return bitswapOptionsOut{BitswapOpts: opts}
-	}
+	})
 }
 
 type onlineExchangeIn struct {
@@ -58,7 +57,6 @@ type onlineExchangeIn struct {
 
 	Mctx        helpers.MetricsCtx
 	Host        host.Host
-	Rt          irouting.ProvideManyRouter
 	Bs          blockstore.GCBlockstore
 	BitswapOpts []bitswap.Option `group:"bitswap-options"`
 }
@@ -66,9 +64,9 @@ type onlineExchangeIn struct {
 // OnlineExchange creates new LibP2P backed block exchange (BitSwap).
 // Additional options to bitswap.New can be provided via the "bitswap-options"
 // group.
-func OnlineExchange() interface{} {
-	return func(in onlineExchangeIn, lc fx.Lifecycle) exchange.Interface {
-		bitswapNetwork := network.NewFromIpfsHost(in.Host, in.Rt)
+func OnlineExchange() fx.Option {
+	return fx.Provide(func(in onlineExchangeIn, lc fx.Lifecycle) exchange.Interface {
+		bitswapNetwork := network.NewFromIpfsHost(in.Host)
 
 		exch := bitswap.New(helpers.LifecycleCtx(in.Mctx, lc), bitswapNetwork, in.Bs, in.BitswapOpts...)
 		lc.Append(fx.Hook{
@@ -77,5 +75,5 @@ func OnlineExchange() interface{} {
 			},
 		})
 		return exch
-	}
+	})
 }
diff --git a/core/node/core.go b/core/node/core.go
index 9a2035a4c8c7..feeb2280030e 100644
--- a/core/node/core.go
+++ b/core/node/core.go
@@ -7,7 +7,6 @@ import (
 	"github.com/ipfs/boxo/blockservice"
 	blockstore "github.com/ipfs/boxo/blockstore"
 	exchange "github.com/ipfs/boxo/exchange"
-	offline "github.com/ipfs/boxo/exchange/offline"
 	"github.com/ipfs/boxo/fetcher"
 	bsfetcher "github.com/ipfs/boxo/fetcher/impl/blockservice"
 	"github.com/ipfs/boxo/filestore"
@@ -17,6 +16,7 @@ import (
 	pathresolver "github.com/ipfs/boxo/path/resolver"
 	pin "github.com/ipfs/boxo/pinning/pinner"
 	"github.com/ipfs/boxo/pinning/pinner/dspinner"
+	"github.com/ipfs/boxo/provider"
 	"github.com/ipfs/go-cid"
 	"github.com/ipfs/go-datastore"
 	format "github.com/ipfs/go-ipld-format"
@@ -29,8 +29,8 @@ import (
 )
 
 // BlockService creates new blockservice which provides an interface to fetch content-addressable blocks
-func BlockService(lc fx.Lifecycle, bs blockstore.Blockstore, rem exchange.Interface) blockservice.BlockService {
-	bsvc := blockservice.New(bs, rem)
+func BlockService(lc fx.Lifecycle, bs blockstore.Blockstore, rem exchange.Interface, prov provider.Provider) blockservice.BlockService {
+	bsvc := blockservice.New(bs, rem, blockservice.WithProvider(prov))
 
 	lc.Append(fx.Hook{
 		OnStop: func(ctx context.Context) error {
@@ -41,6 +41,32 @@ func BlockService(lc fx.Lifecycle, bs blockstore.Blockstore, rem exchange.Interf
 	return bsvc
 }
 
+type offlineIn struct {
+	fx.In
+
+	Bs   blockstore.Blockstore
+	Prov provider.Provider `optional:"true"`
+}
+
+type offlineOut struct {
+	fx.Out
+
+	Bs blockservice.BlockService `name:"offlineBlockService"`
+}
+
+// OfflineBlockservice is like [BlockService] but it makes an offline version.
+func OfflineBlockservice(lc fx.Lifecycle, in offlineIn) offlineOut {
+	bsvc := blockservice.New(in.Bs, nil, blockservice.WithProvider(in.Prov))
+
+	lc.Append(fx.Hook{
+		OnStop: func(ctx context.Context) error {
+			return bsvc.Close()
+		},
+	})
+
+	return offlineOut{Bs: bsvc}
+}
+
 // Pinning creates new pinner which tells GC which blocks should be kept
 func Pinning(bstore blockstore.Blockstore, ds format.DAGService, repo repo.Repo) (pin.Pinner, error) {
 	rootDS := repo.Datastore()
@@ -82,8 +108,8 @@ func (s *syncDagService) Session(ctx context.Context) format.NodeGetter {
 	return merkledag.NewSession(ctx, s.DAGService)
 }
 
-// FetchersOut allows injection of fetchers.
-type FetchersOut struct {
+// fetchersOut allows injection of fetchers.
+type fetchersOut struct {
 	fx.Out
 	IPLDFetcher          fetcher.Factory `name:"ipldFetcher"`
 	UnixfsFetcher        fetcher.Factory `name:"unixfsFetcher"`
@@ -91,29 +117,25 @@ type FetchersOut struct {
 	OfflineUnixfsFetcher fetcher.Factory `name:"offlineUnixfsFetcher"`
 }
 
-// FetchersIn allows using fetchers for other dependencies.
-type FetchersIn struct {
+type fetcherIn struct {
 	fx.In
-	IPLDFetcher          fetcher.Factory `name:"ipldFetcher"`
-	UnixfsFetcher        fetcher.Factory `name:"unixfsFetcher"`
-	OfflineIPLDFetcher   fetcher.Factory `name:"offlineIpldFetcher"`
-	OfflineUnixfsFetcher fetcher.Factory `name:"offlineUnixfsFetcher"`
+	Online  blockservice.BlockService
+	Offline blockservice.BlockService `name:"offlineBlockservice"`
 }
 
 // FetcherConfig returns a fetcher config that can build new fetcher instances
-func FetcherConfig(bs blockservice.BlockService) FetchersOut {
-	ipldFetcher := bsfetcher.NewFetcherConfig(bs)
+func FetcherConfig(in fetcherIn) fetchersOut {
+	ipldFetcher := bsfetcher.NewFetcherConfig(in.Online)
 	ipldFetcher.PrototypeChooser = dagpb.AddSupportToChooser(bsfetcher.DefaultPrototypeChooser)
 	unixFSFetcher := ipldFetcher.WithReifier(unixfsnode.Reify)
 
 	// Construct offline versions which we can safely use in contexts where
 	// path resolution should not fetch new blocks via exchange.
-	offlineBs := blockservice.New(bs.Blockstore(), offline.Exchange(bs.Blockstore()))
-	offlineIpldFetcher := bsfetcher.NewFetcherConfig(offlineBs)
+	offlineIpldFetcher := bsfetcher.NewFetcherConfig(in.Offline)
 	offlineIpldFetcher.PrototypeChooser = dagpb.AddSupportToChooser(bsfetcher.DefaultPrototypeChooser)
 	offlineUnixFSFetcher := offlineIpldFetcher.WithReifier(unixfsnode.Reify)
 
-	return FetchersOut{
+	return fetchersOut{
 		IPLDFetcher:          ipldFetcher,
 		UnixfsFetcher:        unixFSFetcher,
 		OfflineIPLDFetcher:   offlineIpldFetcher,
@@ -130,8 +152,17 @@ type PathResolversOut struct {
 	OfflineUnixFSPathResolver pathresolver.Resolver `name:"offlineUnixFSPathResolver"`
 }
 
+// PathResolverIn allows using fetchers for other dependencies.
+type PathResolverIn struct {
+	fx.In
+	IPLDFetcher          fetcher.Factory `name:"ipldFetcher"`
+	UnixfsFetcher        fetcher.Factory `name:"unixfsFetcher"`
+	OfflineIPLDFetcher   fetcher.Factory `name:"offlineIpldFetcher"`
+	OfflineUnixfsFetcher fetcher.Factory `name:"offlineUnixfsFetcher"`
+}
+
 // PathResolverConfig creates path resolvers with the given fetchers.
-func PathResolverConfig(fetchers FetchersIn) PathResolversOut {
+func PathResolverConfig(fetchers PathResolverIn) PathResolversOut {
 	return PathResolversOut{
 		IPLDPathResolver:          pathresolver.NewBasicResolver(fetchers.IPLDFetcher),
 		UnixFSPathResolver:        pathresolver.NewBasicResolver(fetchers.UnixfsFetcher),
@@ -145,6 +176,23 @@ func Dag(bs blockservice.BlockService) format.DAGService {
 	return merkledag.NewDAGService(bs)
 }
 
+type offlineDagIn struct {
+	fx.In
+
+	Bs blockservice.BlockService `name:"offlineBlockService"`
+}
+
+type offlineDagOut struct {
+	fx.Out
+
+	DAG format.DAGService `name:"offlineDagService"`
+}
+
+// OfflineDag is like [Dag] but it makes an offline version.
+func OfflineDag(lc fx.Lifecycle, in offlineDagIn) offlineDagOut {
+	return offlineDagOut{DAG: merkledag.NewDAGService(in.Bs)}
+}
+
 // Files loads persisted MFS root
 func Files(mctx helpers.MetricsCtx, lc fx.Lifecycle, repo repo.Repo, dag format.DAGService) (*mfs.Root, error) {
 	dsk := datastore.NewKey("/local/filesroot")
diff --git a/core/node/groups.go b/core/node/groups.go
index e1e2e4b9c988..30b2f6c14ad1 100644
--- a/core/node/groups.go
+++ b/core/node/groups.go
@@ -284,12 +284,9 @@ func Online(bcfg *BuildCfg, cfg *config.Config, userResourceOverrides rcmgr.Part
 		recordLifetime = d
 	}
 
-	/* don't provide from bitswap when the strategic provider service is active */
-	shouldBitswapProvide := !cfg.Experimental.StrategicProviding
-
 	return fx.Options(
-		fx.Provide(BitswapOptions(cfg, shouldBitswapProvide)),
-		fx.Provide(OnlineExchange()),
+		BitswapOptions(cfg),
+		OnlineExchange(),
 		fx.Provide(DNSResolver),
 		fx.Provide(Namesys(ipnsCacheSize)),
 		fx.Provide(Peering),
@@ -325,7 +322,9 @@ func Offline(cfg *config.Config) fx.Option {
 // Core groups basic IPFS services
 var Core = fx.Options(
 	fx.Provide(BlockService),
+	fx.Provide(OfflineBlockservice),
 	fx.Provide(Dag),
+	fx.Provide(OfflineDag),
 	fx.Provide(FetcherConfig),
 	fx.Provide(PathResolverConfig),
 	fx.Provide(Pinning),
diff --git a/docs/examples/kubo-as-a-library/go.mod b/docs/examples/kubo-as-a-library/go.mod
index 2ad0ae26973d..4cbae77849c2 100644
--- a/docs/examples/kubo-as-a-library/go.mod
+++ b/docs/examples/kubo-as-a-library/go.mod
@@ -7,7 +7,7 @@ go 1.20
 replace github.com/ipfs/kubo => ./../../..
 
 require (
-	github.com/ipfs/boxo v0.16.0
+	github.com/ipfs/boxo v0.16.1-0.20231228230304-6d5475fee213
 	github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
 	github.com/libp2p/go-libp2p v0.32.2
 	github.com/multiformats/go-multiaddr v0.12.0
diff --git a/docs/examples/kubo-as-a-library/go.sum b/docs/examples/kubo-as-a-library/go.sum
index d82db17e0d23..93dd5c9dc970 100644
--- a/docs/examples/kubo-as-a-library/go.sum
+++ b/docs/examples/kubo-as-a-library/go.sum
@@ -303,8 +303,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy
 github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI=
 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
-github.com/ipfs/boxo v0.16.0 h1:A9dUmef5a+mEFki6kbyG7el5gl65CiUBzrDeZxzTWKY=
-github.com/ipfs/boxo v0.16.0/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
+github.com/ipfs/boxo v0.16.1-0.20231228230304-6d5475fee213 h1:TnRtSHZQqHcLuRvyRPpB9rbdmuVfRYOENoDS/0P119E=
+github.com/ipfs/boxo v0.16.1-0.20231228230304-6d5475fee213/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
 github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
diff --git a/gc/gc.go b/gc/gc.go
index c85f9d6bf24d..55abdbd27866 100644
--- a/gc/gc.go
+++ b/gc/gc.go
@@ -9,7 +9,6 @@ import (
 
 	bserv "github.com/ipfs/boxo/blockservice"
 	bstore "github.com/ipfs/boxo/blockstore"
-	offline "github.com/ipfs/boxo/exchange/offline"
 	dag "github.com/ipfs/boxo/ipld/merkledag"
 	pin "github.com/ipfs/boxo/pinning/pinner"
 	"github.com/ipfs/boxo/verifcid"
@@ -52,7 +51,9 @@ func GC(ctx context.Context, bs bstore.GCBlockstore, dstor dstore.Datastore, pn
 
 	unlocker := bs.GCLock(ctx)
 
-	bsrv := bserv.New(bs, offline.Exchange(bs))
+	// it is fine to make a custom blockservice here since we are not gonna write new blocks
+	// FIXME: this is hacky, please fix
+	bsrv := bserv.New(bs, nil)
 	ds := dag.NewDAGService(bsrv)
 
 	output := make(chan Result, 128)
diff --git a/go.mod b/go.mod
index 1c1f5e5d4786..3f03fd597daa 100644
--- a/go.mod
+++ b/go.mod
@@ -17,7 +17,7 @@ require (
 	github.com/hashicorp/go-multierror v1.1.1
 	github.com/ipfs-shipyard/nopfs v0.0.12-0.20231027223058-cde3b5ba964c
 	github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c
-	github.com/ipfs/boxo v0.16.0
+	github.com/ipfs/boxo v0.16.1-0.20231228230304-6d5475fee213
 	github.com/ipfs/go-block-format v0.2.0
 	github.com/ipfs/go-cid v0.4.1
 	github.com/ipfs/go-cidutil v0.1.0
diff --git a/go.sum b/go.sum
index 09b15e67f9b2..48162c72cc81 100644
--- a/go.sum
+++ b/go.sum
@@ -337,8 +337,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c h1:7Uy
 github.com/ipfs-shipyard/nopfs/ipfs v0.13.2-0.20231027223058-cde3b5ba964c/go.mod h1:6EekK/jo+TynwSE/ZOiOJd4eEvRXoavEC3vquKtv4yI=
 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
-github.com/ipfs/boxo v0.16.0 h1:A9dUmef5a+mEFki6kbyG7el5gl65CiUBzrDeZxzTWKY=
-github.com/ipfs/boxo v0.16.0/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
+github.com/ipfs/boxo v0.16.1-0.20231228230304-6d5475fee213 h1:TnRtSHZQqHcLuRvyRPpB9rbdmuVfRYOENoDS/0P119E=
+github.com/ipfs/boxo v0.16.1-0.20231228230304-6d5475fee213/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
 github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ=
diff --git a/plugin/plugins/nopfs/nopfs.go b/plugin/plugins/nopfs/nopfs.go
index 64350830f94b..c00319285888 100644
--- a/plugin/plugins/nopfs/nopfs.go
+++ b/plugin/plugins/nopfs/nopfs.go
@@ -59,7 +59,7 @@ func MakeBlocker() (*nopfs.Blocker, error) {
 }
 
 // PathResolvers returns wrapped PathResolvers for Kubo.
-func PathResolvers(fetchers node.FetchersIn, blocker *nopfs.Blocker) node.PathResolversOut {
+func PathResolvers(fetchers node.PathResolverIn, blocker *nopfs.Blocker) node.PathResolversOut {
 	res := node.PathResolverConfig(fetchers)
 	return node.PathResolversOut{
 		IPLDPathResolver:          ipfs.WrapResolver(res.IPLDPathResolver, blocker),
diff --git a/test/dependencies/go.mod b/test/dependencies/go.mod
index b726fb5b00b8..47de6afaeefb 100644
--- a/test/dependencies/go.mod
+++ b/test/dependencies/go.mod
@@ -103,7 +103,7 @@ require (
 	github.com/hexops/gotextdiff v1.0.3 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
 	github.com/ipfs/bbloom v0.0.4 // indirect
-	github.com/ipfs/boxo v0.16.0 // indirect
+	github.com/ipfs/boxo v0.16.1-0.20231228230304-6d5475fee213 // indirect
 	github.com/ipfs/go-block-format v0.2.0 // indirect
 	github.com/ipfs/go-cid v0.4.1 // indirect
 	github.com/ipfs/go-datastore v0.6.0 // indirect
diff --git a/test/dependencies/go.sum b/test/dependencies/go.sum
index 047bf5f5ae76..8f9a02bd54d9 100644
--- a/test/dependencies/go.sum
+++ b/test/dependencies/go.sum
@@ -342,8 +342,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
-github.com/ipfs/boxo v0.16.0 h1:A9dUmef5a+mEFki6kbyG7el5gl65CiUBzrDeZxzTWKY=
-github.com/ipfs/boxo v0.16.0/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
+github.com/ipfs/boxo v0.16.1-0.20231228230304-6d5475fee213 h1:TnRtSHZQqHcLuRvyRPpB9rbdmuVfRYOENoDS/0P119E=
+github.com/ipfs/boxo v0.16.1-0.20231228230304-6d5475fee213/go.mod h1:jAgpNQn7T7BnibUeReXcKU9Ha1xmYNyOlwVEl193ow0=
 github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
 github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM=
 github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s=