What is the curl command?
Max Rozen / Published: January 08, 2025
Last updated: January 25, 2025
curl is one of those programs that feels like its always been there for you in a pinch, like when you're trying to debug what your API is doing, and yet we never take the time to actually learn how to use it (I only ever used it via "copy as curl" from my browser's devtools, prior to writing this article).
It's insanely powerful too, run curl --help all
to see what I mean.
In this article, we're going to take the time to learn what we can do with a tiny subset of curl's options, so we don't have to look them up every time.
Not a fan of reading? Generate a curl command instead.
Table of contents
- What is curl?
- curl examples
- How to make a curl request
- How to save curl output to a file
- How to make a POST request with curl
- How to POST custom headers with curl
- How to POST JSON data with curl
- How to POST a JSON file with curl
- How to change the user-agent header curl uses
- How to follow redirects with curl
- How to see the full HTTP request and response
- How to handle cookies with curl
- How to simulate different HTTP methods
- How to handle authentication methods with curl
- How to handle file uploads
- How to time your requests
- Putting it all together
- Common curl command patterns
What is curl?
curl is an open-source program that lets you transfer data to, or from a server, using URLs. If you've used it before, chances are you were just checking if an HTTP API was responding with the data you expected it to - but it supports a lot more than just HTTP.
Excerpt from man curl
:
curl is a tool for transferring data from or to a server using URLs. It supports these protocols: DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS.
That being said, in this article we're just going to learn how to use curl with HTTP, because that's already a challenge.
curl examples
Here are some examples of how to make requests with curl.
We'll be using https://echo.onlineornot.com - a free API that returns your request data back to you (useful for verifying your curl command does what you expect).
How to make a curl request
At its simplest, you can give curl any URL, and it will show you what's at that URL via a GET request:
curl https://echo.onlineornot.com
(see this example in our curl generator) and you get a response:
{ "method": "GET", "pathname": "/", "searchParams": {}, "headers": { "accept": "*/*", "accept-encoding": "gzip, br", "connection": "Keep-Alive", "host": "echo.onlineornot.com", "user-agent": "curl/8.7.1" }, "body": "", "powered-by": "https://onlineornot.com"}
As I mentioned earlier, if you don't specify the HTTP method you want to use, by default curl will send a GET request. If you want to send a POST request, you'll need to provide an additional flag, as shown below.
How to save curl output to a file
There are two ways to save curl's output to a file, instead of displaying the result in your terminal:
- Using the
-o
flag
For example:
curl -o output.json https://echo.onlineornot.com
(see this example in our curl generator) this creates a file in the same directory as where I ran the command, with the contents:
{ "method": "GET", "pathname": "/", "searchParams": {}, "headers": { "accept": "*/*", "accept-encoding": "gzip, br", "connection": "Keep-Alive", "host": "echo.onlineornot.com", "user-agent": "curl/8.7.1" }, "body": "", "powered-by": "https://onlineornot.com"}
- Using STDIN redirection (the
>
character)
For example:
curl https://echo.onlineornot.com > output.json
This creates the same output.json as before.
How to make a POST request with curl
You can specify the HTTP method using the -X
flag, like so:
curl -X POST https://echo.onlineornot.com
(see this example in our curl generator) which outputs the following in our terminal:
{ "method": "POST", "pathname": "/", "searchParams": {}, "headers": { "accept": "*/*", "accept-encoding": "gzip, br", "connection": "Keep-Alive", "host": "echo.onlineornot.com", "user-agent": "curl/8.7.1" }, "body": "", "powered-by": "https://onlineornot.com"}
POST requests are cool and all, but they're not much use to the APIs you're using if you can't authenticate, or tell the API which format the data you're sending it is in.
How to POST custom headers with curl
You can provide headers to the curl command using the -H
or --header
flag, like so:
# we've used the backslash (\) below to split# the command across multiple linescurl -H 'Content-Type: application/json' \ -X POST https://echo.onlineornot.com
(see this example in our curl generator) which outputs the following in our terminal:
{ "method": "POST", "pathname": "/", "searchParams": {}, "headers": { "accept": "*/*", "accept-encoding": "gzip, br", "connection": "Keep-Alive", "content-type": "application/json", "host": "echo.onlineornot.com", "user-agent": "curl/8.7.1" }, "body": "", "powered-by": "https://onlineornot.com"}
To add multiple headers, you'll need to add additional -H
flags, like so:
curl -H 'Content-Type: application/json' \ -H 'Authorization: Bearer a_real_token_goes_here' \ -X POST https://echo.onlineornot.com
Now that we've provided an Authorization
header and a Content-Type
header, we can send data to most APIs (that support JSON data, anyway).
How to POST JSON data with curl
In case you're wondering:
but when would I send data TO an API?
You would typically send data to an API when creating or updating records.
You can send data with your request using the -d
or --data
flag, like so:
curl -H 'Content-Type: application/json' \ -H 'Authorization: Bearer a_real_token_goes_here' \ -d '{"name": "My website", "url": "https://onlineornot.com"}' \ -X POST https://echo.onlineornot.com
(see this example in our curl generator) which outputs the following in our terminal:
{ "method": "POST", "pathname": "/", "searchParams": {}, "headers": { "accept": "*/*", "accept-encoding": "gzip, br", "authorization": "Bearer a_real_token_goes_here", "connection": "Keep-Alive", "content-length": "56", "content-type": "application/json", "host": "echo.onlineornot.com", "user-agent": "curl/8.7.1" }, "body": "{\"name\": \"My website\", \"url\": \"https://onlineornot.com\"}", "powered-by": "https://onlineornot.com"}
How to POST a JSON file with curl
You can also send files with curl using the -d
flag as in the previous example, and adding @
in front of the file path.
For example, if I was in a directory containing a file called my_data.json
, I could use:
curl -H 'Content-Type: application/json' \ -H 'Authorization: Bearer a_real_token_goes_here' \ -d @my_data.json \ -X POST https://echo.onlineornot.com
(in this case, I've put the data from the previous example into my_data.json
), which outputs the following in our terminal:
{ "method": "POST", "pathname": "/", "searchParams": {}, "headers": { "accept": "*/*", "accept-encoding": "gzip, br", "authorization": "Bearer a_real_token_goes_here", "connection": "Keep-Alive", "content-length": "56", "content-type": "application/json", "host": "echo.onlineornot.com", "user-agent": "curl/8.7.1" }, "body": "{\"name\": \"My website\", \"url\": \"https://onlineornot.com\"}", "powered-by": "https://onlineornot.com"}
How to change the user-agent header curl uses
By default, curl will use the following user-agent header for sending requests: curl/{version_number_here}
For all of the requests in this article, curl has been sending the default user-agent (in my case, curl/8.7.1
).
If you're building your own tool that fetches URLs on top of curl, you might want to customize the user-agent header curl sends. You can do that by passing a user-agent
header, as in the how to post custom headers with curl example above:
curl -H 'user-agent: testing-echo' \ https://echo.onlineornot.com
(see this example in our curl generator) which outputs the following in our terminal:
{ "method": "GET", "pathname": "/", "searchParams": {}, "headers": { "accept": "*/*", "accept-encoding": "gzip, br", "connection": "Keep-Alive", "host": "echo.onlineornot.com", "user-agent": "testing-echo" }, "body": "", "powered-by": "https://onlineornot.com"}
How to follow redirects with curl
By default, curl won't automatically follow redirects (when a website sends you to a different URL). You can enable this with the -L
or --location
flag:
curl -L https://echo.onlineornot.com/redirect
This is particularly useful when working with URLs that might redirect you to a login page or a different domain.
How to see the full HTTP request and response
When debugging APIs, it's often useful to see exactly what curl is sending and receiving. The -v
(verbose) flag shows you the complete HTTP conversation:
curl -v https://echo.onlineornot.com
This will show you:
- DNS lookup details
- TLS/SSL handshake information
- Request headers sent
- Response headers received
- The response body
How to handle cookies with curl
Building on our knowledge of headers, sometimes you need to handle cookies. You can:
- Send a cookie:
curl -H "Cookie: session=123abc" https://echo.onlineornot.com
- Save received cookies to a file:
curl -c cookies.txt https://echo.onlineornot.com
- Use saved cookies in a request:
curl -b cookies.txt https://echo.onlineornot.com
How to simulate different HTTP methods
We've covered GET and POST, but REST APIs often use other HTTP methods. Here's how to use them:
# PUT requestcurl -X PUT -H "Content-Type: application/json" \ -d '{"name": "Updated website"}' \ https://echo.onlineornot.com
# DELETE requestcurl -X DELETE https://echo.onlineornot.com/resource/123
# PATCH requestcurl -X PATCH -H "Content-Type: application/json" \ -d '{"name": "Partial update"}' \ https://echo.onlineornot.com
How to handle authentication methods with curl
Building on our earlier Authorization header example, here's how to handle different auth methods:
- Basic Auth (username/password):
curl -u username:password https://echo.onlineornot.com
- Bearer token (as shown above):
curl -H "Authorization: Bearer a_real_token_goes_here" https://echo.onlineornot.com
- API Key in query string:
curl "https://echo.onlineornot.com?api_key=a_real_token_goes_here"
How to handle file uploads
For APIs that accept file uploads, you can use the -F
flag for form data:
# Upload a single filecurl -F "file=@local-file.pdf" https://echo.onlineornot.com/upload
# Upload multiple files with additional form fieldscurl -F "files[]=@file1.pdf" \ -F "files[]=@file2.pdf" \ -F "description=My files" \ https://echo.onlineornot.com/upload
How to time your requests
When working with APIs, you often want to know how long requests take. The -w
flag lets you format timing data:
curl -w "\nTime taken: %{time_total}s\n" https://echo.onlineornot.com
You can get detailed timing metrics with this format string:
curl -w "\ Time DNS lookup: %{time_namelookup}s\n\ Time to connect: %{time_connect}s\n\ Time to first byte: %{time_starttransfer}s\n\ Total time: %{time_total}s\n" \ https://echo.onlineornot.com
Putting it all together
Here's an example that combines multiple concepts we've learned:
curl -v -L \ -H "Content-Type: application/json" \ -H "Authorization: Bearer a_real_token_goes_here" \ -d '{"name": "Complex request"}' \ -w "\nTotal time: %{time_total}s\n" \ https://echo.onlineornot.com/api/v1/resource
This command:
- Shows verbose output (-v)
- Follows redirects (-L)
- Sets content type and auth headers
- Sends JSON data
- Shows timing information
- Makes a POST request (implied by -d)
Common curl command patterns
To wrap up, here are some common patterns you might use in your day-to-day work:
- API testing:
curl -v -H "Authorization: Bearer a_real_token_goes_here" https://echo.onlineornot.com
- Download a file:
curl -L -o output.zip https://echo.onlineornot.com/file.zip
- API creation request:
curl -X POST \ -H "Content-Type: application/json" \ -H "Authorization: Bearer token" \ -d @create-payload.json \ https://echo.onlineornot.com/resource
Remember, you can always combine these patterns and flags to build the exact curl command you need for your use case.