What is the difference between wget and curl?
wget is a downloader and curl is a data transfer tool. wget can crawl links, mirror a whole site and resume a broken download on its own. curl makes one request at a time with full control over headers, methods and bodies, speaks many more protocols, and prints the response to stdout.
wget and curl are the two command-line tools everyone reaches for to move data over a network, and they get lumped together because both can download a file with one line. But they were built for different jobs, and knowing which job you have makes the choice obvious. wget is a downloader; curl is a data-transfer tool. That one distinction explains almost every difference below.
What is each tool built for?
wget was designed to retrieve files, especially in bulk and especially unattended. It can follow links, mirror an entire site, resume a broken download and keep retrying on a flaky connection, all on its own. It is the tool you want when the goal is “get these files onto disk,” and it is happy to run in a script with no hand holding.
curl was designed to transfer data, in either direction, over an unusually long list of protocols. It is built on libcurl, a library that countless other programs use under the hood, and it exposes fine control over a single request: headers, methods, authentication, upload bodies, cookies. It is the tool you want when the goal is “make exactly this request and show me the response.”
There is also a quieter difference in how they report trouble. curl does not treat an HTTP response code as a failure, so a 404 or a 500 still counts as a successful transfer; you print the error page and the exit code stays zero unless you add -f, which makes curl exit with error 22 and print nothing on any response of 400 or above. wget, built for unattended jobs, is stricter: a failed download is a non-zero exit, which is exactly what a script watching for failures wants. That single behavioral gap bites in CI, where a curl step can look green while quietly downloading an error page.
What can each tool do that the other cannot?
The clearest way to keep them straight is by their non-overlapping strengths.
wget’s territory
- Recursive mirroring. Point wget at a URL with the right flags and it will crawl links and pull down a whole directory or site. curl has no equivalent; it fetches the URLs you name and nothing more.
- Resume by default is easy. wget is built around interrupted downloads: it can retry, resume a partial file, and keep going until the transfer completes.
- Unattended by nature.Continue on error, log to a file, wait between requests: wget’s defaults suit long batch jobs left running.
curl’s territory
- Many protocols. Beyond HTTP and FTP, curl speaks HTTP/2 and HTTP/3, plus SFTP, SCP, SMTP, IMAP, LDAP and a dozen others. wget sticks to HTTP, HTTPS and FTP, and it speaks only HTTP/1.0 and HTTP/1.1.
- Uploads and complex requests. curl sends POST and PUT bodies, custom headers, form data and file uploads with ease. It is the standard way to poke an API from a shell.
- A library behind it. libcurl means the exact behavior you script on the command line is available inside applications in dozens of languages.
- Writes to stdout by default. curl prints the response to your terminal, which makes it a natural pipeline stage feeding into jq or grep. wget saves to a file by default instead.
Side by side
| curl | wget | |
|---|---|---|
| Default action | Print response to stdout | Save file to disk |
| Recursive download / mirror | ||
| Resume a partial download | ||
| HTTP/2 and HTTP/3 | ||
| Protocols beyond HTTP/FTP | ||
| Upload / POST bodies / forms | ||
| Backed by a reusable library | ||
| Follow redirects | With -L | By default |
The same task, in both tools
Most of the day-to-day overlap comes down to a handful of tasks, each written both ways below.
Download a file
Note the two curl flags: lowercase -o takes a filename you supply, while uppercase -O reuses the name from the URL. wget just saves under the remote name with no flag at all, which is the whole point of it.
Resume an interrupted download
POST JSON to an API
This is curl’s home turf. You set the method, a content-type header, and the body.
wget can send the same body with --post-data and a header flag, but it is clumsier and rarely worth it. If you are talking to an API, use curl.
Follow redirects
This is a common curl surprise: without -L, curl shows you the redirect response itself rather than the page it points to. wget follows the chain without asking.
Save and reuse cookies
Inspect response headers
When you are debugging why a request behaves oddly, the headers tell the story. curl shows them with -I for a headers-only request, or -ito include them above the body. wget writes the server’s response headers with -S.
That --spider flag on wget is a quiet way to check whether a URL exists without pulling the file, which is useful in a script that just needs a yes or no.
Mirror a whole site
This is the task with no curl equivalent. wget’s --mirror turns on recursion and time-stamping, sets infinite recursion depth and keeps FTP directory listings, all in one flag, and the companion options rewrite links and pull in the page assets so the copy works offline.
Read it as: mirror the site, rewrite links so they point at your local copy, and grab the images, stylesheets and scripts each page needs. There is simply no way to express this in curl, which is the single sharpest line between the two tools.
Which should you use, wget or curl?
Let the shape of the task pick the tool.
- Reach for wget when you want files on disk: grabbing a release archive, mirroring a docs site, or running a long unattended download that might drop and need to resume.
- Reach for curl when you are working with a request: hitting an API, sending JSON, inspecting headers, testing an endpoint, or piping a response into another tool. It is also the one to learn if you script in a language that ships libcurl bindings.
In practice most developers keep both installed and use them for exactly these two moods. If you find yourself copying the same curl invocation for an API you hit constantly, that is a snippet worth keeping rather than rebuilding; the same goes for the jq filter you pipe it through. The sibling jq cheat sheet pairs naturally with curl, and the cluster pillar, the regex cheat sheet, covers the pattern-matching you end up doing on the output. For copying these commands around a shell without mangling them, see copy and paste in the terminal.
Sources
- curl man page, curl project
- Features: what curl can do, curl project
- curl vs Wget, Daniel Stenberg, curl maintainer
- wget(1) manual page, Debian manpages