Skip to content

Commit 55efd20

Browse files
feat(posts): add "How to publish a private Python package to GitHub Releases"
Post: 2026-03-02-publish-private-python-package-to-github-releases.md
1 parent 00364a6 commit 55efd20

1 file changed

Lines changed: 88 additions & 0 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
layout: post
3+
title: How to publish a private Python package to GitHub Releases
4+
date: 2026-03-02 14:44:14
5+
excerpt: How to publish a private Python package to GitHub Releases.
6+
categories: github releases python package publish
7+
---
8+
9+
This post goes over how to publish a private Python package to GitHub Releases.
10+
11+
## Motivation
12+
13+
Normally, you want to publish your public Python package to PyPI. But for private packages, [GitHub Packages does not support Python](https://github.com/github/roadmap/issues/94).
14+
15+
I didn't want to publish my package to an external private registry, so I wanted to see if I could publish it to [GitHub Releases](https://docs.github.com/repositories/releasing-projects-on-github/about-releases).
16+
17+
## Publish
18+
19+
Publish your Python package with GitHub Actions:
20+
21+
{% raw %}
22+
23+
```yml
24+
# .github/workflows/release.yml
25+
# ...
26+
jobs:
27+
publish:
28+
runs-on: ubuntu-latest
29+
permissions:
30+
contents: write
31+
32+
steps:
33+
- name: Checkout repository
34+
uses: actions/checkout@v6
35+
36+
- name: Install uv
37+
uses: astral-sh/setup-uv@v7
38+
39+
- name: Build package
40+
run: uv build
41+
42+
- name: Upload to GitHub Release
43+
run: gh release upload v${{ needs.release.outputs.version }} dist/*.whl --clobber
44+
env:
45+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
46+
```
47+
48+
{% endraw %}
49+
50+
See [example workflow](https://github.com/remarkablemark/python-package-github-release-test/blob/master/.github/workflows/release-please.yml).
51+
52+
Check the latest release:
53+
54+
```sh
55+
gh release view --repo <USER>/<REPO> --json assets -q '.assets[] | select(.name | endswith(".whl")) | .url'
56+
```
57+
58+
> Replace `<USER>/<REPO>` with your username/organization and repository name.
59+
60+
The URL should look like:
61+
62+
```sh
63+
https://github.com/user/repo/releases/download/v1.2.3/python_package-1.2.3-py3-none-any.whl
64+
```
65+
66+
## Install
67+
68+
Use [GitHub CLI](https://cli.github.com/) to download the wheel:
69+
70+
```sh
71+
gh release download <TAG> -R <USER>/<REPO> -p '*.whl' -D ./vendor/ --clobber
72+
```
73+
74+
> Replace `<TAG>` with your release tag (e.g., `v1.2.3`) and `<USER>/<REPO>` with your username/organization and repository name.
75+
76+
Install your package with [uv](https://docs.astral.sh/uv/):
77+
78+
```sh
79+
uv add ./vendor/*.whl
80+
```
81+
82+
Or pip:
83+
84+
```sh
85+
pip install ./vendor/*.whl
86+
```
87+
88+
See [example repo](https://github.com/remarkablemark/python-package-github-release-test).

0 commit comments

Comments
 (0)