diff --git a/pyproject.toml b/pyproject.toml
index 37727dabe63831214b0baa3e2115500e3fa8b88c..10dba60af1c1ac4bfa78229b789c24f8df3683d2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,5 +1,77 @@
+[build-system]
+build-backend = "setuptools.build_meta"
+requires = [
+    "setuptools>=63",
+]
+
+[project]
+name = "arraycontext"
+version = "2021.1"
+description = "Choose your favorite numpy-workalike"
+readme = "README.rst"
+license = { text = "MIT" }
+authors = [
+    { name = "Andreas Kloeckner", email = "inform@tiker.net" },
+]
+requires-python = ">=3.8"
+classifiers = [
+    "Development Status :: 3 - Alpha",
+    "Intended Audience :: Developers",
+    "Intended Audience :: Other Audience",
+    "Intended Audience :: Science/Research",
+    "License :: OSI Approved :: MIT License",
+    "Natural Language :: English",
+    "Programming Language :: Python",
+    "Programming Language :: Python :: 3 :: Only",
+    "Topic :: Scientific/Engineering",
+    "Topic :: Scientific/Engineering :: Information Analysis",
+    "Topic :: Scientific/Engineering :: Mathematics",
+    "Topic :: Software Development :: Libraries",
+    "Topic :: Utilities",
+]
+dependencies = [
+    "immutabledict>=4.1",
+    "numpy",
+    "pytools>=2024.1.3",
+]
+
+[project.optional-dependencies]
+jax = [
+    "jax>=0.4",
+]
+pyopencl = [
+    "islpy>=2024.1",
+    "loopy>=2024.1",
+    "pyopencl>=2024.1",
+]
+pytato = [
+    "pytato>=2021.1",
+]
+test = [
+    "mypy",
+    "pytest",
+    "ruff",
+]
+
+[project.urls]
+Documentation = "https://documen.tician.de/arraycontext"
+Homepage = "https://github.com/inducer/arraycontext"
+
+[tool.setuptools.packages.find]
+include = [
+    "arraycontext*",
+]
+
+[tool.setuptools.package-dir]
+# https://github.com/Infleqtion/client-superstaq/pull/715
+"" = "."
+
+[tool.setuptools.package-data]
+pytools = [
+    "py.typed",
+]
+
 [tool.ruff]
-target-version = "py38"
 preview = true
 
 [tool.ruff.lint]
@@ -13,15 +85,15 @@ extend-select = [
     "N",   # pep8-naming
     "NPY", # numpy
     "Q",   # flake8-quotes
-    "UP",  # pyupgrade
     "RUF", # ruff
+    "UP",  # pyupgrade
     "W",   # pycodestyle
 ]
 extend-ignore = [
-    "C90",  # McCabe complexity
-    "E221", # multiple spaces before operator
-    "E226", # missing whitespace around arithmetic operator
-    "E402", # module-level import not at top of file
+    "C90",   # McCabe complexity
+    "E221",  # multiple spaces before operator
+    "E226",  # missing whitespace around arithmetic operator
+    "E402",  # module-level import not at top of file
     "UP006", # updated annotations due to __future__ import
     "UP007", # updated annotations due to __future__ import
 ]
@@ -33,15 +105,17 @@ multiline-quotes = "double"
 
 [tool.ruff.lint.isort]
 combine-as-imports = true
+known-first-party = [
+    "jax",
+    "loopy",
+    "pymbolic",
+    "pyopencl",
+    "pytato",
+    "pytools",
+]
 known-local-folder = [
     "arraycontext",
 ]
-known-first-party = [
-  "pytools",
-  "pyopencl",
-  "pytato",
-  "loopy",
-]
 lines-after-imports = 2
 
 [tool.mypy]
@@ -51,15 +125,13 @@ warn_unused_ignores = true
 # check_untyped_defs = true
 
 [[tool.mypy.overrides]]
-
 module = [
-  "islpy",
-  "loopy.*",
-  "meshmode.*",
-  "pymbolic",
-  "pymbolic.*",
-  "pyopencl.*",
-  "jax.*",
+    "islpy.*",
+    "loopy.*",
+    "meshmode.*",
+    "pymbolic",
+    "pymbolic.*",
+    "pyopencl.*",
+    "jax.*",
 ]
-
 ignore_missing_imports = true
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 659052654f8bbc4d2cbb99de17b3a778b1d22d53..0000000000000000000000000000000000000000
--- a/setup.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-
-
-def main():
-    from setuptools import find_packages, setup
-
-    version_dict = {}
-    init_filename = "arraycontext/version.py"
-    exec(
-        compile(open(init_filename).read(), init_filename, "exec"), version_dict
-    )
-
-    setup(
-        name="arraycontext",
-        version=version_dict["VERSION_TEXT"],
-        description="Choose your favorite numpy-workalike",
-        long_description=open("README.rst").read(),
-        author="Andreas Kloeckner",
-        author_email="inform@tiker.net",
-        license="MIT",
-        url="https://documen.tician.de/arraycontext",
-        classifiers=[
-            "Development Status :: 3 - Alpha",
-            "Intended Audience :: Developers",
-            "Intended Audience :: Other Audience",
-            "Intended Audience :: Science/Research",
-            "License :: OSI Approved :: MIT License",
-            "Natural Language :: English",
-            "Programming Language :: Python",
-            "Programming Language :: Python :: 3",
-            "Topic :: Scientific/Engineering",
-            "Topic :: Scientific/Engineering :: Information Analysis",
-            "Topic :: Scientific/Engineering :: Mathematics",
-            "Topic :: Software Development :: Libraries",
-            "Topic :: Utilities",
-        ],
-        packages=find_packages(),
-        python_requires="~=3.8",
-        install_requires=[
-            "numpy",
-            "pytools>=2024.1.3",
-            "immutabledict",
-            "loopy>=2019.1",
-        ],
-        extras_require={
-            "test": ["pytest>=2.3"],
-        },
-        package_data={"arraycontext": ["py.typed"]},
-    )
-
-
-if __name__ == "__main__":
-    main()