diff --git a/doc/pipeline_simple_intro.rst b/doc/pipeline_simple_intro.rst
index 1a2ff4a5402d0b91cc0426076b31cb6d5b9232e7..62df9e4574a2538f7f06c9814ec9ba3c49046038 100644
--- a/doc/pipeline_simple_intro.rst
+++ b/doc/pipeline_simple_intro.rst
@@ -290,13 +290,13 @@ The command above is equivalent to the following command::
     bob.bio.face.config.baseline.iresnet100
 
 This information can be obtained by either inspecting the ``setup.py`` of the
-relevant pacakge or using the following code snippet:
+relevant package or using the following code snippet:
 
 .. code-block:: python
 
-    import pkg_resources
+    import importlib.metadata
 
-    for entry_point in pkg_resources.iter_entry_points("bob.bio.config"):
+    for entry_point in importlib.metadata.entry_points(group="bob.bio.config"):
         if entry_point.name not in ("atnt", "iresnet100"):
             continue
         print(entry_point)
diff --git a/src/bob/bio/base/script/bio.py b/src/bob/bio/base/script/bio.py
index 8ff90cd48e62e0be08e72baf783c190bb9108106..db470867b56033c44dded94778aba871f741e0ea 100644
--- a/src/bob/bio/base/script/bio.py
+++ b/src/bob/bio/base/script/bio.py
@@ -1,13 +1,14 @@
 """The main entry for bob.bio (click-based) scripts.
 """
+import importlib.metadata
+
 import click
-import pkg_resources
 
 from clapper.click import AliasedGroup
 from click_plugins import with_plugins
 
 
-@with_plugins(pkg_resources.iter_entry_points("bob.bio.cli"))
+@with_plugins(importlib.metadata.entry_points(group="bob.bio.cli"))
 @click.group(cls=AliasedGroup)
 def bio():
     """Biometric recognition commands."""
diff --git a/src/bob/bio/base/script/pipeline.py b/src/bob/bio/base/script/pipeline.py
index dabadd115b5c98aa0958c823993ae04d635a1659..0022ca9350b1e07d32ca43216cc56d9cbca6e5aa 100644
--- a/src/bob/bio/base/script/pipeline.py
+++ b/src/bob/bio/base/script/pipeline.py
@@ -1,11 +1,12 @@
+import importlib.metadata
+
 import click
-import pkg_resources
 
 from clapper.click import AliasedGroup
 from click_plugins import with_plugins
 
 
-@with_plugins(pkg_resources.iter_entry_points("bob.bio.pipeline.cli"))
+@with_plugins(importlib.metadata.entry_points(group="bob.bio.pipeline.cli"))
 @click.group(cls=AliasedGroup)
 def pipeline():
     """Available pipelines"""
diff --git a/src/bob/bio/base/script/vulnerability.py b/src/bob/bio/base/script/vulnerability.py
index 6bdbd2f8f7135541668dee31c1c0c81b18aedfd2..23d43e2149f17865f3dd9983dc891c24292ad56a 100644
--- a/src/bob/bio/base/script/vulnerability.py
+++ b/src/bob/bio/base/script/vulnerability.py
@@ -1,13 +1,14 @@
 """The main entry for bob.vuln
 """
+import importlib.metadata
+
 import click
-import pkg_resources
 
 from clapper.click import AliasedGroup
 from click_plugins import with_plugins
 
 
-@with_plugins(pkg_resources.iter_entry_points("bob.vuln.cli"))
+@with_plugins(importlib.metadata.entry_points(group="bob.vuln.cli"))
 @click.group(cls=AliasedGroup)
 def vulnerability():
     """Vulnerability analysis related commands."""
diff --git a/src/bob/bio/base/utils/resources.py b/src/bob/bio/base/utils/resources.py
index 6393d4a440c5ccecb70c38e772b074e29ff44d6d..378c684a978a63a29d98bbe88388030a872ed28c 100644
--- a/src/bob/bio/base/utils/resources.py
+++ b/src/bob/bio/base/utils/resources.py
@@ -5,11 +5,13 @@
 
 from __future__ import print_function
 
+import importlib.metadata
+import importlib.resources
 import logging
-import os
+
+from pathlib import Path
 
 import clapper.config
-import pkg_resources
 
 logger = logging.getLogger("bob.bio.base")
 
@@ -95,12 +97,18 @@ def read_config_file(filenames, keyword=None):
     return getattr(config, keyword)
 
 
-def _get_entry_points(keyword, strip=[], package_prefix="bob.bio."):
+def _get_entry_points(
+    keyword: str,
+    strip: list[str] | None = None,
+    package_prefix: str = "bob.bio.",
+) -> list[importlib.metadata.EntryPoint]:
     """Returns the list of entry points for registered resources with the given keyword."""
+    if strip is None:
+        strip = []
     return [
         entry_point
-        for entry_point in pkg_resources.iter_entry_points(
-            package_prefix + keyword
+        for entry_point in importlib.metadata.entry_points().select(
+            group=package_prefix + keyword
         )
         if not entry_point.name.startswith(tuple(strip))
     ]
@@ -145,7 +153,7 @@ def load_resource(
     """
 
     # first, look if the resource is a file name
-    if os.path.isfile(resource):
+    if Path(resource).is_file():
         return read_config_file([resource], keyword)
 
     if keyword not in valid_keywords:
@@ -174,14 +182,14 @@ def load_resource(
             index = -1
             if preferred_package is not None:
                 for i, p in enumerate(entry_points):
-                    if p.dist.project_name == preferred_package:
+                    if p.dist.metadata["name"] == preferred_package:
                         index = i
                         break
 
             if index == -1:
                 # by default, use the first one that is not from bob.bio
                 for i, p in enumerate(entry_points):
-                    if not p.dist.project_name.startswith(package_prefix):
+                    if not p.dist.metadata["name"].startswith(package_prefix):
                         index = i
                         break
 
@@ -189,15 +197,15 @@ def load_resource(
                 logger.debug(
                     "RESOURCES: Using the resource '%s' from '%s', and ignoring the one from '%s'",
                     resource,
-                    entry_points[index].module_name,
-                    entry_points[1 - index].module_name,
+                    entry_points[index].module,
+                    entry_points[1 - index].module,
                 )
                 return entry_points[index].load()
             else:
                 logger.warn(
                     "Under the desired name '%s', there are multiple entry points defined, we return the first one: %s",
                     resource,
-                    [entry_point.module_name for entry_point in entry_points],
+                    [entry_point.module for entry_point in entry_points],
                 )
                 return entry_points[0].load()
 
@@ -241,28 +249,37 @@ def extensions(keywords=valid_keywords, package_prefix="bob.bio."):
         )
     ]
     return sorted(
-        list(set(entry_point.dist.project_name for entry_point in entry_points))
+        list(
+            set(
+                entry_point.dist.metadata["name"]
+                for entry_point in entry_points
+            )
+        )
     )
 
 
 def resource_keys(
-    keyword, exclude_packages=[], package_prefix="bob.bio.", strip=["dummy"]
+    keyword, exclude_packages=None, package_prefix="bob.bio.", strip=None
 ):
     """Reads and returns all resources that are registered with the given keyword.
     Entry points from the given ``exclude_packages`` are ignored."""
+    if exclude_packages is None:
+        exclude_packages = []
+    if strip is None:
+        strip = ["dummy"]
     ret_list = [
         entry_point.name
         for entry_point in _get_entry_points(
             keyword, strip=strip, package_prefix=package_prefix
         )
-        if entry_point.dist.project_name not in exclude_packages
+        if entry_point.dist.metadata["name"] not in exclude_packages
     ]
     return sorted(ret_list)
 
 
 def list_resources(
     keyword,
-    strip=["dummy"],
+    strip=None,
     package_prefix="bob.bio.",
     verbose=False,
     packages=None,
@@ -273,6 +290,8 @@ def list_resources(
             "The given keyword '%s' is not valid. Please use one of %s!"
             % (str(keyword), str(valid_keywords))
         )
+    if strip is None:
+        strip = ["dummy"]
 
     entry_points = _get_entry_points(
         keyword, strip, package_prefix=package_prefix
@@ -289,29 +308,30 @@ def list_resources(
         entry_points = [
             entry_point
             for entry_point in entry_points
-            if entry_point.dist.project_name in packages
+            if entry_point.dist.metadata["name"] in packages
         ]
 
     for entry_point in sorted(
-        entry_points, key=lambda p: (p.dist.project_name, p.name)
+        entry_points, key=lambda p: (p.dist.metadata["name"], p.name)
     ):
-        if last_dist != str(entry_point.dist):
-            retval += "\n- %s @ %s: \n" % (
-                str(entry_point.dist),
-                str(entry_point.dist.location),
+        if last_dist != f"{entry_point.dist.name} {entry_point.dist.version}":
+            retval += "\n- %s %s @ %s: \n" % (
+                entry_point.dist.name,
+                entry_point.dist.version,
+                str(entry_point.dist.locate_file("")),
             )
-            last_dist = str(entry_point.dist)
+            last_dist = f"{entry_point.dist.name} {entry_point.dist.version}"
 
-        if len(entry_point.attrs):
+        if entry_point.attr is not None:
             retval += "  + %s --> %s: %s\n" % (
                 entry_point.name + " " * (length - len(entry_point.name)),
-                entry_point.module_name,
-                entry_point.attrs[0],
+                entry_point.module,
+                entry_point.attr,
             )
         else:
             retval += "  + %s --> %s\n" % (
                 entry_point.name + " " * (length - len(entry_point.name)),
-                entry_point.module_name,
+                entry_point.module,
             )
         if verbose:
             retval += "    ==> " + str(entry_point.load()) + "\n\n"
@@ -320,9 +340,11 @@ def list_resources(
 
 
 def database_directories(
-    strip=["dummy"], replacements=None, package_prefix="bob.bio."
+    strip=None, replacements=None, package_prefix="bob.bio."
 ):
     """Returns a dictionary of original directories for all registered databases."""
+    if strip is None:
+        strip = ["dummy"]
     entry_points = _get_entry_points(
         "database", strip, package_prefix=package_prefix
     )
@@ -364,11 +386,13 @@ def get_resource_filename(resource_name, group):
     """
 
     # Check if it's already a path
-    if os.path.exists(resource_name):
+    if Path(resource_name).exists():
         return resource_name
 
     # If it's a resource get the path of this resource
-    resources = [r for r in pkg_resources.iter_entry_points(group)]
+    resources = [
+        r for r in importlib.metadata.entry_points().select(group=group)
+    ]
 
     # if resource_name not in [r.name for r in resources]:
     #    raise ValueError(f"Resource not found: `{resource_name}`")
@@ -382,9 +406,9 @@ def get_resource_filename(resource_name, group):
 
     # TODO: This get the root path only
     #        I don't know how to get the filename
-    return (
-        pkg_resources.resource_filename(
-            resource.module_name, resource.module_name.split(".")[-1]
+    containing, _dot, resource_filename = resource.module.rpartition(".")
+    return str(
+        importlib.resources.files(containing).joinpath(
+            resource_filename + ".py"
         )
-        + ".py"
     )