diff --git a/src/pygobbler/__init__.py b/src/pygobbler/__init__.py
index 86d6a23..836bb56 100644
--- a/src/pygobbler/__init__.py
+++ b/src/pygobbler/__init__.py
@@ -43,3 +43,4 @@
 from .reject_probation import reject_probation
 from .set_permissions import set_permissions
 from .unpack_path import unpack_path
+from .reroute_links import reroute_links
diff --git a/src/pygobbler/remove_asset.py b/src/pygobbler/remove_asset.py
index 4930585..117f8e8 100644
--- a/src/pygobbler/remove_asset.py
+++ b/src/pygobbler/remove_asset.py
@@ -4,6 +4,8 @@
 def remove_asset(project: str, asset: str, staging: str, url: str, force: bool = False):
     """
     Remove an asset of a project from the registry.
+    This should only be performed by Gobbler instance administrators.
+    Consider running :py:func:`~pygobbler.reroute_links.reroute_links` beforehand to avoid dangling references to files in this asset.
 
     Args:
         project:
diff --git a/src/pygobbler/remove_project.py b/src/pygobbler/remove_project.py
index ab6d484..9383ccb 100644
--- a/src/pygobbler/remove_project.py
+++ b/src/pygobbler/remove_project.py
@@ -4,6 +4,8 @@
 def remove_project(project: str, staging: str, url: str):
     """
     Remove a project from the registry.
+    This should only be performed by Gobbler instance administrators.
+    Consider running :py:func:`~pygobbler.reroute_links.reroute_links` beforehand to avoid dangling references to files in this project.
 
     Args:
         project:
diff --git a/src/pygobbler/remove_version.py b/src/pygobbler/remove_version.py
index 4735999..58b1dff 100644
--- a/src/pygobbler/remove_version.py
+++ b/src/pygobbler/remove_version.py
@@ -4,6 +4,8 @@
 def remove_version(project: str, asset: str, version: str, staging: str, url: str, force: bool = False):
     """
     Remove a version of a project asset from the registry.
+    This should only be performed by Gobbler instance administrators.
+    Consider running :py:func:`~pygobbler.reroute_links.reroute_links` beforehand to avoid dangling references to files in this version.
 
     Args:
         project:
diff --git a/src/pygobbler/reroute_links.py b/src/pygobbler/reroute_links.py
new file mode 100644
index 0000000..2403233
--- /dev/null
+++ b/src/pygobbler/reroute_links.py
@@ -0,0 +1,47 @@
+from typing import List
+from ._utils import dump_request
+
+
+def reroute_links(to_delete: List, staging: str, url: str, dry_run: bool = False) -> List:
+    """Reroute symbolic links to files in directories that are to be deleted, e.g., by :py:func:`~pygobbler.remove_project.remove_project`.
+    This preserves the validity of links within the Gobbler registry.
+
+    Note that rerouting does not actually delete the directories specified in ``to_delete``.
+    Deletion requires separate invocations of :py:func:`~pygobbler.remove_project.remove_project` and friends - preferably after the user has verified that rerouting was successful!
+
+    Rerouting is not necessary if ``to_delete`` consists only of probational versions, or projects/assets containing only probational versions.
+    The Gobbler should never create links to files in probational version directories.
+
+    Args:
+        to_delete:
+            List of projects, assets or versions to be deleted.
+            Each entry should be a dicionary containing at least the ``project`` name.
+            When deleting an asset, the inner list should contain an additional ``asset`` name.
+            When deleting a version, the inner list should contain additional ``asset`` and ``version`` names.
+            Different inner lists may specify different projects, assets or versions.
+
+        staging:
+            Path to the staging directory.
+
+        url:
+            URL for the Gobbler REST API.
+
+        dry_run:
+            Whether to perform a dry run of the rerouting.
+
+    Returns:
+        List of dictionaries.
+        Each dictionary represents a rerouting action and contains the following fields.
+
+        - ``path``, string containing the path to a symbolic link in the registry that was changed by rerouting.
+        - ``copy``, boolean indicating whether the link at ``path`` was replaced by a copy of its target file.
+          If ``False``, the link was merely updated to refer to a new target file.
+        - ``source``, the path to the target file that caused rerouting of ``path``.
+          Specifically, this is a file in one of the to-be-deleted directories specified in ``to_delete``.
+          If ``copy = TRUE``, this is the original linked-to file that was copied to ``path``.
+
+        If ``dry_run = False``, the registry is modified as described by the rerouting actions.
+        Otherwise, no modifications are performed to the registry.
+    """
+    out = dump_request(staging, url, "reroute_links", { "to_delete": to_delete, "dry_run": dry_run })
+    return out["changes"]
diff --git a/src/pygobbler/start_gobbler.py b/src/pygobbler/start_gobbler.py
index efaefc1..7330238 100644
--- a/src/pygobbler/start_gobbler.py
+++ b/src/pygobbler/start_gobbler.py
@@ -14,7 +14,7 @@ def start_gobbler(
     registry: Optional[str] = None,
     port: Optional[int] = None,
     wait: float = 1,
-    version: str = "0.3.9",
+    version: str = "0.3.10",
     overwrite: bool = False) -> Tuple[bool, str, str, str]:
     """
     Start a test Gobbler service.
diff --git a/tests/test_reroute_links.py b/tests/test_reroute_links.py
new file mode 100644
index 0000000..c385868
--- /dev/null
+++ b/tests/test_reroute_links.py
@@ -0,0 +1,32 @@
+import pygobbler as pyg
+import os
+
+
+def test_reroute_links():
+    _, staging, registry, url = pyg.start_gobbler()
+
+    pyg.remove_project("test-reroute", staging=staging, url=url)
+    pyg.create_project("test-reroute", staging=staging, url=url)
+
+    src = pyg.allocate_upload_directory(staging)
+    with open(os.path.join(src, "foo"), "w") as handle:
+        handle.write("BAR")
+
+    pyg.upload_directory("test-reroute", "simple", "v1", src, staging=staging, url=url)
+    pyg.upload_directory("test-reroute", "simple", "v2", src, staging=staging, url=url)
+    pyg.upload_directory("test-reroute", "simple", "v3", src, staging=staging, url=url)
+
+    actions = pyg.reroute_links([{"project":"test-reroute", "asset":"simple", "version":"v1"}], staging=staging, url=url, dry_run=True)
+    print(actions)
+    assert all([x["source"] == "test-reroute/simple/v1/foo" for x in actions])
+    all_paths = [x["path"] for x in actions]
+    assert "test-reroute/simple/v2/foo" in all_paths
+    assert "test-reroute/simple/v3/foo" in all_paths
+    all_copy = [x["copy"] for x in actions]
+    assert all_copy[all_paths.index("test-reroute/simple/v2/foo")]
+    assert not all_copy[all_paths.index("test-reroute/simple/v3/foo")]
+    assert os.path.islink(os.path.join(registry, "test-reroute/simple/v2/foo")) 
+
+    actions2 = pyg.reroute_links([{"project":"test-reroute", "asset":"simple", "version":"v1"}], staging=staging, url=url)
+    assert actions == actions2
+    assert not os.path.islink(os.path.join(registry, "test-reroute/simple/v2/foo"))