Skip to main content
⚡ Calmops

CURL Command Usage — Complete Guide to Making HTTP Requests

Table of Contents

Introduction

curl (Client URL) is the Swiss Army knife of HTTP requests from the command line. Whether you’re testing APIs, downloading files, automating workflows, or debugging web services, curl is the tool millions of developers rely on daily. This guide provides everything you need to master curl, from basic requests to advanced techniques.


Core Concepts & Terminology 📚

What is CURL?

CURL stands for Client URL—it’s a command-line tool and library for transferring data using URLs. It supports multiple protocols but is primarily used for HTTP/HTTPS requests.

Key characteristics:

  • Protocol-agnostic: Works with HTTP, HTTPS, FTP, SFTP, SCP, LDAP, and more
  • Scriptable: Perfect for automation and CI/CD pipelines
  • Lightweight: Available on nearly all Unix-like systems
  • Powerful: Handles authentication, cookies, redirects, proxies, and more

HTTP Fundamentals Refresher

Understanding HTTP is crucial for mastering curl:

Concept Explanation
HTTP Request A message sent by the client (your curl command) to the server
HTTP Response The server’s reply, containing status code, headers, and body
HTTP Methods GET (retrieve), POST (submit), PUT (update), DELETE (remove), PATCH (partial update), HEAD (headers only), OPTIONS (allowed methods)
Status Code 3-digit number indicating result: 2xx (success), 3xx (redirect), 4xx (client error), 5xx (server error)
Headers Metadata about the request/response (Content-Type, User-Agent, Authorization, etc.)
Body The actual data being sent (POST/PUT) or received

Important Abbreviations

Abbreviation Full Name Meaning
HTTP HyperText Transfer Protocol Unencrypted web communication (legacy)
HTTPS HyperText Transfer Protocol Secure Encrypted web communication (current standard)
REST Representational State Transfer Architecture style for web APIs
JSON JavaScript Object Notation Lightweight data format (most common for APIs)
XML eXtensible Markup Language Alternative data format (older APIs)
URL Uniform Resource Locator Web address (e.g., https://example.com/api/users)
Query String Parameters in URL Data after ? (e.g., ?name=John&age=30)
SSL/TLS Secure Sockets Layer / Transport Layer Security Encryption protocols for HTTPS
Proxy Intermediary server Routes requests through another server
Redirect HTTP 3xx response Server tells client to go to a different URL
CORS Cross-Origin Resource Sharing Browser security policy for cross-domain requests

Architecture: How CURL Works 🏗️

Here’s a simplified view of how curl makes a request:

┌──────────────┐
│  Your Device │
│  (Terminal)  │
└──────┬───────┘
       │
       │ curl command
       │ (DNS lookup → TCP connection → TLS handshake → HTTP request)
       ▼
┌──────────────────────┐
│   Internet/Network   │
│  (with possible      │
│   proxies, firewalls)│
└──────┬───────────────┘
       │
       ▼
┌──────────────────────┐
│   Web Server         │
│  (listens on :80     │
│   or :443)           │
└──────┬───────────────┘
       │
       │ HTTP Response
       │ (headers + body)
       ▼
┌──────────────────────┐
│  curl parses         │
│  - Status code       │
│  - Response headers  │
│  - Response body     │
└──────────────────────┘

Basic HTTP Methods & Examples 🌐

1. GET Request (Retrieve Data)

GET is the default method—curl sends it automatically without the -X flag.

# Simple GET request
curl https://api.github.com/users/github

# GET with query parameters
curl "https://api.example.com/search?q=nodejs&limit=10"

# GET with custom headers
curl -H "Authorization: Bearer YOUR_TOKEN" https://api.example.com/me

# GET with verbose output (shows all details)
curl -v https://example.com

# GET and save to file
curl https://example.com/data.json -o data.json

What it retrieves: Status code, response headers, response body

Real-world use: Fetching API data, checking if a server is online, downloading files


2. POST Request (Submit Data)

POST sends data to the server. Use -X POST to specify the method.

# Simple POST with form data
curl -X POST -d "username=john&password=secret" https://example.com/login

# POST with JSON data
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"username":"john","email":"[email protected]"}' \
  https://api.example.com/users

# POST with data from a file
curl -X POST -d @data.json https://api.example.com/upload

# POST with multiple files
curl -F "[email protected]" -F "description=My photo" https://example.com/upload

What it sends: Request body (form data, JSON, files)

Real-world use: Creating new records, logging in, submitting forms, uploading files


3. PUT Request (Update Entire Resource)

PUT replaces an entire resource at a given URL.

# PUT with JSON (replaces entire resource)
curl -X PUT \
  -H "Content-Type: application/json" \
  -d '{"username":"john_updated","email":"[email protected]"}' \
  https://api.example.com/users/123

# PUT with data from file
curl -X PUT -d @updated.json https://api.example.com/users/123

Key difference from POST: PUT is idempotent (multiple identical requests have same effect as one)

Real-world use: Updating user profiles, replacing configuration files


4. PATCH Request (Partial Update)

PATCH updates only specified fields, leaving others unchanged.

# PATCH to update only email (username stays same)
curl -X PATCH \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]"}' \
  https://api.example.com/users/123

# Useful for large objects where you only want to change one field

Real-world use: Updating individual user fields, toggling a feature flag


5. DELETE Request (Remove Resource)

# Simple DELETE
curl -X DELETE https://api.example.com/users/123

# DELETE with authorization header
curl -X DELETE \
  -H "Authorization: Bearer TOKEN" \
  https://api.example.com/posts/456

Real-world use: Deleting user accounts, removing data, cleaning up resources


Essential Curl Options & Flags 🔧

Headers Management

# View response headers
curl -i https://example.com  # Shows status line + headers + body

# Only show response headers
curl -I https://example.com

# Add custom header
curl -H "X-API-Key: abc123" https://api.example.com

# Multiple headers
curl -H "X-API-Key: abc123" -H "Accept: application/json" https://api.example.com

# View request headers being sent (verbose output)
curl -v https://example.com 2>&1 | grep ">"

Authentication

# Basic authentication (username:password)
curl -u "username:password" https://api.example.com/protected

# Bearer token (for OAuth/JWT)
curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." https://api.example.com

# API Key in header
curl -H "X-API-Key: your-api-key-here" https://api.example.com

# API Key in query parameter
curl "https://api.example.com/data?apiKey=your-api-key-here"

Data Management

# Send form data
curl -d "param1=value1&param2=value2" https://example.com

# Send JSON
curl -H "Content-Type: application/json" -d '{"key":"value"}' https://api.example.com

# Send data from file
curl -d @file.txt https://example.com

# URL-encode data automatically
curl --data-urlencode "message=Hello World" https://example.com

Output Control

# Save to file with original name
curl -O https://example.com/document.pdf

# Save to file with custom name
curl -o myfile.pdf https://example.com/document.pdf

# Append to file instead of overwriting
curl https://example.com/data >> data.json

# Show only response body (default behavior)
curl https://example.com

# Show only response headers
curl -I https://example.com

# Pretty-print JSON (pipe to jq)
curl https://api.example.com/users | jq .

Advanced Techniques 🚀

1. Handling Redirects

# Follow redirects automatically
curl -L https://short-url.com/abc123

# Follow redirects and show which URLs it visited
curl -L -v https://short-url.com/abc123

# Limit maximum redirects (default is unlimited)
curl -L --max-redirs 5 https://example.com

Why it matters: Many URLs redirect (301, 302, 303, 307, 308). Without -L, curl stops at the redirect and shows the response.


2. Working with Cookies

# Save cookies from response
curl https://example.com -c cookies.txt

# Use saved cookies in next request
curl https://example.com -b cookies.txt

# Send specific cookie value
curl -b "session_id=abc123def456" https://example.com

# Combine: save and send cookies in session
curl -c cookies.txt -b cookies.txt https://example.com/page1
curl -b cookies.txt https://example.com/page2

Real-world use: Maintaining login sessions across multiple requests


3. Proxy Requests

# HTTP proxy
curl -x "http://proxy.company.com:8080" https://example.com

# SOCKS5 proxy (with authentication)
curl -x "socks5://user:pass@localhost:1080" http://remote-site.com

# SOCKS5 proxy (alternative syntax)
curl --socks5 "user:pass@localhost:1080" http://remote-site.com

# Proxy with specific user/password
curl -x "http://proxy.company.com:8080" \
  -U "proxyuser:proxypass" \
  https://example.com

When to use: Behind corporate firewalls, anonymity, accessing geo-restricted content


4. Timeouts & Retries

# Connection timeout (seconds to establish connection)
curl --connect-timeout 10 https://slow-server.com

# Maximum time for entire operation
curl -m 30 https://example.com  # max 30 seconds total

# Combined: connect in 5 sec, total operation 30 sec
curl --connect-timeout 5 -m 30 https://example.com

# Retry on transient errors (not built-in, use wrapper)
# Better approach: use a bash loop
for i in {1..3}; do
  curl https://example.com && break
  sleep 2
done

5. SSL/TLS & Certificate Handling

# Disable SSL certificate verification (NOT recommended in production!)
curl -k https://self-signed-cert.example.com

# Use specific certificate
curl --cert /path/to/cert.pem https://example.com

# Use certificate with key
curl --cert /path/to/cert.pem --key /path/to/key.pem https://example.com

# Specify CA bundle for verification
curl --cacert /path/to/ca-bundle.crt https://example.com

# Show SSL/TLS details
curl -v https://example.com 2>&1 | grep -A 20 "SSL"

6. Request/Response Inspection

# Verbose output (shows entire exchange)
curl -v https://example.com

# More verbose (includes data transfer)
curl -vv https://example.com

# Show only headers, not body
curl -i https://example.com

# Show request being sent (useful for debugging)
curl -v https://example.com 2>&1 | grep ">"

# Save all headers to file
curl -D headers.txt https://example.com

# Trace request (extremely verbose)
curl --trace trace.log https://example.com

7. Working with APIs: Real-World Examples

Example: GitHub API

# Get user information
curl https://api.github.com/users/linus

# Get user repositories (with pagination)
curl "https://api.github.com/users/linus/repos?page=1&per_page=10"

# Create a repository (requires authentication)
curl -X POST \
  -H "Authorization: token YOUR_GITHUB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-new-repo",
    "description": "My new repository",
    "private": false
  }' \
  https://api.github.com/user/repos

Example: OpenWeather API

# Get weather for a city
curl "https://api.openweathermap.org/data/2.5/weather?q=London&appid=YOUR_API_KEY"

# Parse JSON result with jq
curl -s "https://api.openweathermap.org/data/2.5/weather?q=London&appid=KEY" | jq '.main.temp'

Example: Creating a Resource on Custom API

# Complete example with multiple options
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer eyJhbGc..." \
  -d '{
    "title": "New Article",
    "content": "Article content here",
    "tags": ["curl", "api"]
  }' \
  -v \
  https://api.example.com/articles

Common Pitfalls & Best Practices ⚠️

Pitfall #1: Forgetting Quotes for URLs with Parameters

Wrong:

curl https://api.example.com/search?q=hello&page=1
# & is interpreted as background job operator

Right:

curl "https://api.example.com/search?q=hello&page=1"
# or escape the &:
curl https://api.example.com/search?q=hello\&page=1

Pitfall #2: Not Setting Content-Type for JSON

Wrong:

curl -X POST -d '{"name":"John"}' https://api.example.com/users
# Server might treat this as form data, not JSON

Right:

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"name":"John"}' \
  https://api.example.com/users

Pitfall #3: Storing Credentials in Plain Text

Wrong:

curl -u "admin:password123" https://api.example.com
# Password visible in bash history!

Better:

# Use environment variables
curl -u "$API_USER:$API_PASSWORD" https://api.example.com

# Or use token from file
TOKEN=$(cat ~/.api-token)
curl -H "Authorization: Bearer $TOKEN" https://api.example.com

# Or use -u without password (curl will prompt)
curl -u "admin" https://api.example.com  # Will ask for password

Pitfall #4: Ignoring SSL Certificate Errors

Wrong:

curl -k https://self-signed.example.com  # In production!
# This disables all security checks

Right:

# Get proper certificate OR add to trusted store
curl --cacert /path/to/cert.pem https://self-signed.example.com

# If self-signed certificate in development only:
curl -k https://self-signed-dev.example.com  # Only in dev!

Pitfall #5: Not Handling Redirects

Wrong:

curl https://short.url/abc123
# Returns 301/302, shows HTML redirect page

Right:

curl -L https://short.url/abc123
# Automatically follows redirects to final destination

Best Practices ✅

1. Always Quote URLs with Special Characters

curl "https://example.com/search?q=hello world&filter=recent"

2. Use -s (Silent) in Scripts

# Don't show progress bar in scripts
curl -s https://api.example.com/data | jq .

3. Use -S (Show Errors Even in Silent Mode)

# Silent, but still show errors
curl -sS https://api.example.com/data

4. Set User-Agent for Better Compatibility

curl -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" https://example.com
# Some servers reject requests without User-Agent

5. Handle HTTP Status Codes in Scripts

# Get HTTP status code
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://api.example.com)

if [ $STATUS -eq 200 ]; then
  echo "Success"
else
  echo "Failed with status $STATUS"
fi

6. Pretty-Print JSON Responses

# Use jq for formatting
curl -s https://api.example.com/data | jq '.'

# Or use Python for on-demand pretty-printing
curl -s https://api.example.com/data | python -m json.tool

7. Save Both Headers and Body

# Headers to file, body to stdout
curl -i https://example.com > response.txt

# Or separate them
curl -D headers.txt -o body.txt https://example.com

8. Retry on Failure (Bash Script)

#!/bin/bash
retry_count=0
max_retries=3

while [ $retry_count -lt $max_retries ]; do
  if curl -s https://api.example.com; then
    echo "Success"
    exit 0
  fi
  retry_count=$((retry_count + 1))
  echo "Attempt $retry_count failed, retrying..."
  sleep 2
done

echo "Failed after $max_retries attempts"
exit 1

Debugging & Troubleshooting 🔍

Get Detailed Request/Response Information

# Full verbose output
curl -v https://example.com 2>&1

# Very verbose (includes data hex dumps)
curl -vv https://example.com 2>&1

# Save trace log
curl --trace-ascii debug.txt https://example.com

# Show just request headers sent by curl
curl -v https://example.com 2>&1 | grep ">"

# Show just response headers
curl -v https://example.com 2>&1 | grep "<"

Check Response Time

# Get timing breakdown
curl -w "@curl-format.txt" -o /dev/null -s https://example.com

# Create curl-format.txt with:
# time_namelookup:  %{time_namelookup}\n
# time_connect:     %{time_connect}\n
# time_appconnect:  %{time_appconnect}\n
# time_pretransfer: %{time_pretransfer}\n
# time_redirect:    %{time_redirect}\n
# time_starttransfer: %{time_starttransfer}\n
# ---
# time_total:       %{time_total}\n

# Or simpler version
curl -w "Response time: %{time_total}s\n" -o /dev/null -s https://example.com

Test Connection Without Making Request

# Just connect, don't send request
curl -v --head https://example.com

# Or only show headers
curl -I https://example.com

CURL vs. Alternatives 🔄

Pros & Cons: CURL

Pros ✅

  • Available on nearly all Unix/Linux systems
  • Extremely lightweight and fast
  • Rich feature set (proxies, authentication, cookies, redirects)
  • Perfect for scripts and automation
  • Handles multiple protocols (HTTP, HTTPS, FTP, etc.)
  • Easy to learn; simple one-liner commands

Cons ❌

  • Command-line interface can be verbose for complex requests
  • JSON formatting requires piping to external tools (jq)
  • No built-in request templating/collection management

When to Use Alternatives

Alternative Use Case Pros
wget Downloading files, recursive downloads Better at file downloads; recursive website mirroring
Postman API testing, team collaboration GUI; request collections; environment variables; testing
Insomnia API testing; similar to Postman Lightweight; modern UI; free
httpie Human-friendly HTTP requests Prettier output; intuitive syntax; auto JSON formatting
Python requests Scripting, automation More readable code; better for complex logic
Node.js axios/fetch Web development, automation Native to JavaScript ecosystem

Quick Comparison Table

Tool Use Case Learning Curve Speed
curl Scripts, one-liners, CI/CD Easy Very Fast
wget File downloads Easy Very Fast
httpie Quick API testing Easy Fast
Postman Team API testing Medium Medium
Python requests Complex automation Medium Depends on script

Useful Resources & References 📖

Official Documentation

Learning Resources

JSON Processing:

API Development & Testing:

Bash/Shell Scripting Resources:

CI/CD Integration:

  • GitHub Actions: Use curl in workflow files
  • Jenkins: curl plugins and integration
  • GitLab CI: curl in pipelines

Books & Deep Dives

  • “HTTP: The Definitive Guide” — Comprehensive HTTP reference
  • “RESTful Web Services” — Understanding REST API design

Advanced Architecture: Integrating CURL in Workflows 🏗️

Typical CI/CD Pipeline with CURL

┌──────────────┐
│  Git Commit  │
└──────┬───────┘
       │
       ▼
┌──────────────────┐
│ CI/CD System     │ (GitHub Actions, Jenkins, GitLab CI)
│ (runs on trigger)│
└──────┬───────────┘
       │
       ▼
┌──────────────────────────────┐
│ Build & Test Phase           │
│ curl -v http://localhost:3000 │ (check if service is ready)
└──────┬───────────────────────┘
       │
       ▼
┌──────────────────────────────┐
│ API Integration Tests        │
│ curl -X POST ... -d @test.json│ (verify API responses)
└──────┬───────────────────────┘
       │
       ▼
┌──────────────────────────────┐
│ Deploy to Production         │
│ curl -X POST -H "Auth: ..." .│ (trigger deployment API)
└──────┬───────────────────────┘
       │
       ▼
┌──────────────────────────────┐
│ Post-Deploy Health Check     │
│ curl -I https://example.com  │ (verify endpoint is up)
└──────────────────────────────┘

Real-World Scenarios 🎯

Scenario 1: Monitor API Availability

#!/bin/bash
# Check if API is up every 60 seconds

while true; do
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health)
  
  if [ $STATUS -eq 200 ]; then
    echo "✓ API is up ($(date))"
  else
    echo "✗ API DOWN - Status: $STATUS ($(date))"
    # Send alert
    mail -s "API Down Alert" [email protected] <<< "API returned status $STATUS"
  fi
  
  sleep 60
done

Scenario 2: Batch Process API Requests

#!/bin/bash
# Process list of user IDs and fetch their data

USERS="user1 user2 user3 user4 user5"

for user in $USERS; do
  echo "Fetching data for $user..."
  
  curl -s \
    -H "Authorization: Bearer $API_TOKEN" \
    "https://api.example.com/users/$user" | jq '.'
  
  # Add delay to avoid rate limiting
  sleep 1
done

Scenario 3: Upload File with Progress

#!/bin/bash
# Upload file with progress tracking

curl -F "[email protected]" \
  -F "description=Backup file" \
  --progress-bar \
  https://upload.example.com/files

Scenario 4: Conditional API Request Based on Response

#!/bin/bash
# Check if resource exists, create if not

RESPONSE=$(curl -s -H "Authorization: Bearer $TOKEN" \
  "https://api.example.com/resources/my-resource")

if echo "$RESPONSE" | grep -q "not found"; then
  echo "Resource doesn't exist, creating..."
  curl -X POST \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $TOKEN" \
    -d '{"name":"my-resource"}' \
    https://api.example.com/resources
else
  echo "Resource already exists"
  echo "$RESPONSE" | jq '.'
fi

Summary & Quick Reference 🎯

Most Common curl Commands

# GET request
curl https://example.com

# POST with JSON
curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' https://api.example.com

# Show headers
curl -i https://example.com

# Follow redirects
curl -L https://short.url/abc

# With authentication
curl -u "username:password" https://api.example.com

# Save to file
curl https://example.com -o output.html

# Through proxy
curl -x "socks5://user:pass@localhost:1080" https://example.com

# Verbose mode (debugging)
curl -v https://example.com

# With custom headers
curl -H "X-API-Key: abc123" https://api.example.com

Conclusion

Mastering curl unlocks powerful automation capabilities. Whether you’re testing APIs, monitoring services, or building CI/CD pipelines, curl is an indispensable tool in any developer’s toolkit. The combinations are virtually unlimited—start with the basics and build up your expertise through experimentation.

Next step: Pick a public API (GitHub, OpenWeather, etc.) and experiment with curl commands. Practice builds muscle memory!


See Also:

Comments