reqwest: your Cargo.toml features decide whether you have cookies, JSON and a working TLS stack
An easy and powerful Rust HTTP Client
At a glance
- What is it?
- The batteries-included Rust HTTP client, read through its feature graph rather than its feature list: four default features, a TLS fork with two ALPN variants per family, a blocking client that drags in futures utilities, and a published documentation build that enables everything.
- Who is it for?
- Reach for it when you want a client that handles JSON, cookies, proxies and redirects without assembling the pieces yourself, and stay on the default rustls path unless you have a reason not to. Do not read the feature bullet list as a description of what a default build contains.
- Can I use it commercially?
- Yes. Apache-2.0 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 2 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- seanmonstar/reqwest11,926 ★ · +92
| Repository | 2026-09-22 | 2026-11-14 |
|---|---|---|
| seanmonstar/reqwest | 11.8k | 11.9k |
92 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The default feature set is four items and none of them is json
The headline list reads like everything is switched on. It is not. The default set is four entries.
default = ["default-tls", "charset", "http2", "system-proxy"]
default-tls = ["rustls"]So an unqualified dependency gets a TLS stack, character set handling, HTTP/2 and system proxy discovery, and nothing else. JSON is not in that set, which is why the README example has to ask for it explicitly, along with a Tokio runtime for the async entry point.
[dependencies]
reqwest = { version = "0.13", features = ["json"] }
tokio = { version = "1", features = ["full"] }Two consequences follow. First, copying a snippet that calls .json() into a project that wrote its dependency without the json feature gets you a compile error rather than a silent fallback. Second, and more awkward in a workspace, Cargo generally unifies features for the same resolved package, but resolver and target contexts can keep them separate; inspect `cargo tree -e features` to see what is enabled. The declared floor is edition 2021 with rust-version 1.85.0, so the compiler requirement is fixed and public, and the include list restricts what ships in the published crate to the README, the manifest, both licenses and the Rust sources under src.
Cookies and decompression are opt-in, so a default build silently omits them
A cookie store appears in the feature list as a capability, but the feature that provides it is not a default. Neither is any of the compression formats. Each is a separate dependency edge that has to be requested.
cookies = ["dep:cookie_crate", "dep:cookie_store"]
gzip = ["tower-http/decompression-gzip"]brotli and zstd follow the same shape as gzip, each enabling a decompression layer on the tower-http stack. Since these features are additive within a build graph, checking the merged feature set of your workspace rather than the dependency line you wrote is the only way to know what is actually present.
native-tls on Linux takes OpenSSL from the system or fails the build outright
Choosing the operating system TLS stack moves the hard part off your toolchain and onto your machine. With the native-tls feature enabled, the platform framework is used where one exists, which the requirements section names as Windows and macOS. Linux is the different case: there the crate looks for OpenSSL already installed on the system, and if it does not find it, the build fails. That is the one hard failure in the whole configuration story, and it happens at compile time on a machine you may not control. There is an escape hatch with a cost: native-tls-vendored compiles a copy of OpenSSL instead of searching for one, which trades a missing dependency for a longer build.
native-tls = ["__native-tls", "__native-tls-alpn"]
native-tls-vendored = ["__native-tls", "native-tls-crate?/vendored", "__native-tls-alpn"]The default avoids the whole question by routing through rustls, which brings no system library requirement at all. The choice you make on a developer laptop is not necessarily the choice that works on a build agent or a container image, and that difference is invisible until the build runs somewhere else. Nothing in the crate negotiates this for you at runtime, so the decision belongs in the manifest, where it is visible to everyone reviewing the build.
Each TLS family ships an ALPN variant and a no-ALPN twin
Look at the feature names and the same decision appears four times over. rustls and rustls-no-provider both enable the platform verifier and the internal rustls dependency, but the plain rustls feature additionally pulls in the aws-lc-rs provider. On the native side, native-tls and native-tls-no-alpn differ only by the ALPN entry, and the vendored pair repeats the split with the vendored flag added.
rustls = ["__rustls-aws-lc-rs", "dep:rustls-platform-verifier", "__rustls"]
rustls-no-provider = ["dep:rustls-platform-verifier", "__rustls"]
native-tls = ["__native-tls", "__native-tls-alpn"]
native-tls-no-alpn = ["__native-tls"]ALPN is how a client advertises which protocols it will speak over a TLS connection, and the no-ALPN forms exist for the case where you want the TLS stack without negotiating HTTP/2 through it. The practical reading is that picking a TLS feature is rarely one decision. You are choosing a family, a provider or vendoring strategy, and a protocol negotiation behaviour, and the four combinations are spelled out in the manifest rather than behind a simpler name. Choosing the default rustls path takes the provider automatically; the no-provider form leaves that choice to you and will not work as a drop-in replacement unless you already have a provider.
The blocking Client is not free, it pulls in futures utilities and tokio/sync
Two client types are offered, async and blocking, which reads like a free choice of style. The feature graph says otherwise.
blocking = ["dep:futures-channel", "futures-channel?/sink", "dep:futures-util", "futures-util?/io", "futures-util?/sink", "tokio/sync"]Six edges are switched on, five of them into the futures ecosystem, and the last one wires into tokio. So a project that reaches for the blocking client to avoid an async runtime still ends up compiling parts of one, which undercuts the usual reason for wanting a synchronous API in the first place. The blocking example lives in examples/blocking.rs alongside form.rs, json_typed.rs, json_dynamic.rs, simple.rs, h3_simple.rs, tor_socks.rs and connect_via_lower_priority_tokio_runtime.rs, which is a reasonable map of what the crate is built for. But the examples directory does not tell you which of those need a feature you have not enabled.
docs.rs compiles with all features plus two unstable cfg flags
The documentation you read online is not built from your dependency line. The manifest sets all-features for docs.rs and passes two cfg values into rustdoc.
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs", "--cfg", "reqwest_unstable"]
targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]Every feature is on there, including every TLS family, so the published pages describe an API surface larger than any single real build produces. More pointed for a reader: an item documented there may sit behind the reqwest_unstable cfg, and you are not passing that flag unless you set it yourself, so something visible on docs.rs can be absent from your build without producing an error message that explains why. Two targets are generated, the Linux host and wasm32-unknown-unknown, which matches the WASM line in the feature list but means anything platform-specific to other targets has no rendered documentation at all. The consequence for anyone learning the crate from those pages is that the docs answer what the API can be, not what it is in the configuration you actually depend on.
The playground turns on six features your Cargo.toml does not have
There is a third build configuration on top of yours and docs.rs, and it is the one that sends you down a wrong path. The playground metadata enables six features.
[package.metadata.playground]
features = [
"blocking",
"cookies",
"query",
"form",
"json",
"multipart",
]Compare that with the four-item default set: the playground adds blocking, cookies, query, form, json and multipart. Code that runs in the playground therefore exercises cookie handling, form encoding and multipart uploads that your project has not opted into, and a snippet copied out of it fails to compile on a dependency line that never asked for them. The README example demonstrates the shape of the failure, since it declares features itself rather than relying on defaults.
reqwest = { version = "0.13", features = ["json"] }The last piece of context is the release timeline. The crate sits at 0.13.5, published 2026-09-08 after 0.13.4 in May and 0.13.3 in April, and the last push to the repository was on 2026-10-19, so the manifest you are reading corresponds to a line that is still moving.
Editorial conclusion
Reach for it when you want a client that handles JSON, cookies, proxies and redirects without assembling the pieces yourself, and stay on the default rustls path unless you have a reason not to. Do not read the feature bullet list as a description of what a default build contains. Before you commit, check which of your dependencies pull optional features into your build, decide your TLS family on the platform you deploy to rather than the one you develop on, and confirm your compiler meets the stated 1.85.0 floor.
Frequently asked questions
What is Reqwest?
An ergonomic, batteries-included HTTP client for Rust, offering async and blocking clients, plain bodies alongside JSON, urlencoded and multipart, a customizable redirect policy, HTTP proxies, HTTPS through rustls or optionally the system TLS stack, a cookie store and WASM support.
Is reqwest asynchronous?
Both. There are async and blocking Client types, and the README example is asynchronous and runs on Tokio. The blocking feature is what enables the blocking client, and it pulls in futures-channel, futures-util and tokio/sync.
Can reqwest handle cookies?
Yes, a cookie store is one of its capabilities, but the cookies feature is not in the default set of default-tls, charset, http2 and system-proxy. Enabling it pulls in the cookie_crate and cookie_store dependencies.
reqwest vs hyper
The repository sets out no comparison with hyper. What the manifest shows is that hyper sits underneath: the http2 feature enables hyper/http2, hyper-util/http2 and hyper-rustls?/http2 along with the h2 dependency, so reqwest is a higher level client layered over that stack.
Official sources
Where developers are discussing it
Posts on Hacker News, dev.to and Lobsters that link to this repository, found by our scan of those communities. 1 in the last 30 days; newest first.
- Renting Out One T4 to Three Customers: Gemma 4, vLLM Multi-LoRA and a Rust Gatewaydev.to · Oct 16, 2026 · 2 points · 0 comments
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/seanmonstar-reqwest)Star history chart for your README
[](https://hysenlabs.com/projects/seanmonstar-reqwest)Was this useful?