What is curl?
The curl command is a powerful tool for transferring data to or from a server using URLs. It supports numerous protocols including HTTP, HTTPS, FTP, FTPS, SCP, SFTP, TFTP, LDAP, and many more. The name stands for "Client URL" or "see URL". It's an essential tool for developers, sysadmins, and anyone working with web services, APIs, or network operations. Think of it as a command-line web browser that can do much more than just browse.
Example 1Basic GET Request
curl https://example.com
Fetches the content from a URL and displays it in the terminal. This is the simplest use of curl - just retrieve a web page.
<!doctype html>
<html>
<head>
<title>Example Domain</title>
</head>
<body>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples...</p>
</body>
</html>
Example 2Save Output to File
curl -o myfile.html https://example.com
Download content and save it to a specific filename using -o (lowercase). This gives you control over the output filename.
Pro Tip: Use -O (uppercase) to save with the remote filename: curl -O https://example.com/file.pdf
Example 3Follow Redirects
curl -L https://github.com
The -L flag tells curl to follow HTTP redirects. Many URLs redirect (301, 302 responses), and without -L, curl stops at the redirect.
Note: This is one of the most commonly needed flags. Many modern websites use redirects extensively.
Example 4Show Response Headers
curl -I https://example.com
Display only the HTTP headers using -I (HEAD request). Great for checking server responses, content type, and status codes without downloading the body.
HTTP/2 200
content-type: text/html; charset=UTF-8
date: Sat, 02 Nov 2025 14:30:00 GMT
server: Apache/2.4.41
content-length: 1256
last-modified: Thu, 17 Oct 2025 07:18:26 GMT
Example 5Include Headers in Output
curl -i https://example.com
Display both headers AND body content using -i. Useful when you need to see the full HTTP response.
Example 6Verbose Mode for Debugging
curl -v https://example.com
Enable verbose mode with -v to see detailed information about the connection, SSL handshake, request headers, and response. Essential for debugging.
* Trying 93.184.216.34:443...
* Connected to example.com (93.184.216.34) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
...
> GET / HTTP/2
> Host: example.com
> User-Agent: curl/7.68.0
> Accept: */*
< HTTP/2 200
Pro Tip: Use --trace or --trace-ascii for even more detailed debugging output.
Example 7POST Request with Data
curl -X POST -d "name=John&email=john@example.com" https://api.example.com/users
Send a POST request with form data using -d. The -X flag specifies the HTTP method (though -d implies POST, so -X POST is optional here).
Note: -d sends data as application/x-www-form-urlencoded by default
Example 8POST JSON Data
curl -X POST -H "Content-Type: application/json" -d '{"name":"John","email":"john@example.com"}' https://api.example.com/users
Send JSON data to an API. Use -H to set the Content-Type header and -d for the JSON payload. This is how you interact with RESTful APIs.
Pro Tip: Use single quotes around JSON to avoid shell interpretation issues with double quotes.
Example 9Send JSON from File
curl -X POST -H "Content-Type: application/json" -d @data.json https://api.example.com/users
Read data from a file using @filename syntax. The @ tells curl to read the content from the specified file.
Example 10Basic Authentication
curl -u username:password https://api.example.com/secure
Provide HTTP Basic Authentication credentials using -u. The credentials are sent in the Authorization header.
Security Warning: This exposes passwords in command history. Use -u username (without password) to be prompted, or use environment variables.
Example 11Set Custom Headers
curl -H "Authorization: Bearer YOUR_TOKEN" -H "Accept: application/json" https://api.example.com/data
Add custom HTTP headers using -H. You can specify multiple headers by using -H multiple times. Essential for API authentication tokens.
Example 12Upload a File
curl -F "file=@/path/to/file.pdf" https://api.example.com/upload
Upload a file using multipart/form-data with -F flag. The @ prefix indicates a file path.
Example 13Download with Progress Bar
curl -# -O https://example.com/largefile.zip
Show a simple progress bar instead of the detailed progress meter using -#. Useful for large downloads where you just want to see percentage complete.
######################################################################## 100.0%
Example 14Resume Interrupted Download
curl -C - -O https://example.com/largefile.zip
Resume a partially downloaded file using -C -. The dash tells curl to automatically determine where to resume from.
Pro Tip: This only works if the server supports range requests (most modern servers do).
Example 15Set User Agent
curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" https://example.com
Change the User-Agent header using -A. Some websites serve different content based on the user agent.
Example 16Use Cookies
curl -b cookies.txt https://example.com
Send cookies from a file using -b. Useful for maintaining sessions across requests.
# Save cookies to file curl -c cookies.txt https://example.com/login # Use saved cookies curl -b cookies.txt https://example.com/dashboard
Example 17Follow Redirects with Max Limit
curl -L --max-redirs 5 https://example.com
Follow redirects but limit the maximum number to prevent infinite redirect loops. Default is 50 if not specified.
Example 18Test API Response Time
curl -w "@curl-format.txt" -o /dev/null -s https://api.example.com
Measure various timing metrics using -w with a format file. The -o /dev/null discards the output, -s silences progress.
# Create curl-format.txt with:
time_namelookup: %{time_namelookup}s\n
time_connect: %{time_connect}s\n
time_appconnect: %{time_appconnect}s\n
time_pretransfer: %{time_pretransfer}s\n
time_redirect: %{time_redirect}s\n
time_starttransfer: %{time_starttransfer}s\n
time_total: %{time_total}s\n
time_namelookup: 0.001s
time_connect: 0.025s
time_appconnect: 0.156s
time_pretransfer: 0.156s
time_redirect: 0.000s
time_starttransfer: 0.234s
time_total: 0.245s
Example 19Silent Mode (No Progress)
curl -s https://api.example.com/status | jq .
Suppress progress meter and error messages with -s. Perfect for piping output to other commands like jq for JSON parsing.
Example 20Only Show Errors (Silent but Show Errors)
curl -sS https://api.example.com/data
Combine -s (silent) with -S (show errors) to hide progress but still display errors. Best of both worlds for scripting.
Example 21DELETE Request
curl -X DELETE https://api.example.com/users/123
Send a DELETE request to remove a resource. Common in RESTful API operations.
Example 22PUT Request to Update Data
curl -X PUT -H "Content-Type: application/json" -d '{"name":"Jane"}' https://api.example.com/users/123
Send a PUT request to update an existing resource. PUT is typically used for full resource updates.
Example 23PATCH Request for Partial Update
curl -X PATCH -H "Content-Type: application/json" -d '{"email":"newemail@example.com"}' https://api.example.com/users/123
Send a PATCH request for partial updates. Unlike PUT, PATCH only updates specified fields.
Example 24Download Multiple Files
curl -O https://example.com/file1.pdf -O https://example.com/file2.pdf
Download multiple files in one command by using -O multiple times. Each file is saved with its remote name.
Example 25FTP Download
curl -u username:password ftp://ftp.example.com/file.txt -o file.txt
Download from FTP server with authentication. curl supports many protocols beyond HTTP!
📚 Additional Information
Common curl Options
| Option | Description |
|---|---|
| -o, --output | Write output to file instead of stdout |
| -O, --remote-name | Save with remote filename |
| -L, --location | Follow redirects |
| -I, --head | Show headers only (HEAD request) |
| -i, --include | Include headers in output |
| -v, --verbose | Verbose output for debugging |
| -s, --silent | Silent mode (no progress) |
| -S, --show-error | Show errors even in silent mode |
| -X, --request | Specify HTTP method (GET, POST, PUT, DELETE, etc.) |
| -d, --data | Send POST data |
| -H, --header | Add custom header |
| -u, --user | Provide username:password for authentication |
| -A, --user-agent | Set User-Agent string |
| -b, --cookie | Send cookies from file or string |
| -c, --cookie-jar | Save cookies to file |
| -F, --form | Upload file (multipart/form-data) |
| -C, --continue-at | Resume download |
| -#, --progress-bar | Show simple progress bar |
| -w, --write-out | Display custom info after transfer |
| --limit-rate | Limit transfer speed |
| --max-time | Maximum time for operation |
| --retry | Retry request on failure |
| -k, --insecure | Skip SSL certificate verification |
HTTP Methods (REST API)
| Method | Purpose | Example |
|---|---|---|
| GET | Retrieve data | curl https://api.example.com/users |
| POST | Create new resource | curl -X POST -d "data" URL |
| PUT | Update entire resource | curl -X PUT -d "data" URL |
| PATCH | Partial update | curl -X PATCH -d "data" URL |
| DELETE | Remove resource | curl -X DELETE URL |
| HEAD | Get headers only | curl -I URL |
| OPTIONS | Check allowed methods | curl -X OPTIONS URL |
Response Status Codes
# Get just the HTTP status code
curl -o /dev/null -s -w "%{http_code}\n" https://example.com
# Common status codes:
# 200 OK - Success
# 201 Created - Resource created
# 204 No Content - Success, no body
# 301 Moved Permanently - Redirect
# 302 Found - Temporary redirect
# 400 Bad Request - Invalid request
# 401 Unauthorized - Authentication required
# 403 Forbidden - No permission
# 404 Not Found - Resource doesn't exist
# 500 Internal Server Error - Server error
# 503 Service Unavailable - Server down
Advanced curl Techniques
Rate Limiting
# Limit download speed to 100KB/s curl --limit-rate 100k -O https://example.com/largefile.zip
Timeouts
# Set connection timeout to 10 seconds curl --connect-timeout 10 https://example.com # Set maximum time for entire operation to 60 seconds curl --max-time 60 https://example.com # Both combined curl --connect-timeout 10 --max-time 60 https://example.com
Retries
# Retry failed requests up to 5 times curl --retry 5 https://api.example.com # Add delay between retries (5 seconds) curl --retry 5 --retry-delay 5 https://api.example.com # Retry only on specific errors curl --retry 3 --retry-connrefused https://api.example.com
Parallel Downloads
# Download multiple files in parallel (curl 7.66+) curl -Z --parallel --parallel-max 10 \ -O https://example.com/file1.pdf \ -O https://example.com/file2.pdf \ -O https://example.com/file3.pdf
GraphQL Queries
curl -X POST https://api.example.com/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{ users { id name email } }"}'
Testing Different HTTP Versions
# Force HTTP/1.1 curl --http1.1 https://example.com # Force HTTP/2 curl --http2 https://example.com # Try HTTP/2 but fallback to HTTP/1.1 curl --http2-prior-knowledge https://example.com
Proxy Usage
# Use HTTP proxy curl -x http://proxy.example.com:8080 https://example.com # Use SOCKS proxy curl --socks5 proxy.example.com:1080 https://example.com # Proxy with authentication curl -x http://proxy.example.com:8080 -U user:pass https://example.com
Real-World Sysadmin Use Cases
Health Check Monitoring
# Check if service is up
curl -f -s -o /dev/null https://myapp.com/health || echo "Service down!"
# Check multiple endpoints
for url in https://api1.com/health https://api2.com/health; do
status=$(curl -o /dev/null -s -w "%{http_code}" "$url")
echo "$url: $status"
done
API Testing in Scripts
#!/bin/bash
# Test API endpoint and parse response
response=$(curl -s -w "\n%{http_code}" https://api.example.com/status)
body=$(echo "$response" | head -n -1)
status=$(echo "$response" | tail -n 1)
if [ "$status" -eq 200 ]; then
echo "API is healthy: $body"
else
echo "API error: Status $status"
exit 1
fi
Download and Verify Checksum
# Download file and its checksum curl -O https://example.com/file.tar.gz curl -O https://example.com/file.tar.gz.sha256 # Verify sha256sum -c file.tar.gz.sha256
Send Alerts to Slack/Discord
# Slack webhook
curl -X POST -H 'Content-type: application/json' \
--data '{"text":"Server disk space critical!"}' \
https://hooks.slack.com/services/YOUR/WEBHOOK/URL
# Discord webhook
curl -X POST -H "Content-Type: application/json" \
-d '{"content":"Backup completed successfully"}' \
https://discord.com/api/webhooks/YOUR/WEBHOOK
Automated Login and Session
# Login and save session cookie curl -c cookies.txt -X POST \ -d "username=admin&password=secret" \ https://example.com/login # Use session for authenticated requests curl -b cookies.txt https://example.com/dashboard # Logout curl -b cookies.txt -X POST https://example.com/logout rm cookies.txt
Check SSL Certificate Expiration
# Get certificate expiration date
curl -vI https://example.com 2>&1 | grep "expire date"
# More detailed certificate info
curl -vI https://example.com 2>&1 | awk '/expire date/{print}'
Download Latest Release from GitHub
# Get latest release URL latest_url=$(curl -s https://api.github.com/repos/user/repo/releases/latest \ | grep "browser_download_url.*\.tar\.gz" \ | cut -d : -f 2,3 \ | tr -d \") # Download it curl -L -O $latest_url
Security Best Practices
- Avoid plaintext passwords: Use -u username (prompts for password) or environment variables
- Verify SSL certificates: Don't use -k/--insecure in production
- Use API tokens: Prefer token authentication over username/password
- Be careful with -v: Verbose output may expose sensitive data in logs
- Clear bash history: Use space before command or history -d to remove sensitive commands
- Store credentials securely: Use .netrc file with proper permissions (600)
Using .netrc for Authentication
# Create ~/.netrc with permissions 600 cat > ~/.netrc << EOF machine api.example.com login myusername password mypassword EOF chmod 600 ~/.netrc # curl will automatically use these credentials curl https://api.example.com/secure
Debugging Tips
- Use -v for verbose: See full request/response cycle
- Use --trace or --trace-ascii: Even more detailed debugging
- Check DNS resolution: curl -v shows IP address connected to
- Test with curl -I first: Check headers before downloading large files
- Use --trace-time: Add timestamps to trace output
curl vs wget
| Feature | curl | wget |
|---|---|---|
| Protocols | Many (HTTP, FTP, SFTP, SCP, etc.) | Fewer (HTTP, HTTPS, FTP) |
| Recursive download | No | Yes (wget -r) |
| API interaction | Excellent | Basic |
| POST/PUT/DELETE | Easy | Difficult |
| Output to stdout | Default | Requires -O - |
| Custom headers | Easy (-H) | Harder |
| Best for | APIs, single files, automation | Mirroring sites, recursive downloads |
Performance Optimization
# Use HTTP/2 for better performance curl --http2 https://example.com # Enable compression curl --compressed https://example.com # Keep-alive (reuse connection for multiple requests) curl --keepalive-time 60 https://example.com # Use DNS cache curl --dns-servers 8.8.8.8 https://example.com
Common Pitfalls and Solutions
Pitfall: Forgetting -L causes curl to not follow redirects
Solution: Always use -L when dealing with URLs that might redirect
Solution: Always use -L when dealing with URLs that might redirect
Pitfall: Using single quotes with JSON in Windows breaks
Solution: Windows PowerShell requires double quotes; escape inner quotes
Solution: Windows PowerShell requires double quotes; escape inner quotes
Pitfall: Large downloads timeout
Solution: Use --max-time or --connect-timeout appropriately
Solution: Use --max-time or --connect-timeout appropriately
Quick Reference Commands
# Simple GET
curl https://example.com
# GET with headers shown
curl -i https://example.com
# POST with JSON
curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' URL
# POST with form data
curl -X POST -d "key=value" URL
# Upload file
curl -F "file=@path/to/file" URL
# Download with progress bar
curl -# -O URL
# Follow redirects
curl -L URL
# Save to file
curl -o filename URL
# Silent but show errors
curl -sS URL
# With authentication
curl -u user:pass URL
# With custom header
curl -H "Authorization: Bearer TOKEN" URL
# Timing information
curl -w "%{time_total}\n" -o /dev/null -s URL
# Just status code
curl -o /dev/null -s -w "%{http_code}\n" URL
Pro Tip for Beginners: Start with simple GET requests (curl URL), then gradually add options as you need them. The man page (man curl) is excellent and has examples for almost everything.
Pro Tip for Sysadmins: Create shell functions for common curl patterns you use frequently. For example, a function for checking API health, another for posting to Slack, etc.
Useful Shell Functions
# Check HTTP status
http_status() {
curl -o /dev/null -s -w "%{http_code}\n" "$1"
}
# Pretty print JSON response
curl_json() {
curl -s "$1" | jq .
}
# Download with retry and resume
curl_reliable() {
curl -C - --retry 5 --retry-delay 3 -# -O "$1"
}
# Usage:
# http_status https://google.com
# curl_json https://api.github.com/users/octocat
# curl_reliable https://example.com/largefile.zip
Testing APIs: Complete Workflow
# 1. Check if API is reachable
curl -I https://api.example.com
# 2. Test authentication
curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/auth/test
# 3. GET request
curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/users
# 4. POST request (create)
curl -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"John","email":"john@example.com"}' \
https://api.example.com/users
# 5. PUT request (update)
curl -X PUT \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"John Updated"}' \
https://api.example.com/users/123
# 6. DELETE request
curl -X DELETE \
-H "Authorization: Bearer YOUR_TOKEN" \
https://api.example.com/users/123
Fun Facts
- curl was first released in 1997 as httpget, then renamed to curl
- The creator, Daniel Stenberg, still maintains curl after 25+ years
- curl is used in virtually every connected device - cars, TVs, phones, spacecraft
- NASA used curl on the Mars helicopter Ingenuity
- curl supports over 25 different protocols
- The official curl website uses curl in its logo: curl.se
- There's a "curl up" conference dedicated to curl and HTTP