What is the curl command?

Max Rozen

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 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:

  1. 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"
}
  1. 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 lines
curl -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:

  1. Send a cookie:
curl -H "Cookie: session=123abc" https://echo.onlineornot.com
  1. Save received cookies to a file:
curl -c cookies.txt https://echo.onlineornot.com
  1. 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 request
curl -X PUT -H "Content-Type: application/json" \
-d '{"name": "Updated website"}' \
https://echo.onlineornot.com
# DELETE request
curl -X DELETE https://echo.onlineornot.com/resource/123
# PATCH request
curl -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:

  1. Basic Auth (username/password):
curl -u username:password https://echo.onlineornot.com
  1. Bearer token (as shown above):
curl -H "Authorization: Bearer a_real_token_goes_here" https://echo.onlineornot.com
  1. 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 file
curl -F "file=@local-file.pdf" https://echo.onlineornot.com/upload
# Upload multiple files with additional form fields
curl -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:

  1. API testing:
curl -v -H "Authorization: Bearer a_real_token_goes_here" https://echo.onlineornot.com
  1. Download a file:
curl -L -o output.zip https://echo.onlineornot.com/file.zip
  1. 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.

Reliable uptime monitoring for your business,
in just 30 seconds.
Get started for free

No credit card required.