diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index 34f844a180bf546c5b3ac0abb20c44b62ec53435..ebc0bd6a4e493827939e25df51c7985d021647ce 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -11,6 +11,7 @@
 #include "nar-accessor.hh"
 #include "json.hh"
 #include "thread-pool.hh"
+#include "callback.hh"
 
 #include <chrono>
 #include <future>
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 6e55f83d5fc8bf72542b522a92a8b081e0ecf485..0b51d90eae3c0c4444277f84c22aa8c8f459ada2 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -17,6 +17,7 @@
 #include "daemon.hh"
 #include "worker-protocol.hh"
 #include "topo-sort.hh"
+#include "callback.hh"
 
 #include <algorithm>
 #include <iostream>
diff --git a/src/libstore/dummy-store.cc b/src/libstore/dummy-store.cc
index 128832e605bfd2b75962a36db385b13f83b6498b..49641c2acc04868caf173b5ab04c56e81b24d5af 100644
--- a/src/libstore/dummy-store.cc
+++ b/src/libstore/dummy-store.cc
@@ -1,4 +1,5 @@
 #include "store-api.hh"
+#include "callback.hh"
 
 namespace nix {
 
diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc
index 4149f81550d6e2f996fafa05bb490e444e8fd880..6241b5e005b573ceed1233149ca4b7536be7ee10 100644
--- a/src/libstore/filetransfer.cc
+++ b/src/libstore/filetransfer.cc
@@ -5,6 +5,7 @@
 #include "s3.hh"
 #include "compression.hh"
 #include "finally.hh"
+#include "callback.hh"
 
 #ifdef ENABLE_S3
 #include <aws/core/client/ClientConfiguration.h>
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index f4ab15a10983d5e372a6e817234b858622213b26..86be7c006cef8cc97446759331eb5a3389fe14fa 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -2,6 +2,7 @@
 #include "filetransfer.hh"
 #include "globals.hh"
 #include "nar-info-disk-cache.hh"
+#include "callback.hh"
 
 namespace nix {
 
diff --git a/src/libstore/legacy-ssh-store.cc b/src/libstore/legacy-ssh-store.cc
index e9478c1d50e2a4295c2ca8aeeefc02190f848c89..5af75669afc3bd492524b579173f13fefe6521f2 100644
--- a/src/libstore/legacy-ssh-store.cc
+++ b/src/libstore/legacy-ssh-store.cc
@@ -6,6 +6,7 @@
 #include "worker-protocol.hh"
 #include "ssh.hh"
 #include "derivations.hh"
+#include "callback.hh"
 
 namespace nix {
 
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index c618203f07ed263306f2ae63e2599cd75d1d63ca..94ff34cb8e7b81d723c1d97e06f9e5dc59f2bb1b 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -6,6 +6,7 @@
 #include "derivations.hh"
 #include "nar-info.hh"
 #include "references.hh"
+#include "callback.hh"
 
 #include <iostream>
 #include <algorithm>
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc
index da39816962163c6ac406e02a459cfaf9eb6a3cdc..ad4dccef995e25cefce4a79e37e04d8b2e296943 100644
--- a/src/libstore/misc.cc
+++ b/src/libstore/misc.cc
@@ -5,7 +5,7 @@
 #include "store-api.hh"
 #include "thread-pool.hh"
 #include "topo-sort.hh"
-
+#include "callback.hh"
 
 namespace nix {
 
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index e92b94975de3d304c1509b41c0dbca2a30b6d93c..27535f1d04a403478e22cb34f49448e749b7f80d 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -10,6 +10,7 @@
 #include "pool.hh"
 #include "finally.hh"
 #include "logging.hh"
+#include "callback.hh"
 
 #include <sys/types.h>
 #include <sys/stat.h>
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 2d5077ed033929a769e906e713e1804a6367ea43..1bbc74db80d91c0e420fff90e5d71385f03ce246 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -8,9 +8,7 @@
 #include "json.hh"
 #include "url.hh"
 #include "archive.hh"
-
-#include <future>
-
+#include "callback.hh"
 
 namespace nix {
 
diff --git a/src/libutil/callback.hh b/src/libutil/callback.hh
new file mode 100644
index 0000000000000000000000000000000000000000..ef31794bee30dd2deb9789436bef529cb38c4a90
--- /dev/null
+++ b/src/libutil/callback.hh
@@ -0,0 +1,46 @@
+#pragma once
+
+#include <future>
+#include <functional>
+
+namespace nix {
+
+/* A callback is a wrapper around a lambda that accepts a valid of
+   type T or an exception. (We abuse std::future<T> to pass the value or
+   exception.) */
+template<typename T>
+class Callback
+{
+    std::function<void(std::future<T>)> fun;
+    std::atomic_flag done = ATOMIC_FLAG_INIT;
+
+public:
+
+    Callback(std::function<void(std::future<T>)> fun) : fun(fun) { }
+
+    Callback(Callback && callback) : fun(std::move(callback.fun))
+    {
+        auto prev = callback.done.test_and_set();
+        if (prev) done.test_and_set();
+    }
+
+    void operator()(T && t) noexcept
+    {
+        auto prev = done.test_and_set();
+        assert(!prev);
+        std::promise<T> promise;
+        promise.set_value(std::move(t));
+        fun(promise.get_future());
+    }
+
+    void rethrow(const std::exception_ptr & exc = std::current_exception()) noexcept
+    {
+        auto prev = done.test_and_set();
+        assert(!prev);
+        std::promise<T> promise;
+        promise.set_exception(exc);
+        fun(promise.get_future());
+    }
+};
+
+}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 082e263757971fd77d8ada38b5a0c92a8cc962ed..91e0a15436f38b98dff3a259ce25c065a262e498 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -17,7 +17,6 @@
 #include <map>
 #include <sstream>
 #include <optional>
-#include <future>
 #include <iterator>
 
 #ifndef HAVE_STRUCT_DIRENT_D_TYPE
@@ -480,43 +479,8 @@ std::optional<typename T::mapped_type> get(const T & map, const typename T::key_
 }
 
 
-/* A callback is a wrapper around a lambda that accepts a valid of
-   type T or an exception. (We abuse std::future<T> to pass the value or
-   exception.) */
 template<typename T>
-class Callback
-{
-    std::function<void(std::future<T>)> fun;
-    std::atomic_flag done = ATOMIC_FLAG_INIT;
-
-public:
-
-    Callback(std::function<void(std::future<T>)> fun) : fun(fun) { }
-
-    Callback(Callback && callback) : fun(std::move(callback.fun))
-    {
-        auto prev = callback.done.test_and_set();
-        if (prev) done.test_and_set();
-    }
-
-    void operator()(T && t) noexcept
-    {
-        auto prev = done.test_and_set();
-        assert(!prev);
-        std::promise<T> promise;
-        promise.set_value(std::move(t));
-        fun(promise.get_future());
-    }
-
-    void rethrow(const std::exception_ptr & exc = std::current_exception()) noexcept
-    {
-        auto prev = done.test_and_set();
-        assert(!prev);
-        std::promise<T> promise;
-        promise.set_exception(exc);
-        fun(promise.get_future());
-    }
-};
+class Callback;
 
 
 /* Start a thread that handles various signals. Also block those signals