Free-threaded Python on GitHub Actions

Table of Contents
GitHub Actions now supports experimental free-threaded CPython!
There are three ways to add it to your test matrix:
- actions/setup-python:
t
suffix - actions/setup-uv:
t
suffix - actions/setup-python:
freethreaded
variable
actions/setup-python: t
suffix #
Using actions/setup-python, you
can add the t
suffix for Python versions 3.13 and higher: 3.13t
and 3.14t
.
This is my preferred method, we can clearly see which versions are free-threaded and it’s straightforward to test both regular and free-threaded builds.
on: [push, pull_request, workflow_dispatch]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version: [
"3.13",
"3.13t", # add this!
"3.14",
"3.14t", # add this!
]
os: ["windows-latest", "macos-latest", "ubuntu-latest"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true # needed for 3.14
- run: |
python --version --version
python -c "import sys; print('sys._is_gil_enabled:', sys._is_gil_enabled())"
python -c "import sysconfig; print('Py_GIL_DISABLED:', sysconfig.get_config_var('Py_GIL_DISABLED'))"
Regular builds will output something like:
Python 3.14.0a6 (main, Mar 17 2025, 02:44:29) [GCC 13.3.0]
sys._is_gil_enabled: True
Py_GIL_DISABLED: 0
And free-threaded builds will output something like:
Python 3.14.0a6 experimental free-threading build (main, Mar 17 2025, 02:44:30) [GCC 13.3.0]
sys._is_gil_enabled: False
Py_GIL_DISABLED: 1
For example: hugovk/test/actions/runs/14057185035
actions/setup-uv: t
suffix #
Similarly, you can install uv with
astral/setup-uv and use that to
set up free-threaded Python using the t
suffix.
on: [push, pull_request, workflow_dispatch]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version: [
"3.13",
"3.13t", # add this!
"3.14",
"3.14t", # add this!
]
os: ["windows-latest", "macos-latest", "ubuntu-latest"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: astral-sh/setup-uv@v5 # change this!
with:
python-version: ${{ matrix.python-version }}
enable-cache: false # only needed for this example with no dependencies
- run: |
python --version --version
python -c "import sys; print('sys._is_gil_enabled:', sys._is_gil_enabled())"
python -c "import sysconfig; print('Py_GIL_DISABLED:', sysconfig.get_config_var('Py_GIL_DISABLED'))"
For example: hugovk/test/actions/runs/13967959519
actions/setup-python: freethreaded
variable #
Back to actions/setup-python, you can also set the freethreaded
variable for 3.13
and higher.
on: [push, pull_request, workflow_dispatch]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version: ["3.13", "3.14"]
os: ["windows-latest", "macos-latest", "ubuntu-latest"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
allow-prereleases: true # needed for 3.14
freethreaded: true # add this!
- run: |
python --version --version
python -c "import sys; print('sys._is_gil_enabled:', sys._is_gil_enabled())"
python -c "import sysconfig; print('Py_GIL_DISABLED:', sysconfig.get_config_var('Py_GIL_DISABLED'))"
For example: hugovk/test/actions/runs/39359291708
PYTHON_GIL=0
#
And you may want to set PYTHON_GIL=0
to force Python to keep the GIL disabled, even
after importing a module that doesn’t support running without it.
See Running Python with the GIL Disabled for more info.
With the t
suffix:
- name: Set PYTHON_GIL
if: endsWith(matrix.python-version, 't')
run: |
echo "PYTHON_GIL=0" >> "$GITHUB_ENV"
With the freethreaded
variable:
- name: Set PYTHON_GIL
if: "${{ matrix.freethreaded }}"
run: |
echo "PYTHON_GIL=0" >> "$GITHUB_ENV"
Please test! #
For free-threaded Python to succeed and become the default, it’s essential there is ecosystem and community support. Library maintainers: please test it and where needed, adapt your code, and publish free-threaded wheels so others can test their code that depends on yours. Everyone else: please test your code too!
See also #
- Help us test free-threaded Python without the GIL for other ways to test and how to check your build
- Python free-threading guide
- actions/setup-python#973
- actions/setup-python@v5.5.0
Header photo: “Spinning Room, Winding Bobbins with Woolen Yarn for Weaving, Philadelphia, PA” by Library Company of Philadelphia, with no known copyright restrictions.