Skip to the content.

curl vs HttpClient in C#: when to use which

curl vs HttpClient in C# is not either-or: CurlDotNet runs curl commands on top of HttpClient. Use CurlDotNet when your starting point is a curl command or you want curl’s behavior with less code. Use HttpClient directly when you need full control of the transport, streaming, or features CurlDotNet does not expose.

dotnet add package CurlDotNet

The same request both ways

CurlDotNet, pasted from API docs:

using CurlDotNet;

var result = await Curl.ExecuteAsync("""
    curl -X POST https://httpbin.org/post \
      -H "Authorization: Bearer abc123" \
      --json '{"name":"Ada"}'
    """);
Console.WriteLine(result.StatusCode);

Raw HttpClient:

using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://httpbin.org/post");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "abc123");
request.Headers.Accept.ParseAdd("application/json");
request.Content = new StringContent("""{"name":"Ada"}""", Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);

CurlDotNet’s typed alternative sits in between:

using CurlDotNet.Core;

var result = await CurlRequestBuilder.Post("https://httpbin.org/post")
    .WithBearerToken("abc123").WithJson(new { name = "Ada" }).ExecuteAsync();

Comparison

  CurlDotNet HttpClient
Starting from a curl command Paste and run Translate by hand
Redirects Off unless -L (curl rules) On by default
HTTP 4xx / 5xx Result with IsSuccess = false (or an exception with -f) Response with IsSuccessStatusCode = false
Network errors CurlException with curl exit code HttpRequestException / TaskCanceledException
Timeouts None unless -m / --connect-timeout, as in curl 100 seconds by default (HttpClient.Timeout)
Retries --retry Write your own, or use Polly
Binary vs text body Detected for you You choose the read method
Save to file -o Write the stream yourself
Streaming large bodies No, the response is buffered in memory Yes (ResponseHeadersRead)
HTTP/2 and HTTP/3 selection --http1.1, --http2, --http2-prior-knowledge, --http3 HttpRequestMessage.Version
Client certificates, custom CA, key pinning --cert, --key, --cacert, --capath, --pinnedpubkey (.NET 5+) HttpClientHandler / SocketsHttpHandler
IHttpClientFactory, typed clients, Polly Not integrated First-class
Code generation (C#, Python, JS, PowerShell) Built in n/a
Dependencies One NuGet package In the box

Choose CurlDotNet when

Choose HttpClient when

Mixing them is fine: prototype with the pasted curl command, then call Curl.ToHttpClient(cmd) for a starting point when you move a hot path to raw HttpClient. It carries over headers, body, -u, -x, -k, -L, -m and -F.