diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index fd959fa8501e56bc4f1869e363b4a2118a86edce..0000000000000000000000000000000000000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,2 +0,0 @@
-include requirements.txt
-include VERSION
diff --git a/VERSION b/VERSION
deleted file mode 100644
index 0d91a54c7d439e84e3dd17d3594f1b2b6737f430..0000000000000000000000000000000000000000
--- a/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-0.3.0
diff --git a/pyproject.toml b/pyproject.toml
index 24be6f8c255151161b9d3aa3901c88ae3a01b3a8..79fa552f4952f4d18a410db2d66b3093e96800e6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,3 +1,29 @@
+[build-system]
+requires = ["setuptools >= 61.0"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "nerval"
+version = "0.3.0"
+description = "Tool to evaluate NER on noisy text."
+dynamic = ["dependencies"]
+authors = [
+    { name = "Teklia", email = "contact@teklia.com" },
+]
+maintainers = [
+    { name = "Teklia", email = "contact@teklia.com" },
+]
+readme = { file = "README.md", content-type = "text/markdown" }
+
+[project.scripts]
+nerval = "nerval.cli:main"
+
+[tool.setuptools]
+packages = ["nerval"]
+
+[tool.setuptools.dynamic]
+dependencies = { file = ["requirements.txt"] }
+
 [tool.ruff]
 exclude = [".git", "__pycache__"]
 ignore = [
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 611c366fbf771b8ee8e3ad9678c2a650b88b8e31..0000000000000000000000000000000000000000
--- a/setup.py
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env python
-from pathlib import Path
-
-from setuptools import find_packages, setup
-
-
-def parse_requirements_line(line):
-    """Special case for git requirements"""
-    if line.startswith("git+http"):
-        assert "@" in line, "Branch should be specified with suffix (ex: @master)"
-        assert (
-            "#egg=" in line
-        ), "Package name should be specified with suffix (ex: #egg=kraken)"
-        package_name = line.split("#egg=")[-1]
-        return f"{package_name} @ {line}"
-    else:
-        return line
-
-
-def parse_requirements():
-    path = Path(__file__).parent.resolve() / "requirements.txt"
-    assert path.exists(), f"Missing requirements: {path}"
-    return list(
-        map(parse_requirements_line, map(str.strip, path.read_text().splitlines())),
-    )
-
-
-setup(
-    name="nerval",
-    version=Path("VERSION").read_text(),
-    description="Tool to evaluate NER on noisy text.",
-    author="Teklia",
-    author_email="contact@teklia.com",
-    packages=find_packages(),
-    entry_points={"console_scripts": ["nerval=nerval.cli:main"]},
-    install_requires=parse_requirements(),
-)