curl
Transfer data to/from a URL over many protocols
By CMD Script Team · 4 min read · Last updated
curl [OPTIONS] URL...Options
| Flag | Description |
|---|---|
-O | Save output to a local file using the remote file's name |
-L | Follow HTTP redirects (3xx responses) |
-X | Set the HTTP request method, e.g. -X POST |
-H | Add a custom request header, e.g. -H 'Content-Type: application/json' |
-d | Send data in the request body (implies POST unless -X overrides it) |
-I | Fetch headers only, using an HTTP HEAD request |
-s | Silent mode, suppress the progress meter and error messages |
-v | Verbose mode, show the full request/response exchange |
Distribution compatibility
- Ubuntu
- Debian
- Fedora
- Arch
- macOS
What it does
curl (Client URL) transfers data to or from a server using any of a huge number of
supported protocols — HTTP, HTTPS, FTP, SFTP, and more — from the command line. It's
the standard tool for scripting HTTP requests: testing APIs, downloading files,
checking response headers, or debugging web services, and it exposes fine-grained
control over methods, headers, and request bodies that makes it a staple of both
development and operations work.
Beginner examples
curl https://example.com— fetch a URL and print the response body to stdoutcurl -O https://example.com/file.zip— download a file, saving it under its remote namecurl -I https://example.com— fetch only the response headerscurl -L https://example.com— follow redirects to reach the final URL
curl -o page.html https://example.com
Advanced examples
- Send a POST request with a JSON body:
curl -X POST -H "Content-Type: application/json" -d '{"name":"alice"}' https://api.example.com/users - Add an authorization header for an API call:
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/me - Submit form data:
curl -X POST -d "username=alice&password=secret" https://example.com/login - Save a download while following redirects:
curl -L -O https://example.com/latest-release - Time a request's phases for performance debugging:
curl -w "%{time_total}\n" -o /dev/null -s https://example.com
curl -sSL -X GET -H "Accept: application/json" https://api.example.com/status
Common mistakes
- Forgetting
-Land being confused why a redirected URL "didn't work" — curl prints the redirect response instead of following it unless told to. - Using
-dwithout realizing it implicitly switches the request to POST, which can be surprising when you only meant to attach data to a GET. - Not quoting JSON bodies properly in the shell, leading to broken quotes/escaping —
wrapping the JSON in single quotes (and using
\"inside if needed) avoids most of this. - Assuming
curl -Orespects a custom filename — it always uses the remote URL's basename; use-o filenamewhen you need control over the local name.
Tips
- Add
-sin scripts to suppress the progress meter, and pair it with-S(-sS) to still show errors even in silent mode. - Use
-vwhen a request behaves unexpectedly — it prints the full request and response headers, revealing redirects, auth failures, or unexpected content types. curl -wwith a format string can extract specific metrics (status code, total time, size) for lightweight scripted health checks.
Best practices
- Always check the HTTP status code in scripts (
curl -o /dev/null -s -w "%{http_code}\n" URL) rather than assuming a request succeeded just because curl didn't error. - Prefer
-H "Authorization: Bearer $TOKEN"over embedding secrets in URLs, which can leak into logs and shell history. - Use
--fail(-f) in scripts so curl returns a non-zero exit code on HTTP error responses (4xx/5xx) instead of silently succeeding with an error page as the body.
Try it yourself
A simulated shell with a sample home directory — experiment freely, nothing leaves your browser. Type help to list supported commands.
Real-world use cases
- Testing and debugging REST APIs during development, sending custom methods, headers, and bodies without needing a full HTTP client library.
- Downloading release artifacts, container base images, or installers inside Dockerfiles and CI pipelines.
- Health-checking a service endpoint in a monitoring script by checking the returned HTTP status code.
Common interview questions
- How do you send a POST request with a JSON payload using curl?
curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' URL— the header declares the body format and-dsupplies the payload. - How would you make curl fail (non-zero exit code) on an HTTP error response?
Add
-f/--fail, which makes curl return an error instead of printing the server's error page as if it succeeded. - What's the difference between -o and -O?
-o filenamesaves output under a name you choose;-Osaves it using the remote URL's own filename.
Frequently Asked Questions
What's the difference between curl -O and curl -o?
curl -O saves the downloaded file using the same name as in the URL; curl -o filename lets you choose the local filename explicitly.
How do I send a JSON POST request with curl?
curl -X POST -H 'Content-Type: application/json' -d '{"name":"alice"}' https://api.example.com/users — the -H sets the content type and -d supplies the JSON body.
How do I see just the HTTP response headers without the body?
curl -I https://example.com sends a HEAD request and prints only the response headers, useful for checking status codes, redirects, or content type quickly.
Why didn't curl follow a redirect?
By default curl does not follow 3xx redirects; add -L to make it follow them automatically to the final destination URL.
Cheat sheet
Download a quick-reference cheat sheet for curl.