diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d33908a484fe8db81c5905c071d875ee77003e40..d1b975e7956fd063437251be0e0053ec6c744957 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -83,11 +83,9 @@ test_enpt_install:
 
     # install enpt
     - pip install -e .
-    - cd ..
-    - pwd
-    - ls
 
     # test importability
+    - cd ../..
     - python -c "import enpt; print(enpt)"
     - python -c "from enpt.model.images import EnMAPL1Product_SensorGeo"
 
@@ -96,6 +94,7 @@ test_enpt_install:
   only:
     - main
     - dev
+    - maintenance/modernize_setup
 
 
 pages:
diff --git a/HISTORY.rst b/HISTORY.rst
index 53f5c093256590827f43aacddbc707f80b7d9844..7b3c89730eabd4530d1689bed404031654ba1286 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -2,10 +2,11 @@
 History
 =======
 
-0.20.3 (coming soon)
+0.21.0 (coming soon)
 --------------------
 
 * Adapted CI runner build script to upstream changes in GitLab 17.0.
+* !108: Migrated setup procedure from using setup.py + setup.cfg to using pyproject.toml only. Dropped requirements.txt.
 
 
 0.20.2 (2024-05-30)
diff --git a/MANIFEST.in b/MANIFEST.in
index c53b26f1f8e93dff23ed0241769ae2dcc5d421f0..1aab9bbceec569a28ff05422541b4bfbaadc1fd9 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,9 +4,17 @@ include HISTORY.rst
 include LICENSE
 include README.rst
 
-recursive-exclude tests *
+exclude .coveragerc
+exclude .gitattributes
+exclude .gitignore
+exclude .gitlab-ci.yml
+exclude MANIFEST.in
+
+recursive-exclude .github *
+recursive-exclude docs *
 recursive-exclude examples *
+recursive-exclude tests *
 recursive-exclude * __pycache__
 recursive-exclude * *.py[co]
 
-recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif
+recursive-include *.rst conf.py Makefile make.bat *.jpg *.png *.gif
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000000000000000000000000000000000000..b8f3df4d1340c4d23dc2a1ecd3c571ef29f58054
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,145 @@
+# -*- coding: utf-8 -*-
+
+# EnPT, EnMAP Processing Tool - A Python package for pre-processing of EnMAP Level-1B data
+#
+# Copyright (C) 2018-2024 Karl Segl (GFZ Potsdam, segl@gfz-potsdam.de), Daniel Scheffler
+# (GFZ Potsdam, danschef@gfz-potsdam.de), Niklas Bohn (GFZ Potsdam, nbohn@gfz-potsdam.de),
+# Stéphane Guillaso (GFZ Potsdam, stephane.guillaso@gfz-potsdam.de)
+#
+# This software was developed within the context of the EnMAP project supported
+# by the DLR Space Administration with funds of the German Federal Ministry of
+# Economic Affairs and Energy (on the basis of a decision by the German Bundestag:
+# 50 EE 1529) and contributions from DLR, GFZ and OHB System AG.
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version. Please note the following exception: `EnPT` depends on tqdm, which
+# is distributed under the Mozilla Public Licence (MPL) v2.0 except for the files
+# "tqdm/_tqdm.py", "setup.py", "README.rst", "MANIFEST.in" and ".gitignore".
+# Details can be found here: https://github.com/tqdm/tqdm/blob/master/LICENCE.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with this program. If not, see <https://www.gnu.org/licenses/>.
+
+[build-system]
+requires = [
+    "setuptools>=61.2",
+    "setuptools-git",
+]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "enpt"
+description = "EnMAP Processing Tool"
+authors = [
+    {name = "Daniel Scheffler", email = "daniel.scheffler@gfz-potsdam.de"},
+    {name = "Niklas Bohn", email = "nbohn@gfz-potsdam.de"},
+    {name = "Stéphane Guillaso", email = "stephane.guillaso@gfz-potsdam.de"},
+    {name = "Brenner Silva", email = "brenner.silva@awi.de"},
+    {name = "Leonardo Alvarado", email = "leonardo.alvarado@awi.de"},
+    {name = "Karl Segl", email = "segl@gfz-potsdam.de"},
+]
+maintainers = [
+    {name = "Daniel Scheffler", email = "daniel.scheffler@gfz-potsdam.de"},
+]
+license = {text = "GPL-3.0-or-later"}
+classifiers = [
+    "Development Status :: 4 - Beta",
+    "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
+    "Natural Language :: English",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: 3.11",
+]
+keywords = [
+    "EnPT",
+    "EnMAP",
+    "EnMAP-Box",
+    "hyperspectral",
+    "remote sensing",
+    "satellite",
+    "processing chain"
+]
+requires-python = ">=3.8"
+dependencies = [
+    "acwater>=0.3.0",
+    "arosics>=1.0.0",
+    "cerberus",
+    "gdal",
+    "geoarray>=0.15.8",
+    "jsmin",
+    "lxml",
+    "matplotlib",
+    "mvgavg",
+    "natsort",
+    "numpy",
+    "numpy-indexed",
+    "packaging",
+    "pandas",
+    "py_tools_ds>=0.14.25",
+    "pyproj>=3.4.0",
+    "scikit-image",
+    "scipy",
+    "sensormapgeo>=1.0.0",
+    "sicor>=0.19.1",
+    "tqdm",
+    "utm",
+]
+dynamic = ["version"]
+
+[project.readme]
+file = "README.rst"
+content-type = "text/x-rst"
+
+[project.urls]
+"Source code" = "https://git.gfz-potsdam.de/EnMAP/GFZ_Tools_EnMAP_BOX/EnPT"
+"Issue Tracker" = "https://git.gfz-potsdam.de/EnMAP/GFZ_Tools_EnMAP_BOX/EnPT/-/issues"
+"Documentation" = "https://enmap.git-pages.gfz-potsdam.de/GFZ_Tools_EnMAP_BOX/EnPT/doc"
+"Change log" = "https://git.gfz-potsdam.de/EnMAP/GFZ_Tools_EnMAP_BOX/EnPT/-/blob/main/HISTORY.rst"
+"Zenodo" = "https://zenodo.org/records/8229436"
+
+[project.optional-dependencies]
+doc = [
+    "sphinx-argparse",
+    "sphinx_rtd_theme",
+]
+test = [
+    "pytest",
+    "pytest-cov",
+    "pytest-reporter-html1",
+    "urlchecker",
+]
+lint = [
+    "flake8",
+    "pycodestyle",
+    "pydocstyle",
+]
+dev = [
+    "enpt[test]",
+    "enpt[doc]",
+    "enpt[lint]",
+]
+
+[project.scripts]
+arosics = "enpt.cli:main"
+
+[tool.setuptools]
+zip-safe = false
+include-package-data = true
+license-files = ["LICENSE"]
+
+[tool.setuptools.packages.find]
+namespaces = false
+
+[tool.setuptools.dynamic]
+version = {attr = "enpt.version.__version__"}
+
+[tool.distutils.bdist_wheel]
+universal = 1
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 6174902902616447860837294c197743c7b19a52..0000000000000000000000000000000000000000
--- a/requirements.txt
+++ /dev/null
@@ -1,22 +0,0 @@
-acwater>=0.3.0
-arosics>=1.0.0
-cerberus
-gdal
-geoarray>=0.15.8
-jsmin
-lxml
-matplotlib
-mvgavg
-natsort
-numpy
-numpy-indexed
-packaging
-pandas
-pyproj>=3.4.0
-py_tools_ds>=0.14.25
-scikit-image
-scipy
-sensormapgeo>=1.0.0
-sicor>=0.19.1
-tqdm
-utm
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 4faf28b04ea784af13b5d9098ef791bd8558b767..0000000000000000000000000000000000000000
--- a/setup.cfg
+++ /dev/null
@@ -1,18 +0,0 @@
-[bumpversion]
-current_version = 0.1.0
-commit = True
-tag = True
-
-[bumpversion:file:setup.py]
-search = version='{current_version}'
-replace = version='{new_version}'
-
-[bumpversion:file:enpt/__init__.py]
-search = __version__ = '{current_version}'
-replace = __version__ = '{new_version}'
-
-[bdist_wheel]
-universal = 1
-
-[flake8]
-exclude = docs
diff --git a/setup.py b/setup.py
deleted file mode 100644
index ce02015556f49eb4c09fe865645d88881cace97e..0000000000000000000000000000000000000000
--- a/setup.py
+++ /dev/null
@@ -1,122 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# EnPT, EnMAP Processing Tool - A Python package for pre-processing of EnMAP Level-1B data
-#
-# Copyright (C) 2018-2024 Karl Segl (GFZ Potsdam, segl@gfz-potsdam.de), Daniel Scheffler
-# (GFZ Potsdam, danschef@gfz-potsdam.de), Niklas Bohn (GFZ Potsdam, nbohn@gfz-potsdam.de),
-# Stéphane Guillaso (GFZ Potsdam, stephane.guillaso@gfz-potsdam.de)
-#
-# This software was developed within the context of the EnMAP project supported
-# by the DLR Space Administration with funds of the German Federal Ministry of
-# Economic Affairs and Energy (on the basis of a decision by the German Bundestag:
-# 50 EE 1529) and contributions from DLR, GFZ and OHB System AG.
-#
-# This program is free software: you can redistribute it and/or modify it under
-# the terms of the GNU General Public License as published by the Free Software
-# Foundation, either version 3 of the License, or (at your option) any later
-# version. Please note the following exception: `EnPT` depends on tqdm, which
-# is distributed under the Mozilla Public Licence (MPL) v2.0 except for the files
-# "tqdm/_tqdm.py", "setup.py", "README.rst", "MANIFEST.in" and ".gitignore".
-# Details can be found here: https://github.com/tqdm/tqdm/blob/master/LICENCE.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
-# details.
-#
-# You should have received a copy of the GNU Lesser General Public License along
-# with this program. If not, see <https://www.gnu.org/licenses/>.
-
-from setuptools import setup, find_packages
-
-__author__ = 'Daniel Scheffler'
-
-
-with open('README.rst') as readme_file:
-    readme = readme_file.read()
-
-version = {}
-with open("enpt/version.py", encoding='utf-8') as version_file:
-    exec(version_file.read(), version)
-
-req = [
-    'acwater>=0.3.0',
-    'arosics>=1.0.0',
-    'cerberus',
-    'gdal',
-    'geoarray>=0.15.8',
-    'jsmin',
-    'lxml',
-    'matplotlib',
-    'mvgavg',
-    'natsort',
-    'numpy',
-    'numpy-indexed',
-    'packaging',
-    'pandas',
-    'pyproj>=3.4.0',
-    'py_tools_ds>=0.14.25',
-    'scikit-image',
-    'scipy',
-    'sensormapgeo>=1.0.0',
-    'sicor>=0.19.1',
-    'tqdm',
-    'utm',
-]
-
-req_setup = ['setuptools-git']  # needed for package_data version controlled by GIT
-
-req_test = ['pytest', 'pytest-cov', 'pytest-reporter-html1', 'urlchecker']
-
-req_doc = ['sphinx-argparse', 'sphinx_rtd_theme']
-
-req_lint = ['flake8', 'pycodestyle', 'pydocstyle']
-
-req_dev = req_setup + req_test + req_doc + req_lint
-
-setup(
-    author="Karl Segl, Daniel Scheffler, Niklas Bohn, Stéphane Guillaso, Brenner Silva, Leonardo Alvarado",
-    author_email="segl@gfz-potsdam.de, danschef@gfz-potsdam.de, nbohn@gfz-potsdam.de, "
-                 "stephane.guillaso@gfz-potsdam.de, brenner.silva@awi.de, leonardo.alvarado@awi.de",
-    classifiers=[
-        'Development Status :: 4 - Beta',
-        'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
-        'Natural Language :: English',
-        'Programming Language :: Python :: 3.8',
-        'Programming Language :: Python :: 3.9',
-        'Programming Language :: Python :: 3.10',
-        'Programming Language :: Python :: 3.11',
-    ],
-    description="EnMAP Processing Tool",
-    entry_points={
-        'console_scripts': [
-            'enpt=enpt.cli:main',
-        ],
-    },
-    extras_require={
-        "doc": req_doc,
-        "test": req_test,
-        "lint": req_lint,
-        "dev": req_dev
-    },
-    keywords=['EnPT', 'EnMAP', 'EnMAP-Box', 'hyperspectral', 'remote sensing', 'satellite', 'processing chain'],
-    include_package_data=True,
-    install_requires=req,
-    license="GPL-3.0-or-later",
-    long_description=readme,
-    long_description_content_type='text/x-rst',
-    name='enpt',
-    package_dir={'enpt': 'enpt'},
-    # NOTE: if the 'package_data' files are not under CVS or Subversion version control, we need setuptools-git here,
-    #       otherwise they are not included in the PyPI upload content
-    package_data={"enpt": ["resources/**/**/*"]},
-    packages=find_packages(exclude=['tests*', 'examples*']),  # does not seem to work, therefore use MANIFEST.in
-    python_requires='>=3.8',
-    setup_requires=req_setup,
-    test_suite='tests',
-    tests_require=req_test,
-    url='https://git.gfz-potsdam.de/EnMAP/GFZ_Tools_EnMAP_BOX/EnPT',
-    version=version['__version__'],
-    zip_safe=False
-)