In this episode we'll explore modern curl 8.x features: the --json and --oauth2-bearer shorthands, WebSocket, HTTP/3, parallel transfers, thorough retry, clean output, and --libcurl, while understanding the monthly release rhythm and disciplined security focus.

In episode 18, you learned to dissect failed requests — now we switch to the opposite direction: leveraging the best capabilities curl currently offers. Since its rebirth as the 8.x series in 2023, curl has changed from a "stable classic tool" into a project continuously delivering modern features with a very disciplined monthly release rhythm.
Why should you care about the latest releases? Two reasons. First, modern features save time: a single --json flag replaces three manual flags, and --parallel runs several requests at once without writing a loop. Second, security: the latest releases bring CVE fixes worth adopting — a topic we'll explore in depth in episode 21. Episode 19 is a tour of features that are stable and deserve a place in your daily workflow.
curl 8.x runs on a consistent pattern: one release per month, minor version bumps by one, and serious security handling — if there's a CVE, the fix ships quickly and is documented as an official advisory. Since mid-2026, the 8.x series has gone through dozens of releases, and a number of network features that were once experimental were finally declared stable in the 8.19–8.21 series.
Check the curl version on your machine first:
curl --versionNote two important lines in the output: Protocols and Features. In the Features line, you can see whether your build includes HTTP3, websockets, brotli, and others. Features not in that list can't be used — even if the flag option is typed correctly.
--json: All the Boilerplate in One FlagIn episode 6, you met --json as a replacement for three flags at once: the POST method, the Content-Type: application/json header, and the payload. Here's the comparison once more:
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "Budi", "email": "budi@example.com"}'Those two requests are identical. --json also accepts payloads from a file with the @ prefix, for example curl --json @payload.json. The benefit isn't just being shorter, but having fewer places for typos — and every shorter request is one bug opportunity removed.
--oauth2-bearer: The Right Auth HeaderSending a Bearer token manually means writing -H "Authorization: Bearer <token>" on every request. --oauth2-bearer does the same with one descriptive flag:
curl --oauth2-bearer "$TOKEN" https://api.example.com/meNotice the token comes from the $TOKEN environment variable, not hard-coded in the command — a habit we'll reinforce in episode 21. --oauth2-bearer is identical to -H "Authorization: Bearer $TOKEN", but easier to read for the team members maintaining your scripts later.
--wsWebSocket enables persistent two-way communication — not the one-shot request-response of regular HTTP. curl 8.x supports it via the --ws flag: curl performs the WebSocket handshake, then exchanges message frames interactively.
curl --ws wss://stream.example.com/liveAfter the connection forms, whatever you type is sent as a message, and responses arrive in real time until the connection closes. This is very useful for testing streaming feeds or debugging chat protocols. Keep in mind: WebSocket support in curl is still marked experimental — make sure your build includes the websockets feature (see curl --version), and test in a non-production environment first.
--http3HTTP/3 is the HTTP evolution running on QUIC — a protocol built on UDP, not TCP. Its main advantage is eliminating head-of-line blocking: in HTTP/2, one lost packet can hold up the whole stream; in HTTP/3, each stream is independent so one disruption doesn't hold back the others.
curl --http3 https://example.comcurl --http3-only https://example.com--http3 tries HTTP/3 and drops to HTTP/2 or HTTP/1.1 if unsupported; --http3-only forces it and fails if the server doesn't support it. Like WebSocket, HTTP/3 needs a curl build that includes it — if Features in curl --version doesn't contain HTTP3, this feature won't run. For servers behind modern CDNs, try comparing the timing with -w from episode 18; the difference can be surprising.
-Z, --parallelA for loop in a script sends requests one at a time, sequentially. --parallel (alias -Z) makes curl send many URLs concurrently in a single process, with connections capped by --parallel-max (default 50).
curl -Z -o /dev/null \
https://api.example.com/users \
https://api.example.com/posts \
https://api.example.com/commentsImagine three cashiers serving three queues at once, not one cashier serving them one by one. For scripts testing many endpoints or fetching many files, this parallelism cuts execution time drastically without writing additional complexity.
--retry-all-errorsBy default, curl only retries errors considered temporary (like timeouts or connection resets). --retry-all-errors extends that to almost all transfer failures:
curl --retry 5 --retry-delay 2 --retry-all-errors \
https://cdn.example.com/big-file.zip -o big-file.zipThis combination says: try up to 5 times, pause 2 seconds between attempts, and don't give up on any transfer error. This isn't a license to be careless — still set a bound (--retry) so scripts don't hang forever. Retry is an acknowledgment that networks are fragile; --retry-all-errors is the way to face it patiently but with discipline.
--output-dir and --remove-on-errorTwo small flags that prevent big messes:
curl --output-dir ./downloads --remove-on-error -O \
https://cdn.example.com/reports/latest.zip--output-dir places all downloaded files into a specific directory, so your working folder isn't littered with random files. --remove-on-error deletes files that failed to download completely — preventing partial files from being silently treated as complete by your scripts. A half-downloaded file is a time bomb: its size is right, but its contents are corrupt. These flags kill that bomb early.
--libcurl: Opening the Door to COne of the most understated but most useful features is --libcurl. With a single flag, curl writes the entire request you ran as equivalent C source code using libcurl:
curl --libcurl request.c https://api.example.com/usersThe generated request.c file is the perfect starting point for learning the libcurl API — and that's exactly what we'll dissect in episode 20. No need to write C from scratch: just run the curl you already understand, then let it write out the library version.
Tip
For quick exploration of all modern options, run curl --help all then grep the keywords, for example curl --help all | grep -A1 ws to learn the WebSocket options. Full documentation is also available online at curl's official site — always consult it before using experimental features.
Episode 19 introduced the modern curl 8.x features ready for daily use: --json to simplify JSON requests, --oauth2-bearer for token authentication, WebSocket with --ws, HTTP/3 with --http3, parallel transfers with -Z, thorough retry with --retry-all-errors, clean download management with --output-dir and --remove-on-error, and the bridge to C via --libcurl.
The consistent pattern behind all these features: curl keeps evolving, and you must keep following. Monthly releases mean new features arrive fast — and so do security fixes.
In the next episode 20, we'll open the hood: libcurl and programming language integration — how the library behind curl works through curl_easy and curl_multi, the cross-language binding ecosystem, and how to start embedding curl into your own applications. See you!