An HTTP client for Erlang. Simple, reliable, fast.
- HTTP/3 support - Experimental QUIC/HTTP3 via lsquic. Opt-in with
{protocols, [http3, http2, http1]}. - HTTP/2 support - Automatic protocol negotiation via ALPN. Multiplexing, header compression, flow control.
- Process per connection - Each connection runs in its own
gen_statemprocess. Clean isolation, automatic cleanup on crashes. - Connection pooling - Reuse connections automatically. Configure pools per host or globally.
- Streaming - Stream request bodies, response bodies, or both. Handle large files without loading them in memory.
- Async responses - Get response chunks as messages. Process other work while waiting.
- WebSocket support - Full WebSocket client with the same process-per-connection model.
- IPv6 first - Happy Eyeballs algorithm tries IPv6 before IPv4 for faster connections on modern networks.
- SSL by default - Secure connections with certificate verification using Mozilla's CA bundle.
%% Start hackney
application:ensure_all_started(hackney).
%% Simple GET
{ok, 200, _Headers, Body} = hackney:get(<<"https://httpbin.org/get">>, [], <<>>, [with_body]).
%% POST JSON
Headers = [{<<"content-type">>, <<"application/json">>}],
Payload = <<"{\"key\": \"value\"}">>,
{ok, 201, _, _} = hackney:post(<<"https://httpbin.org/post">>, Headers, Payload, [with_body]).
%% Stream large response
{ok, 200, _, Ref} = hackney:get(<<"https://example.com/large-file">>),
stream_body(Ref).
stream_body(Ref) ->
case hackney:stream_body(Ref) of
{ok, Chunk} -> io:format("~p bytes~n", [byte_size(Chunk)]), stream_body(Ref);
done -> ok
end.{deps, [hackney]}.{:hackney, "~> 2.0"}| Guide | Description |
|---|---|
| Getting Started | Installation, first requests, basic patterns |
| HTTP Guide | Requests, responses, streaming, async, pools |
| HTTP/2 Guide | HTTP/2 protocol, ALPN, multiplexing, server push |
| HTTP/3 Guide | HTTP/3 over QUIC, opt-in configuration, Alt-Svc |
| WebSocket Guide | Connect, send, receive, active mode |
| Design Guide | Architecture, pooling, load regulation internals |
| Migration Guide | Upgrading from hackney 1.x |
| API Reference | Full module documentation |
| Changelog | Version history |
All standard HTTP methods as convenient functions:
hackney:get(URL).
hackney:post(URL, Headers, Body).
hackney:put(URL, Headers, Body).
hackney:delete(URL).
hackney:head(URL).
hackney:options(URL).
hackney:patch(URL, Headers, Body).Connections are pooled by default. Configure pools for different use cases:
%% Use default pool
hackney:get(URL).
%% Named pool with custom settings
hackney_pool:start_pool(api_pool, [{max_connections, 100}]),
hackney:get(URL, [], <<>>, [{pool, api_pool}]).
%% No pooling for one-off requests
hackney:get(URL, [], <<>>, [{pool, false}]).Stream request bodies for uploads:
{ok, Ref} = hackney:post(URL, Headers, stream),
hackney:send_body(Ref, <<"chunk 1">>),
hackney:send_body(Ref, <<"chunk 2">>),
hackney:finish_send_body(Ref),
{ok, Status, _, Ref} = hackney:start_response(Ref).Stream response bodies for downloads:
{ok, 200, _, Ref} = hackney:get(URL),
read_chunks(Ref).
read_chunks(Ref) ->
case hackney:stream_body(Ref) of
{ok, Data} -> process(Data), read_chunks(Ref);
done -> ok
end.Receive response data as messages:
{ok, Ref} = hackney:get(URL, [], <<>>, [async]),
receive
{hackney_response, Ref, {status, 200, _}} -> ok
end,
receive
{hackney_response, Ref, {headers, Headers}} -> ok
end,
receive_body(Ref).
receive_body(Ref) ->
receive
{hackney_response, Ref, done} -> ok;
{hackney_response, Ref, Bin} -> receive_body(Ref)
end.{ok, Conn} = hackney:ws_connect(<<"wss://echo.websocket.org">>),
ok = hackney:ws_send(Conn, {text, <<"hello">>}),
{ok, {text, <<"hello">>}} = hackney:ws_recv(Conn),
hackney:ws_close(Conn).HTTP/2 is used automatically when the server supports it:
%% Automatic HTTP/2 via ALPN negotiation
{ok, 200, Headers, Body} = hackney:get(<<"https://nghttp2.org/">>, [], <<>>, [with_body]).
%% Force HTTP/1.1 only
hackney:get(URL, [], <<>>, [{protocols, [http1]}]).
%% Force HTTP/2 only
hackney:get(URL, [], <<>>, [{protocols, [http2]}]).HTTP/3 support is opt-in. Enable it per-request or globally:
%% Enable HTTP/3 for a single request
hackney:get(URL, [], <<>>, [{protocols, [http3, http2, http1]}]).
%% Enable HTTP/3 globally (application-wide)
application:set_env(hackney, default_protocols, [http3, http2, http1]).Note: HTTP/3 uses QUIC (UDP transport). Some networks may block UDP traffic.
Upload files and form data:
Multipart = {multipart, [
{<<"field">>, <<"value">>},
{file, <<"/path/to/file.txt">>},
{file, <<"/path/to/image.png">>, <<"image.png">>, [{<<"content-type">>, <<"image/png">>}]}
]},
hackney:post(URL, [], Multipart).%% HTTP proxy
hackney:get(URL, [], <<>>, [{proxy, <<"http://proxy:8080">>}]).
%% With authentication
hackney:get(URL, [], <<>>, [{proxy, <<"http://user:pass@proxy:8080">>}]).
%% Environment variables work automatically
%% HTTP_PROXY, HTTPS_PROXY, NO_PROXY%% Follow redirects automatically
hackney:get(URL, [], <<>>, [{follow_redirect, true}, {max_redirect, 5}]).hackney:get(URL, [], <<>>, [
{connect_timeout, 5000}, %% Connection timeout
{recv_timeout, 30000} %% Response timeout
]).%% Custom CA certificate
hackney:get(URL, [], <<>>, [
{ssl_options, [{cacertfile, "/path/to/ca.pem"}]}
]).
%% Skip verification (development only)
hackney:get(URL, [], <<>>, [insecure]).| Module | Purpose |
|---|---|
hackney |
Main API - requests, connections, WebSocket |
hackney_pool |
Connection pool management |
hackney_url |
URL parsing and encoding |
hackney_headers |
Header manipulation |
hackney_multipart |
Multipart encoding |
hackney_cookie |
Cookie parsing |
hackney_http |
HTTP protocol parser |
Erlang/OTP 27+
See CONTRIBUTING.md for guidelines on pull requests and development setup.
Issues and pull requests welcome at https://github.com/benoitc/hackney
Professional support is available via Enki Multimedia. Contact sales@enki-multimedia.eu.
Apache 2.0 - See LICENSE and NOTICE
Copyright (c) 2012-2026 Benoit Chesneau