setuptools
distutils
Python packaging
software development
Python tools

setuptools vs. distutils why is distutils still a thing?

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

distutils was the original standard-library packaging toolkit for Python, while setuptools grew into the richer tool most projects actually use. The confusing part is that distutils is historically important, still appears in old code and documentation, but is no longer the tool you should choose for new packaging work.

What distutils Was For

distutils provided the basic building blocks for packaging and installing Python projects. It supported simple source distributions and extension-module builds, but it was intentionally minimal.

That minimalism became a problem as packaging needs grew. Modern packaging expects dependency metadata, entry points, wheels, build isolation, and better interoperability with package indexes and installers. distutils never became the right place for that ecosystem to evolve.

Why setuptools Took Over

setuptools started as an extension on top of the older model and became the de facto standard for Python package building for many years. It added capabilities such as:

  • dependency declaration
  • console script entry points
  • wheel-oriented packaging workflows
  • richer extension hooks

A small modern example uses pyproject.toml and setuptools as the build backend:

toml
1[build-system]
2requires = ["setuptools>=68", "wheel"]
3build-backend = "setuptools.build_meta"
4
5[project]
6name = "example-package"
7version = "0.1.0"
8description = "Example package"
9dependencies = ["requests>=2.31"]
10
11[project.scripts]
12hello-example = "example.cli:main"

This is the packaging direction most current Python projects should follow.

So Why Do People Still Mention distutils

There are three main reasons.

First, a huge amount of legacy packaging material was written around setup.py and distutils. Older blog posts, tutorials, and internal enterprise packages still refer to it.

Second, for years setuptools itself preserved compatibility with distutils concepts and interfaces, so many developers interacted with the old vocabulary even when they were effectively using newer tooling.

Third, transition in packaging ecosystems is slow. Build tools, CI jobs, downstream Linux packaging, and extension-module workflows often lag behind best practice.

The Current State

Python formally deprecated distutils and removed it from the standard library in Python 3.12. That is the key fact that clears up the confusion: distutils still matters historically, but it is not a future-facing packaging choice.

You may still see imports that appear to use distutils, especially in old setup scripts or compatibility code. In many real projects, those references exist because the code has not been modernized yet, not because distutils remains the preferred approach.

Some tooling also preserved pieces of the old behavior for compatibility, which makes the ecosystem look more alive than it really is.

What You Should Use Instead

For new packages:

  • use pyproject.toml
  • choose a supported build backend such as setuptools, hatchling, or flit
  • build wheels and source distributions through standard frontend tools

Example:

bash
python -m build

That command uses the declared backend from pyproject.toml and avoids relying on legacy packaging entry points.

If you maintain an older setup.py project, modernizing does not have to be all-or-nothing. Start by moving build metadata into pyproject.toml, then reduce or remove direct distutils usage as you touch the package.

Common Pitfalls

The biggest mistake is treating distutils as merely an older equivalent of setuptools. It is not just older; it is also deprecated and removed from the stdlib in current Python.

Another common issue is copying a legacy setup.py example without checking whether it still reflects modern packaging practice.

Teams also sometimes assume packaging means setuptools only. In reality, modern Python packaging is built around standardized metadata and backend interfaces, so you have choices.

Finally, do not confuse installation tooling with build backend choice. pip, build, and the backend each play different roles.

Summary

  • 'distutils was Python’s original packaging toolkit, but it is now legacy technology.'
  • 'setuptools became the dominant successor because it solved practical packaging needs.'
  • Python removed distutils from the standard library in Python 3.12.
  • New projects should use pyproject.toml with a supported build backend.
  • You still see distutils mainly because old code and compatibility layers linger.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.