diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 94d6bf5620c0ddbb6ffbc1f2de0136394a94f773..e42d7d3e246980d0c61a3c5117dd4f0b7ae1a659 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -6,7 +6,7 @@
 # See https://pre-commit.com/hooks.html for more hooks
 repos:
   - repo: https://github.com/psf/black
-    rev: 23.11.0
+    rev: 24.3.0
     hooks:
       - id: black
   - repo: https://github.com/pycqa/docformatter
@@ -14,15 +14,15 @@ repos:
     hooks:
       - id: docformatter
   - repo: https://github.com/pycqa/isort
-    rev: 5.12.0
+    rev: 5.13.2
     hooks:
       - id: isort
   - repo: https://github.com/pycqa/flake8
-    rev: 6.1.0
+    rev: 7.0.0
     hooks:
       - id: flake8
   - repo: https://github.com/pre-commit/mirrors-mypy
-    rev: v1.7.1
+    rev: v1.9.0
     hooks:
     - id: mypy
       args: [
@@ -33,10 +33,10 @@ repos:
       ]
       exclude: '^.*/data/second_config\.py$'
   - repo: https://github.com/asottile/pyupgrade
-    rev: v3.15.0
+    rev: v3.15.1
     hooks:
     - id: pyupgrade
-      args: [--py38-plus]
+      args: [--py310-plus]
   - repo: https://github.com/pre-commit/pre-commit-hooks
     rev: v4.5.0
     hooks:
@@ -51,6 +51,6 @@ repos:
       - id: end-of-file-fixer
       - id: debug-statements
   - repo: https://github.com/fsfe/reuse-tool
-    rev: v2.1.0
+    rev: v3.0.1
     hooks:
       - id: reuse
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index 175644b2b947065db5e4b4a1be21b86638128bd7..0000000000000000000000000000000000000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright © 2022 Idiap Research Institute <contact@idiap.ch>
-#
-# SPDX-License-Identifier: BSD-3-Clause
-
-include LICENSES/*.txt
-recursive-include doc *.rst *.ico *.png *.json *.txt
-recursive-include tests *.py
diff --git a/conda/meta.yaml b/conda/meta.yaml
index fe2828f3f85e7e086d173f3c4e0fa7121d08a9fd..72c3388ddc4bcd1538ecf672e0d03f2a4e82d3bb 100644
--- a/conda/meta.yaml
+++ b/conda/meta.yaml
@@ -6,7 +6,7 @@
 
 package:
   name: {{ data['project']['name'] }}
-  version: {{ data['project']['version'] }}
+  version: {{ environ.get('PACKAGE_VERSION', environ.get('GIT_DESCRIBE_TAG')) }}
 
 source:
   path: ..
@@ -23,6 +23,8 @@ requirements:
   host:
     - python >=3.10
     - pip
+    - hatchling
+    - versioningit
   run:
     - python >=3.10
     - pip
@@ -42,7 +44,6 @@ requirements:
     - python-gitlab
     - python-dateutil
     - pytz
-    - setuptools
     - xdg
 
 test:
diff --git a/pyproject.toml b/pyproject.toml
index 36ed5daa5932413f0f3646d3ce49400e0a81a1e2..cf37fee78ed47ce0a485de6cea1a20ddbda8c6df 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -3,41 +3,64 @@
 # SPDX-License-Identifier: BSD-3-Clause
 
 [build-system]
-    requires = ["setuptools>=61.0.0", "wheel"]
-    build-backend = "setuptools.build_meta"
+requires = ["hatchling", "versioningit"]
+build-backend = "hatchling.build"
 
 [project]
 name = "idiap-devtools"
-version = "1.0.1b0"
+dynamic = ["version"]
 requires-python = ">=3.10"
 description = "This package contains a *pot-pourri* of various tools required to develop python packages at Idiap's GitLab infrastructure"
 readme = "README.md"
-license = {text = "BSD 3-Clause License"}
-authors = [
-  {name = "Andre Anjos", email = "andre.anjos@idiap.ch"},
-]
+license = { text = "BSD 3-Clause License" }
+authors = [{ name = "Andre Anjos", email = "andre.anjos@idiap.ch" }]
 classifiers = [
-    "Development Status :: 4 - Beta",
-    "Intended Audience :: Developers",
-    "License :: OSI Approved :: BSD License",
-    "Natural Language :: English",
-    "Programming Language :: Python :: 3",
-    "Topic :: Software Development :: Libraries :: Python Modules",
+  "Development Status :: 4 - Beta",
+  "Intended Audience :: Developers",
+  "License :: OSI Approved :: BSD License",
+  "Natural Language :: English",
+  "Programming Language :: Python :: 3",
+  "Topic :: Software Development :: Libraries :: Python Modules",
 ]
 dependencies = [
-    "click>=8",
-    "cookiecutter",
-    "gitpython",
-    "packaging",
-    "python-dateutil",
-    "python-gitlab",
-    "pytz",
-    "pyyaml",
-    "setuptools",
-    "tomli",
-    "tomlkit",
-    "xdg",
-    ]
+  "click>=8",
+  "cookiecutter",
+  "gitpython",
+  "packaging",
+  "python-dateutil",
+  "python-gitlab",
+  "pytz",
+  "pyyaml",
+  "tomli",
+  "tomlkit",
+  "xdg",
+]
+
+[tool.hatch.version]
+source = "versioningit"
+
+[tool.versioningit.next-version]
+method = "smallest"
+
+[tool.versioningit.format]
+# Example formatted version: 1.2.4.dev42+ge174a1f
+distance = "{next_version}.dev{distance}+{vcs}{rev}"
+# Example formatted version: 1.2.4.dev42+ge174a1f.d20230922
+distance-dirty = "{next_version}.dev{distance}+{vcs}{rev}.d{build_date:%Y%m%d}"
+
+[tool.hatch.build.targets.sdist]
+include = [
+  "src/**/*.py",
+  "tests/**/*.py",
+  "doc/**/*.rst",
+  "doc/**/*.py",
+  "doc/*.json",
+  "doc/*.txt",
+  "LICENSES/*.txt",
+]
+
+[tool.hatch.build.targets.wheel]
+packages = ["src/idiap_devtools"]
 
 [project.urls]
 documentation = "https://idiap-devtools.readthedocs.io/en/latest/"
@@ -48,30 +71,19 @@ changelog = "https://gitlab.idiap.ch/software/idiap-devtools/-/releases"
 [project.optional-dependencies]
 qa = ["pre-commit"]
 doc = [
-    "sphinx",
-    "furo",
-    "sphinx-autodoc-typehints",
-    "sphinx-copybutton",
-    "sphinx-inline-tabs",
-    "sphinx-click",
-    "auto-intersphinx",
-    ]
-test = [
-    "pytest",
-    "pytest-cov",
-    "coverage",
-    ]
+  "sphinx",
+  "furo",
+  "sphinx-autodoc-typehints",
+  "sphinx-copybutton",
+  "sphinx-inline-tabs",
+  "sphinx-click",
+  "auto-intersphinx",
+]
+test = ["pytest", "pytest-cov", "coverage"]
 
 [project.scripts]
 devtool = "idiap_devtools.scripts.cli:cli"
 
-[tool.setuptools]
-zip-safe = true
-package-dir = {"" = "src"}
-
-[tool.distutils.bdist_wheel]
-universal = true
-
 [tool.isort]
 profile = "black"
 line_length = 80
@@ -83,9 +95,9 @@ line-length = 80
 
 [tool.pytest.ini_options]
 addopts = [
-    "--cov=idiap_devtools",
-    "--cov-report=term-missing",
-    "--import-mode=append",
+  "--cov=idiap_devtools",
+  "--cov-report=term-missing",
+  "--import-mode=append",
 ]
 junit_logging = "all"
 junit_log_passing_tests = false
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 6aeeebe77757841aecdd9592203fc18f9951a933..0000000000000000000000000000000000000000
--- a/setup.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright © 2022 Idiap Research Institute <contact@idiap.ch>
-#
-# SPDX-License-Identifier: BSD-3-Clause
-
-from setuptools import setup
-
-setup()
diff --git a/src/idiap_devtools/click.py b/src/idiap_devtools/click.py
index 0d6d1a71ba293af08a945888e9eb2fa929f87dd2..fcd9e97554a0de70f5c3f276bd8fefb7109465a3 100644
--- a/src/idiap_devtools/click.py
+++ b/src/idiap_devtools/click.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import logging
 import typing
 
diff --git a/src/idiap_devtools/conda.py b/src/idiap_devtools/conda.py
index 02df01fe2fff5bfb2d4558adfc48616eca77cdc2..ddc8ce47a1896091ffa391ef08406dfbb3e53b86 100644
--- a/src/idiap_devtools/conda.py
+++ b/src/idiap_devtools/conda.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import contextlib
 import copy
 import logging
diff --git a/src/idiap_devtools/gitlab/__init__.py b/src/idiap_devtools/gitlab/__init__.py
index ff6dd8888010455a2599ecd8f9f5ca4c95147c75..4fd9f56232a9920f0483e1fae6520e9e92ab5028 100644
--- a/src/idiap_devtools/gitlab/__init__.py
+++ b/src/idiap_devtools/gitlab/__init__.py
@@ -3,8 +3,6 @@
 # SPDX-License-Identifier: BSD-3-Clause
 """Utilities to interact with GitLab."""
 
-from __future__ import annotations
-
 import logging
 import os
 import pathlib
diff --git a/src/idiap_devtools/gitlab/changelog.py b/src/idiap_devtools/gitlab/changelog.py
index cbb17d9851ab35e7f8e8ef64e10c9df5feac5cde..df7e3aa8a74f9893711e28d78f5d059d7716ead7 100644
--- a/src/idiap_devtools/gitlab/changelog.py
+++ b/src/idiap_devtools/gitlab/changelog.py
@@ -3,8 +3,6 @@
 # SPDX-License-Identifier: BSD-3-Clause
 """Utilities for retrieving, parsing and auto-generating changelogs."""
 
-from __future__ import annotations
-
 import datetime
 import io
 import logging
diff --git a/src/idiap_devtools/gitlab/release.py b/src/idiap_devtools/gitlab/release.py
index fe02ede42aaaebb715419b2e704ac183a6b9668f..604c5123c0da82d43bd7edf7385c3681983464ff 100644
--- a/src/idiap_devtools/gitlab/release.py
+++ b/src/idiap_devtools/gitlab/release.py
@@ -3,8 +3,6 @@
 # SPDX-License-Identifier: BSD-3-Clause
 """Utilities to needed to release packages."""
 
-from __future__ import annotations
-
 import difflib
 import logging
 import re
@@ -561,7 +559,7 @@ def update_files_at_default_branch(
 
 def _get_last_pipeline(
     gitpkg: gitlab.v4.objects.projects.Project,
-) -> gitlab.v4.objects.pipelines.Pipeline:
+) -> gitlab.v4.objects.pipelines.ProjectPipeline:
     """Returns the last pipeline of the project.
 
     Arguments:
diff --git a/src/idiap_devtools/gitlab/runners.py b/src/idiap_devtools/gitlab/runners.py
index 8392edf2d038fad94e32e089181757abbf60c5d2..983faf5afcf2641a8f71c2d384c7839a74d33f69 100644
--- a/src/idiap_devtools/gitlab/runners.py
+++ b/src/idiap_devtools/gitlab/runners.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import logging
 import pathlib
 import typing
diff --git a/src/idiap_devtools/profile.py b/src/idiap_devtools/profile.py
index 8edfffce6508ad56e212b1a438b3267b4681d8b7..2e49c2f46f20bc3d88156bc8fc3e50c8d0f007d6 100644
--- a/src/idiap_devtools/profile.py
+++ b/src/idiap_devtools/profile.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import io
 import os
 import pathlib
diff --git a/src/idiap_devtools/python.py b/src/idiap_devtools/python.py
index 83f48a8d7c8f04e5ddf65c02585331ef124cc260..64b9e66bcd0514694041f5aac54074a5eb863d47 100644
--- a/src/idiap_devtools/python.py
+++ b/src/idiap_devtools/python.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import pkg_resources
 import tomli
 
diff --git a/src/idiap_devtools/scripts/cli.py b/src/idiap_devtools/scripts/cli.py
index 62cc4193e4fbeee3f9876a02b042cf37c0365898..5c9a87c2e0c35b43284618f1753951b3efce5882 100644
--- a/src/idiap_devtools/scripts/cli.py
+++ b/src/idiap_devtools/scripts/cli.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import click
 
 from ..click import AliasedGroup
diff --git a/src/idiap_devtools/scripts/env.py b/src/idiap_devtools/scripts/env.py
index d0d55dc7ae69d8d437f8b14d43b84ede6c7e0bff..784633a92174d9c91073dfb7c78ab4aaf655858c 100644
--- a/src/idiap_devtools/scripts/env.py
+++ b/src/idiap_devtools/scripts/env.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import sys
 import typing
 
@@ -258,7 +256,7 @@ def _add_missing_conda_pins(
     epilog="""
 Examples:
 
-  1. Creates an environment installation plan for developing the currently
+  1. Creates a conda environment installation plan for developing the currently
      checked-out package, and the development profile in ``../profile``:
 
      .. code:: sh
diff --git a/src/idiap_devtools/scripts/fullenv.py b/src/idiap_devtools/scripts/fullenv.py
index b6eb41f18e083b9e2668a8a56febc0598624bf6f..bfa83c5f9029c93c1b08c01448a609ab7aed8fee 100644
--- a/src/idiap_devtools/scripts/fullenv.py
+++ b/src/idiap_devtools/scripts/fullenv.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import sys
 
 import click
diff --git a/src/idiap_devtools/scripts/gitlab/__init__.py b/src/idiap_devtools/scripts/gitlab/__init__.py
index 72fad1f7c1c91fcdd3ab0edc09afc928df295398..ad63e2b3d0ac9520ca43ca2ae359766630e3fa6a 100644
--- a/src/idiap_devtools/scripts/gitlab/__init__.py
+++ b/src/idiap_devtools/scripts/gitlab/__init__.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import click
 
 from ...click import AliasedGroup
diff --git a/src/idiap_devtools/scripts/gitlab/badges.py b/src/idiap_devtools/scripts/gitlab/badges.py
index 1eb2699d7b8f9403e7a84980cfee884a9fa209df..22968f59a73a6dd5c090ac8d8bbb0c03aa57ff4b 100644
--- a/src/idiap_devtools/scripts/gitlab/badges.py
+++ b/src/idiap_devtools/scripts/gitlab/badges.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import click
 
 from ...click import PreserveIndentCommand, verbosity_option
diff --git a/src/idiap_devtools/scripts/gitlab/changelog.py b/src/idiap_devtools/scripts/gitlab/changelog.py
index 8e6d606d433ebb0f74aaf530fec7b06775185ccf..d286bdcd7b86327b9b4e7a448287b20c15c70c62 100644
--- a/src/idiap_devtools/scripts/gitlab/changelog.py
+++ b/src/idiap_devtools/scripts/gitlab/changelog.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import sys
 
 import click
diff --git a/src/idiap_devtools/scripts/gitlab/getpath.py b/src/idiap_devtools/scripts/gitlab/getpath.py
index 67de11fd14cf43862d1a7af62fbb3f56b041514d..4e0d763eefc74dd26166d89d80ee6ae4fc886d63 100644
--- a/src/idiap_devtools/scripts/gitlab/getpath.py
+++ b/src/idiap_devtools/scripts/gitlab/getpath.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import click
 
 from ...click import PreserveIndentCommand, verbosity_option
diff --git a/src/idiap_devtools/scripts/gitlab/jobs.py b/src/idiap_devtools/scripts/gitlab/jobs.py
index d37bebf668e513e0f4a7307c21a2c2db6f366aab..a69e3d96d89871e73d55568ca5358e7add361b3e 100644
--- a/src/idiap_devtools/scripts/gitlab/jobs.py
+++ b/src/idiap_devtools/scripts/gitlab/jobs.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import click
 
 from ...click import PreserveIndentCommand, verbosity_option
diff --git a/src/idiap_devtools/scripts/gitlab/lasttag.py b/src/idiap_devtools/scripts/gitlab/lasttag.py
index f1c986d6451f21a4059bbbc11834eaf7ba1a69d1..936b894942d41225f1e6d553c3e9a3b83e56a6be 100644
--- a/src/idiap_devtools/scripts/gitlab/lasttag.py
+++ b/src/idiap_devtools/scripts/gitlab/lasttag.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import click
 
 from ...click import PreserveIndentCommand, verbosity_option
diff --git a/src/idiap_devtools/scripts/gitlab/release.py b/src/idiap_devtools/scripts/gitlab/release.py
index 51278b27e6afd59e58be3d4e4608cfe0a5421595..cb198d6e8ae8cd999dafe530a29c7f2810edf42a 100644
--- a/src/idiap_devtools/scripts/gitlab/release.py
+++ b/src/idiap_devtools/scripts/gitlab/release.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import typing
 
 import click
diff --git a/src/idiap_devtools/scripts/gitlab/runners.py b/src/idiap_devtools/scripts/gitlab/runners.py
index 362d4778e5425fc68af40d6edaefb30529a9d53c..217229dad3c60ff16a982a76faba7185790b245f 100644
--- a/src/idiap_devtools/scripts/gitlab/runners.py
+++ b/src/idiap_devtools/scripts/gitlab/runners.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import os
 
 import click
diff --git a/src/idiap_devtools/scripts/gitlab/settings.py b/src/idiap_devtools/scripts/gitlab/settings.py
index e9de2d1b168c77d8a26d4bf2bb4fb049cac7f450..ed6f8660adb8159c969c71f4f8938aba52735057 100644
--- a/src/idiap_devtools/scripts/gitlab/settings.py
+++ b/src/idiap_devtools/scripts/gitlab/settings.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import typing
 
 import click
diff --git a/src/idiap_devtools/scripts/update_pins.py b/src/idiap_devtools/scripts/update_pins.py
index c1c26091fc82f59f0d9068bab45b7b2f0486138b..362c7e305382f2169a3f053822b75912727ea5b9 100644
--- a/src/idiap_devtools/scripts/update_pins.py
+++ b/src/idiap_devtools/scripts/update_pins.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import sys
 
 import click
diff --git a/src/idiap_devtools/update_pins.py b/src/idiap_devtools/update_pins.py
index 9a15837e802eb57573c0951176ee65d95e4a4776..62020630c03c4d7241d96f7e9fcda2e12baa3bb9 100644
--- a/src/idiap_devtools/update_pins.py
+++ b/src/idiap_devtools/update_pins.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import contextlib
 import copy
 import logging
diff --git a/src/idiap_devtools/utils.py b/src/idiap_devtools/utils.py
index 2097f82b2d4729d0c349e9da46bf2f5f7792e112..4fe17b0b2458c691feb714b6b595d9fe7ca9f375 100644
--- a/src/idiap_devtools/utils.py
+++ b/src/idiap_devtools/utils.py
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: BSD-3-Clause
 
-from __future__ import annotations
-
 import logging
 import os
 import subprocess