How to Use Curl — Command Line HTTP Client Guide
What is Curl?
curl (Client URL) is a command-line tool and library for transferring data using various network protocols. Originally developed by Daniel Stenberg in 1997, curl has become the de facto standard for making HTTP requests from the terminal. It is installed by default on most Unix-based systems (Linux, macOS) and is available for Windows via WSL, PowerShell, or direct downloads.
Curl supports a wide range of protocols including HTTP, HTTPS, FTP, SFTP, SCP, LDAP, SMTP, POP3, and many more. It is widely used for API testing, automation scripts, CI/CD pipelines, and debugging network services.
Basic Syntax
The fundamental syntax of a curl command is:
curl [options] URL[options]— One or more command-line flags that control the behavior (method, headers, data, etc.)URL— The target Uniform Resource Locator
If no options are provided, curl performs a GET request and outputs the response body to the terminal:
curl https://api.example.com/usersGET Requests
The simplest curl command performs an HTTP GET request. The response body is printed to stdout:
curl https://jsonplaceholder.typicode.com/posts/1You can combine GET requests with query parameters directly in the URL:
curl "https://api.example.com/users?page=2&limit=10"View Response Headers
Use the -i flag to include the HTTP response headers in the output:
curl -i https://api.example.com/usersSend Custom Headers
Use -H to add custom HTTP headers to the request:
curl -H "Accept: application/json" https://api.example.com/usersMultiple headers can be supplied by repeating -H:
curl -H "Accept: application/json" -H "Authorization: Bearer token123" https://api.example.com/usersPOST Requests with JSON Data
To send a POST request with a JSON payload, combine -X POST with the -d (data) flag and the Content-Type: application/json header:
curl -X POST \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}' \
https://api.example.com/usersSending Data from a File
When the JSON payload is large, read it from a file using the @ prefix:
curl -X POST \
-H "Content-Type: application/json" \
-d @payload.json \
https://api.example.com/usersURL-Encoded Form Data
For sending form data (application/x-www-form-urlencoded), omit the Content-Type header — curl adds it automatically:
curl -X POST -d "name=Alice&email=alice@example.com" https://api.example.com/usersPUT and PATCH Requests
The -X flag supports any HTTP method:
# PUT — full replacement
curl -X PUT \
-H "Content-Type: application/json" \
-d '{"name": "Alice Updated"}' \
https://api.example.com/users/1
# PATCH — partial update
curl -X PATCH \
-H "Content-Type: application/json" \
-d '{"name": "Alice Partial"}' \
https://api.example.com/users/1DELETE Requests
curl -X DELETE https://api.example.com/users/1Query Parameters
Query parameters can be appended directly to the URL. For complex queries, use the -G flag with -d to let curl build the query string:
# Manual query string
curl "https://api.example.com/search?q=curl&page=1&sort=desc"
# Using -G and -d (curl builds the query string)
curl -G \
-d "q=curl" \
-d "page=1" \
-d "sort=desc" \
https://api.example.com/searchThe -G approach handles URL encoding automatically, which is useful when parameters contain special characters.
File Uploads
Use the -F (form) flag to upload files as multipart/form-data:
curl -X POST \
-F "file=@/path/to/document.pdf" \
-F "description=Annual Report" \
https://api.example.com/uploadMultiple File Uploads
curl -X POST \
-F "images=@photo1.jpg" \
-F "images=@photo2.jpg" \
-F "images=@photo3.jpg" \
https://api.example.com/galleryCustom Filename in Upload
You can override the filename sent to the server:
curl -F "file=@local-file.pdf;filename=report-2026.pdf" https://api.example.com/uploadFollow Redirects (-L)
Many endpoints redirect to a different URL (HTTP 3xx responses). By default, curl does not follow redirects — it prints the redirect response. Use -L (or --location) to follow redirects automatically:
curl -L https://bit.ly/some-linkCurl follows up to 50 redirects by default. Limit the number with --max-redirs:
curl -L --max-redirs 5 https://example.com/redirect-chainSave Output (-o)
By default, curl prints the response body to stdout. To save it to a file, use -o (lowercase) with a filename:
curl -o response.json https://api.example.com/usersUse -O (uppercase) to save using the remote filename:
curl -O https://example.com/files/document.pdfThis is equivalent to downloading a file and preserving its original name.
Verbose Mode (-v)
The -v (verbose) flag prints detailed information about the request and response, including:
- Connection details (DNS resolution, TCP handshake, TLS negotiation)
- Request headers sent
- Response headers received
- SSL certificate information
curl -v https://api.example.com/usersSilent Mode
Conversely, -s (silent) suppresses the progress meter and error messages. Combine with -S to show errors only:
# Completely silent
curl -s https://api.example.com/users
# Silent but show errors
curl -sS https://api.example.com/usersAuthentication (-u)
Curl supports HTTP Basic authentication with the -u flag:
curl -u username:password https://api.example.com/protectedTo avoid exposing credentials in the process list, use a prompt by omitting the password:
curl -u username https://api.example.com/protected
# curl will prompt for the password interactivelyBearer Token Authentication
For Bearer tokens (commonly used with JWTs), use the Authorization header:
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." https://api.example.com/protectedOAuth 2.0 — Client Credentials
curl -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=abc&client_secret=xyz" \
https://auth.example.com/tokenCommon Flags Reference
| Flag | Long Form | Description | Example |
|---|---|---|---|
-X |
--request |
HTTP method | -X POST |
-d |
--data |
Request body data | -d '{"key":"val"}' |
-H |
--header |
Custom HTTP header | -H "Content-Type: application/json" |
-F |
--form |
Multipart form data | -F "file=@photo.jpg" |
-L |
--location |
Follow redirects | -L https://bit.ly/abc |
-o |
--output |
Write to file | -o output.json |
-O |
--remote-name |
Write using remote filename | -O https://example.com/file.pdf |
-v |
--verbose |
Detailed request/response info | -v https://api.example.com |
-s |
--silent |
Suppress progress/errors | -s https://api.example.com |
-S |
--show-error |
Show errors with -s | -sS https://api.example.com |
-u |
--user |
Basic auth credentials | -u user:pass |
-k |
--insecure |
Skip TLS verification | -k https://self-signed.example.com |
-i |
--include |
Include response headers | -i https://api.example.com |
-I |
--head |
Fetch headers only (HEAD) | -I https://api.example.com |
-c |
--cookie-jar |
Write cookies to file | -c cookies.txt |
-b |
--cookie |
Send cookies from file | -b cookies.txt |
--max-time |
— | Max seconds for transfer | --max-time 30 |
--connect-timeout |
— | Max seconds for connection | --connect-timeout 10 |
--retry |
— | Retry count on failure | --retry 3 |
--retry-delay |
— | Seconds between retries | --retry-delay 5 |
-A |
--user-agent |
User-Agent header | -A "Mozilla/5.0" |
-T |
--upload-file |
Upload file (PUT) | -T file.txt https://example.com/ |
-z |
--time-cond |
Conditional download | -z "2026-01-01" |
SSL and Certificate Options
Skip TLS Verification (Testing Only)
For development environments with self-signed certificates:
curl -k https://self-signed.local/apiSpecify Client Certificate
curl --cert client.pem --key client-key.pem https://api.example.com/secureSpecify CA Bundle
curl --cacert /path/to/ca-bundle.crt https://api.example.comCookie Handling
Save Cookies from a Response
curl -c cookies.txt https://example.com/loginSend Cookies with a Request
curl -b cookies.txt https://example.com/dashboardSend a Specific Cookie
curl -b "sessionid=abc123; theme=dark" https://example.com/profileCurl in Bash Scripts
Curl integrates seamlessly into shell scripts. Here are practical patterns:
Check HTTP Status Code
# Get only the HTTP status code
status=$(curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health)
echo "Status: $status"
if [ "$status" -eq 200 ]; then
echo "Service is healthy"
else
echo "Service returned $status"
fiTime a Request
# Print timing details
curl -s -w "\nTime: %{time_total}s\n" https://api.example.com/usersAvailable timing variables: time_namelookup, time_connect, time_appconnect, time_pretransfer, time_starttransfer, time_total.
API Health Check with Retries
#!/bin/bash
URL="https://api.example.com/health"
MAX_RETRIES=3
DELAY=2
for i in $(seq 1 $MAX_RETRIES); do
response=$(curl -s -o /dev/null -w "%{http_code}" "$URL")
if [ "$response" -eq 200 ]; then
echo "API is healthy"
exit 0
fi
echo "Attempt $i failed with status $response. Retrying in ${DELAY}s..."
sleep $DELAY
done
echo "API health check failed after $MAX_RETRIES attempts"
exit 1Download Multiple Files
#!/bin/bash
URLS=(
"https://example.com/files/doc1.pdf"
"https://example.com/files/doc2.pdf"
"https://example.com/files/doc3.pdf"
)
for url in "${URLS[@]}"; do
curl -O "$url"
doneTroubleshooting Common Issues
Connection Refused
If the server is not running or the port is blocked:
curl: (7) Failed to connect to localhost port 3000: Connection refusedCheck: Is the service running? Is the port correct? Firewall rules?
SSL Certificate Errors
curl: (60) SSL certificate problem: self-signed certificateFix: Use -k for testing, or add the CA certificate with --cacert.
Timeout
curl: (28) Connection timed out after 30001 millisecondsFix: Increase --connect-timeout or --max-time. Check network connectivity.
400 Bad Request
This usually indicates malformed request syntax. Check your headers, data format, and URL encoding. Use JSON Formatter to validate your payload.
401 Unauthorized
Authentication is missing or invalid. Verify your credentials and token. Use the JWT Encoder to examine your token.
Practical Examples
Example 1: Test a REST API Endpoint
# GET with auth and pretty output
curl -s \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Accept: application/json" \
https://api.github.com/user | python3 -m json.toolExample 2: Create a Resource with Validation
curl -s -X POST \
-H "Content-Type: application/json" \
-d '{
"title": "New Task",
"description": "Learn curl",
"priority": "high",
"tags": ["tutorial", "cli"]
}' \
https://api.example.com/tasks | jq .Example 3: Upload File with Metadata
curl -s -X POST \
-F "file=@screenshot.png" \
-F "title=Screenshot 2026" \
-F "visibility=public" \
https://api.example.com/uploads | jq .Example 4: OAuth 2.0 Token Exchange
# Obtain access token
TOKEN=$(curl -s -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=abc123" \
-d "redirect_uri=https://myapp.com/callback" \
-d "client_id=myapp" \
-d "client_secret=secret" \
https://auth.example.com/token | jq -r '.access_token')
# Use the token
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/protectedExample 5: GraphQL Query
curl -X POST \
-H "Content-Type: application/json" \
-d '{"query": "{ users { id name email } }"}' \
https://api.example.com/graphqlCurl vs Other HTTP Clients
| Feature | Curl | HTTPie | Postman | Insomnia |
|---|---|---|---|---|
| Interface | CLI | CLI | GUI | GUI |
| Scriptable | Yes | Yes | Limited | Limited |
| Pre-installed | Yes (Linux/macOS) | No | No | No |
| CI/CD Friendly | Yes | Yes | No | No |
| Response Formatting | Manual (pipe) | Built-in | Built-in | Built-in |
| Session Management | Manual | Manual | Built-in | Built-in |
For quick ad-hoc requests, curl is always available. For complex workflows with multiple environments and variables, GUI clients like Postman are useful, but curl remains the most portable and scriptable option.
Related LangStop Tools
- Curl Command Builder — Interactive curl command builder
- REST API Client — Online HTTP client for API testing
- URL Encoder — Encode and decode URL parameters
- JWT Encoder / Decoder — Debug and inspect JWTs
- JSON Formatter — Pretty-print and validate JSON
- Base64 Encoder — Encode and decode Base64 data
- JSON Path Query — Extract data from JSON responses