Author here. I forked Requests in mid-2023 because it's effectively frozen, and Python's HTTP capabilities have fallen far behind what the protocols and the ecosystem allow today. The Requests API is great; I didn't want to replace it, I wanted to catch it up.
Three years later, here's where things stand:
HTTP/2 by default, HTTP/3 over QUIC when the server advertises it via Alt-Svc or via DNS HTTPS record. No configuration needed, the client negotiates automatically. This alone accounts for most of the performance difference in practice. A quick benchmark (1000 requests to httpbingo.org/get, reproduction steps in the README)
niquests 0.551s (HTTP/2) aiohttp 1.351s (HTTP/1.1) httpx 2.087s (HTTP/2)
Security defaults that should have been there years ago. OS trust store instead of bundled certifi. Certificate revocation checks via OCSP or CRL. Encrypted Client Hello. Post-quantum key exchange. None of this is exotic anymore - browsers have shipped most of it - but Python clients still don't do it.
DNS. DNS-over-HTTPS, DNS-over-TLS, DNS-over-QUIC, DNSSEC validation. Per-session resolver configuration.
Other things that accumulated over three years: Happy Eyeballs, WebSocket and SSE over all three HTTP versions, in-memory certificates for mTLS, connection-level telemetry (DNS/TCP/TLS timings via response.conn_info), native Unix socket support, and as of 3.18, experimental Pyodide/WASM support.
Migration is boring by design: import niquests as requests. Existing auth flows, cookie jars, .netrc, adapters - they all work. We also maintain compatibility shims for requests-mock, responses, and betamax.
Happy to discuss anything related to the project or HTTP in general.