Python 3.13 has been out for about a month now, and the feature everyone’s talking about is the experimental free-threaded build — Python without the Global Interpreter Lock (GIL). After decades of the GIL being the standard answer to “why is my Python program only using one core?”, we’re finally seeing what a GIL-free Python looks like in practice. I’ve spent the last few weeks testing it with real workloads, and the results are… nuanced.
Understanding the Free-Threading Build#
First, some context for those who haven’t been following the PEP 703 journey. The free-threaded build is an experimental option — you have to specifically install the python3.13t variant or build CPython with --disable-gil. It’s not the default, and for good reason: removing the GIL required fundamental changes to CPython’s memory management, reference counting, and object lifecycle.
The GIL has been both Python’s curse and its hidden blessing. Yes, it prevents true parallelism in CPU-bound multi-threaded code. But it also makes CPython’s internals simpler and C extensions safer. Remove it, and you need to replace it with fine-grained locking, atomic operations, and thread-safe memory management — all of which have performance implications.
The Python development team, led by Sam Gross’s original no-GIL work, has done an impressive job minimizing the single-threaded performance penalty. In my benchmarks, the free-threaded build runs single-threaded code about 5-10% slower than the standard build. That’s much better than early estimates suggested, but it’s not zero.
Where Free-Threading Shines#
For CPU-bound parallel workloads, the results are genuinely exciting. I tested a data processing pipeline that transforms and validates large CSV files — the kind of ETL work that’s typically done with multiprocessing in Python. With free-threading and the concurrent.futures.ThreadPoolExecutor, I saw near-linear scaling up to 8 cores:
- 1 thread: 45 seconds (vs. 42 seconds with GIL build)
- 4 threads: 12.3 seconds
- 8 threads: 6.8 seconds
Compare this to the standard GIL build where adding threads to CPU-bound work actually makes it slower due to GIL contention. And compared to multiprocessing, free-threading avoids the overhead of serializing data between processes — which can be substantial for large datasets.
Image processing is another natural fit. Using Pillow for batch image resizing and format conversion, free-threading provided a 6.5x speedup on 8 cores compared to single-threaded execution. With multiprocessing, the same workload only achieved 4.2x due to the overhead of passing image data between processes.
Where It Doesn’t (Yet)#
The ecosystem compatibility situation is the main obstacle. Many popular C extensions aren’t yet thread-safe without the GIL. NumPy has made significant progress — their 2.1 release includes initial free-threading support — but it’s still marked as experimental. Pandas, scikit-learn, and many other scientific Python staples don’t officially support free-threading yet.
I hit real issues with SQLAlchemy. While the library itself is working on free-threading compatibility, some of the underlying database drivers aren’t there yet. Connection pooling with free-threading requires careful configuration, and I encountered sporadic segfaults with certain connection patterns. If your application is database-heavy, stick with the standard build for now.
Web frameworks are a mixed bag. Flask and Django both run on the free-threaded build, but their middleware ecosystems haven’t been fully audited. I wouldn’t run a production web service on the free-threaded build today — the risk of subtle thread-safety bugs in third-party middleware is too high.
The Practical Path Forward#
For most Python developers in November 2025, the actionable advice is:
Do try it for: CPU-bound batch processing scripts, data pipelines that don’t depend on incompatible C extensions, and new projects where you control the full dependency stack. These are workloads where you can validate thread safety and where the performance gains are substantial.
Don’t use it for: Production web services, applications with complex C extension dependencies, or anything where a subtle threading bug could cause data corruption. The ecosystem needs another 6-12 months to catch up.
Prepare for it: Even if you’re not using free-threading today, start auditing your code for thread safety. Shared mutable state, global variables modified in request handlers, lazy initialization patterns — these will all become actual bugs when the GIL goes away. The threading module documentation has been updated with guidance on writing GIL-free-compatible code.
The Bigger Picture#
What excites me most about this isn’t the immediate performance gains — it’s what it means for Python’s long-term competitiveness. The GIL has been the standard argument for “Python is too slow for production.” With free-threading, Python can genuinely utilize modern multi-core hardware for CPU-bound work without the awkwardness of multiprocessing.
Combined with the performance improvements we’ve seen in Python 3.11 and 3.12 — the adaptive interpreter, specialization at the bytecode level — Python is getting meaningfully faster with each release. It’ll never match C++ or Rust in raw performance, nor should it try. But narrowing the gap enough that you don’t need to rewrite your hot paths in another language? That’s a game-changer for developer productivity.
My Take#
I’ve been writing Python since the 2.3 days, and the GIL has always been that awkward thing you explain to new developers — “yes, threads exist, but they don’t really work for CPU-bound tasks, use multiprocessing instead, but watch out for the serialization overhead.” It’s been Python’s most enduring footgun.
The free-threaded build in 3.13 is a first step, not a final destination. It’s experimental for a reason. But the direction is right, the implementation is solid, and the performance characteristics are promising. Give it another year for the ecosystem to adapt, and I think we’ll look back at Python 3.13 as the release that finally set Python free from its biggest architectural limitation.
For now, I’m keeping it in my toolkit for specific workloads and watching the ecosystem closely. If you maintain a C extension or a popular library, please start testing with the free-threaded build. The sooner the ecosystem catches up, the sooner we all benefit.
