get-pip.py: the one script that puts pip inside a Python that has none
Helper scripts to install pip, in a Python installation that doesn't have it.
At a glance
- What is it?
- get-pip.py is the Python Packaging Authority's bootstrap script, a copy of pip plus a small amount of glue code that installs the latest pip into whatever environment you point it at. It is tiny, it is generated rather than hand edited, and the project is explicit that you should fetch the published version rather than the files in the repository.
- Who is it for?
- Adopt get-pip.py when you are handed a Python with no pip and no working package manager, in a container image, a CI job or a restricted environment where fetching from PyPI is the only route. Do not adopt it as a routine installation method for a machine you control, because the packaging tools now ship with Python itself, and do not run a copy from an unverified source.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem: a Python that has no package manager
Every Python installation used to come with pip, or at least with a way to get it. That stopped being true in a series of ways, and each way left somebody with a Python that could not install anything.
A stripped down container image, for instance, often has a Python interpreter and nothing else. A minimal operating system install may have a package manager that predates pip and offers a frozen copy. A locked down corporate machine may have Python but no rights to write to site-packages, or a firewall that blocks PyPI. A build system that wants to bootstrap itself in stages hits the same wall.
get-pip.py exists for that situation. The project description is precise: it is a bootstrapping script that enables users to install pip in Python environments that don't already have it installed.
The audience is therefore narrower than it looks. This is not the tool for setting up a development machine, where the Python you install already has a working pip and where the packaging tools are part of the distribution. It is the tool for the environment that was supposed to be self-sufficient and is not.
The trust design is the part that deserves attention first, and the project states it in the first paragraph of its documentation: you should not directly reference the files located in this repository and instead use the versions located at the bootstrap.pypa.io site. In other words, the repository is the source, and the served script is the artefact. The homepage for the project is the same site, bootstrap.pypa.io/pip/.
The licence is MIT, the repository is not archived, and the last push was on 2026-08-04. There are no GitHub releases, because the release is the served script rather than a tagged artefact.
How it works: a bundled pip and a small amount of glue
The mechanism is stated in one sentence in the documentation and it is the whole design: get-pip.py bundles a copy of pip with a tiny amount of glue code, and that glue code comes from the templates/ directory.
So the file you run is not a program that installs pip from somewhere. It is pip itself, plus the small amount of code that unpacks and runs it. That has two consequences worth naming.
The first is that the script works without network access to anything except PyPI, because the installer is already inside it. When the script then contacts PyPI to fetch the latest pip, it is replacing itself with a newer copy, and the bundled version is the fallback. If the machine can reach a local directory of wheels but not PyPI, the documented --no-index and --find-links options make the whole thing work offline.
The second is that the script is a build artefact rather than a hand written program. The repository layout shows the pipeline: a templates/ directory holding the glue code, a public/ directory for the published files, a scripts/ directory, and a noxfile.py that defines the tasks. The generated scripts are not edited by hand, and there is a dedicated session for regenerating them after a pip release.
That last point is the one to keep in mind when reading any diff to the file. A change in a pip release turns into a change in this repository, and the change is not reviewed in the same way as ordinary application code, because the file is executed before anybody looks at it.
The install: download, then run it
The usage section is two commands, and the first one is the part that matters for supply chain reasoning, because it pins where the file comes from.
$ curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ python get-pip.pyThe first command fetches the script over HTTPS from the project site rather than from GitHub, and the second runs it with the interpreter of your choice. The consequence of running it is that the latest version of pip is installed into the current Python environment.
There is a detail in that last sentence that catches people out on older interpreters. When using Python 3.11 or older, by default the packages setuptools and wheel will also be installed if an existing version of them was not found. So on a Python 3.9 or 3.10 environment, this script does three things rather than one, and that is deliberate: those are the two packages that a large share of legacy setup.py based installs still expect to be importable.
On Python 3.12 and newer, that behaviour does not apply, and the script carries its own options to control it explicitly, which are described below.
The document tells you to fetch it with curl rather than to pipe it straight into the interpreter, and that habit is worth keeping. Downloading first means you can look at the file, check its size, and record a hash, before you let it run. Piping a remote script into an interpreter is the same pattern as curl to a shell, and the difference in risk is only the size of the file you can inspect.
Passing arguments through to the underlying pip install
The script is a thin wrapper, and it shows in how arguments behave: it is possible to provide additional arguments to the underlying script, and these are passed through to the underlying pip install command. They can therefore be used to constrain the versions of the packages, install additional packages, or to pass other pip options such as --no-index.
The documentation gives three examples, and between them they cover the three use cases.
# Constrain the pip version
$ python get-pip.py "pip < 21.0"
# Force the installation of `setuptools` and `wheel` on newer Python versions.
$ python get-pip.py setuptools wheel
# Install packages from a local directory instead of PyPI.
$ python get-pip.py --no-index --find-links=/local/copiesThe first is a version constraint written in pip's own requirement syntax, passed as a single argument, which is how you pin the installer itself rather than only the packages it installs. The second forces setuptools and wheel to be installed even on a Python version where they are not added by default, which is the escape hatch for an environment that still needs them. The third is the offline path, and it is the most useful of the three for a constrained machine: with --no-index there is no attempt to reach PyPI at all, and --find-links points at a local directory of wheels that you staged yourself.
Note what the third example implies. get-pip.py is not the only half of an offline install: the local directory of wheels has to exist, and in practice you have to obtain it somehow. The script removes the need for pip, not the need for the packages.
The script's own options, and why they stopped mattering on Python 3.12
The script has its own options, which control which packages it will install, and they are only two.
The --no-setuptools option tells the script not to attempt to install setuptools, and the --no-wheel option does the same for wheel. Both are documented as a no-op on Python 3.12 and newer.
That is the interesting part. The options are still there for compatibility, and they still do what they say on older interpreters, but on a current Python the script no longer installs those two packages in the first place, so the switches have nothing to switch off. The behaviour was removed at the point where the Python distribution stopped needing them, and the flags were left in place so that scripts written for the old behaviour would not break.
That is a reasonable way to evolve a bootstrap script that people have had in automation for years, and it is also a reminder of why the documentation is worth reading. The most useful sentence in the whole page for a reader on a current Python is the one that says the setuptools and wheel install happens on Python 3.11 or older, because it tells you that a successful run of this script on 3.12 did something different from what a run on 3.10 did.
For a system that runs the same script across a range of interpreters, that difference is not academic. A build that assumes setuptools is present will work on 3.10 and fail on 3.12, and the failure will point at the build rather than at the bootstrap.
How the scripts are regenerated after a pip release
The development section is short and reveals how tightly the two projects are coupled.
To work on the project you need nox available on the command line. To generate the scripts, you run nox -s generate. And the interesting one is what happens when a pip release has just been made: you run nox -s update-for-release -- <version>, and that session will handle all the script updates by running generate, commit the changes and tag the commit.
There is a warning attached to that last command, and it is the kind of warning that tells you about the project's real workflow. The documentation says it is important to check that the correct files got modified before pushing, and that the session will pause to let you do this. In other words, the automation prepares the change, and a human still has to confirm that the diff contains the new pip and nothing else before it is pushed and tagged.
That pause is the safety mechanism for a project whose output is a script that people execute with elevated trust. The bundling of pip means a mistake in the generation step can put the wrong content into a file that runs before anybody has read it, and the human check in the release session is what stands between that mistake and a published script.
The project is also part of the wider Python community infrastructure: the discussion channels are the #pypa and #pypa-dev channels on Freenode, bugs go to the issue tracker, and the project expects everyone interacting with its codebases, issue trackers, chat rooms and mailing lists to follow the PSF Code of Conduct.
Editorial conclusion
Adopt get-pip.py when you are handed a Python with no pip and no working package manager, in a container image, a CI job or a restricted environment where fetching from PyPI is the only route. Do not adopt it as a routine installation method for a machine you control, because the packaging tools now ship with Python itself, and do not run a copy from an unverified source. Before you use it, fetch it from bootstrap.pypa.io rather than from a repository mirror, check the hash of what you downloaded, and pass --no-index with a local find-links path if the machine has no route to PyPI at all.
Frequently asked questions
How do I install pip with get-pip.py?
Download the script and run it: curl -sSL https://bootstrap.pypa.io/get-pip.py -o get-pip.py, then python get-pip.py. It installs the latest version of pip into the current Python environment, and on Python 3.11 or older it also installs setuptools and wheel if they are not already present.
Should I download get-pip.py from the GitHub repository?
No. The project states that you should not directly reference the files located in the repository and instead use the versions located at https://bootstrap.pypa.io/. The repository holds the source, and the served script is the artefact to run.
Can I use get-pip.py on a machine that cannot reach PyPI?
Yes, if you have a local directory of wheels. Arguments are passed through to the underlying pip install command, so you can run python get-pip.py --no-index --find-links=/local/copies, which installs from that directory instead of contacting PyPI.
What do the --no-setuptools and --no-wheel options do?
They tell the script not to attempt to install setuptools or wheel. Both are documented as a no-op on Python 3.12 and newer, because on those versions the script no longer installs those packages by default.
How are the get-pip.py scripts updated after a pip release?
Run nox -s update-for-release -- <version>, which regenerates the scripts, commits the changes and tags the commit, pausing so you can check that the correct files were modified before pushing. To regenerate the scripts alone, run nox -s generate.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pypa-get-pip)Was this useful?