What curl Does
curl is a command-line tool for transferring data using URLs. It supports HTTP, HTTPS, FTP, FTPS, SFTP, and a dozen other protocols, but its primary use is making HTTP and HTTPS requests. curl sends a request, prints the response body to standard output, and exits — making it trivially composable with other shell tools.
The use cases are broad: fetching a web page to verify it loads, testing a REST API endpoint, downloading a file, checking which HTTP headers a server returns, following a redirect chain to see where a URL ultimately lands, verifying a TLS certificate, or timing how long a server takes to respond. curl does all of these from a single command and is available on Linux, macOS, and Windows without installing anything extra.
Basic GET Requests
The simplest form prints the response body to the terminal:
curl https://example.com
Add -L to follow redirects (many URLs redirect from HTTP to HTTPS, or from a bare domain to www):
curl -L https://example.com
To see only the HTTP response headers without the body, use -I (which sends a HEAD request):
curl -I https://example.com
To see both request and response headers plus the body, use -v (verbose). This is the most useful debugging mode — it shows the TLS handshake, the exact headers sent and received, and the response body:
curl -v https://example.com
Key Flags Reference
| Flag | Purpose |
|---|---|
-L | Follow redirects (up to 30 by default) |
-I | HEAD request — response headers only, no body |
-v | Verbose — show request headers, response headers, TLS handshake |
-s | Silent — suppress progress meter and error messages |
-o FILE | Save response body to FILE |
-O | Save response body using the remote filename from the URL |
-X METHOD | Set HTTP method (GET, POST, PUT, DELETE, PATCH) |
-d DATA | Request body for POST/PUT (implies POST if no -X given) |
-H "Header: value" | Add a request header |
-u user:pass | HTTP Basic Authentication |
-k | Skip TLS certificate verification (insecure — for testing only) |
--max-time N | Abort if the entire transfer takes longer than N seconds |
--connect-timeout N | Abort if the connection cannot be established within N seconds |
-w FORMAT | Print custom output after transfer (e.g. HTTP status code, timing) |
Making POST Requests and Testing APIs
For a form POST, use -d with key=value pairs:
curl -X POST -d "username=alice&password=secret" https://example.com/login
For a JSON API, set the Content-Type header and pass JSON as the body. Use single quotes around the JSON to avoid shell escaping issues:
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_token_here" \
-d '{"name":"Alice","role":"admin"}' \
https://api.example.com/users
To read the request body from a file (useful for large payloads), prefix the filename with @:
curl -X POST -H "Content-Type: application/json" -d @payload.json https://api.example.com/endpoint
Pipe the output through jq to pretty-print JSON responses:
curl -s https://api.example.com/data | jq .
Checking HTTP Status Codes
The -w flag prints custom information after the transfer. The most useful variable is %{http_code}. Combine with -s -o /dev/null to discard the body and print only the status code — useful in scripts:
curl -s -o /dev/null -w "%{http_code}" https://example.com
Other useful -w variables: %{time_total} (total request time in seconds), %{time_connect} (time to TCP connect), %{time_starttransfer} (TTFB — time to first byte), %{size_download} (bytes downloaded), and %{url_effective} (final URL after redirects).
Inspecting TLS Certificates
curl's verbose mode shows the full TLS handshake including the server certificate chain. To check certificate expiry and subject details without parsing verbose output, combine with openssl:
curl -v https://example.com 2>&1 | grep -A 10 "Server certificate"
To test a server that has a self-signed or invalid certificate during development, add -k to skip verification. Never use -k in production scripts — it disables all TLS security.
Frequently Asked Questions
How do I make a POST request with curl?
Use -X POST -d "body": curl -X POST -d "key=value" https://example.com/api. For JSON, add the Content-Type header: curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' https://api.example.com/endpoint. To read the body from a file, use -d @filename.json.
How do I follow redirects with curl?
Add -L: curl -L https://example.com. Without -L, curl stops at the redirect and prints the 301/302 response. With -L, it follows up to 30 redirects. Add -v to see each redirect URL as it follows the chain.
How do I save a file with curl?
Use -o filename to specify the output file: curl -o page.html https://example.com. Or use -O (capital O) to save with the filename from the URL. Add --progress-bar to show a simple progress bar for large downloads instead of the default statistics display.
How do I test an API with curl?
Combine -X for the method, -H for headers, and -d for the body. For a bearer token API: curl -H "Authorization: Bearer token" https://api.example.com/resource. Add -s to suppress the progress meter and pipe to jq for readable JSON output.
What is the difference between curl and wget?
curl is optimized for making HTTP requests and inspecting responses — ideal for API testing, debugging, and scripting HTTP interactions. wget is optimized for downloading files and recursive website mirroring, with built-in support for resuming interrupted transfers. curl outputs to stdout by default; wget saves to files. For HTTP debugging, curl is more powerful. For downloading files in scripts, either works well.
Is curl available on Windows?
Yes. curl has been included as a built-in command in Windows 10 since the April 2018 update and works in both Command Prompt and PowerShell. It is the same binary as the Linux and macOS versions with identical flag support. On older Windows versions, download curl from curl.se or use Windows Subsystem for Linux.