diff --git a/src/libfetchers/registry.cc b/src/libfetchers/registry.cc
index 74376adc0526cd1c2f2de022462691c870d9b858..c2dfa9dc6e0dcdcbfa3f9893bf1f30620b6e3a0f 100644
--- a/src/libfetchers/registry.cc
+++ b/src/libfetchers/registry.cc
@@ -124,6 +124,13 @@ std::shared_ptr<Registry> getUserRegistry()
     return userRegistry;
 }
 
+std::shared_ptr<Registry> getCustomRegistry(Path p)
+{
+    static auto customRegistry =
+        Registry::read(p, Registry::Custom);
+    return customRegistry;
+}
+
 static std::shared_ptr<Registry> flagRegistry =
     std::make_shared<Registry>(Registry::Flag);
 
diff --git a/src/libfetchers/registry.hh b/src/libfetchers/registry.hh
index 1077af0207a7ff6b00cf1e4dcc223ec18c65ae43..cde22dff68b8fca4b38d366fac7dff98fd164cf9 100644
--- a/src/libfetchers/registry.hh
+++ b/src/libfetchers/registry.hh
@@ -14,6 +14,7 @@ struct Registry
         User = 1,
         System = 2,
         Global = 3,
+        Custom = 4,
     };
 
     RegistryType type;
@@ -48,6 +49,8 @@ typedef std::vector<std::shared_ptr<Registry>> Registries;
 
 std::shared_ptr<Registry> getUserRegistry();
 
+std::shared_ptr<Registry> getCustomRegistry(Path p);
+
 Path getUserRegistryPath();
 
 Registries getRegistries(ref<Store> store);
diff --git a/src/nix/registry.cc b/src/nix/registry.cc
index 4400cc8dc9dea6853e602d639c53f81bd0d7c332..ec80dc0bc57af68fb24650474c4e22aed68230b0 100644
--- a/src/nix/registry.cc
+++ b/src/nix/registry.cc
@@ -152,9 +152,11 @@ struct CmdRegistryPin : RegistryCommand, EvalCommand
 {
     std::string url;
 
+    std::string locked;
+
     std::string description() override
     {
-        return "pin a flake to its current version in user flake registry";
+        return "pin a flake to its current version in user flake registry or to the current version of a flake URI";
     }
 
     std::string doc() override
@@ -167,14 +169,27 @@ struct CmdRegistryPin : RegistryCommand, EvalCommand
     CmdRegistryPin()
     {
         expectArg("url", &url);
+
+        expectArgs({
+            .label = "locked",
+            .optional = true,
+            .handler = {&locked},
+            .completer = {[&](size_t, std::string_view prefix) {
+                completeFlakeRef(getStore(), prefix);
+            }}
+        });
     }
 
     void run(nix::ref<nix::Store> store) override
     {
+        if (locked.empty()) {
+            locked = url;
+        }
         auto registry = getRegistry();
         auto ref = parseFlakeRef(url);
+        auto locked_ref = parseFlakeRef(locked);
         registry->remove(ref.input);
-        auto [tree, resolved] = ref.resolve(store).input.fetch(store);
+        auto [tree, resolved] = locked_ref.resolve(store).input.fetch(store);
         fetchers::Attrs extraAttrs;
         if (ref.subdir != "") extraAttrs["dir"] = ref.subdir;
         registry->add(ref.input, resolved, extraAttrs);