SkillAgentSearch skills...

Hackney

simple HTTP client in Erlang

Install / Use

/learn @benoitc/Hackney
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

hackney

An HTTP client for Erlang. Simple, reliable, fast.

Build Status Hex pm

Why hackney?

  • HTTP/3 support - Experimental QUIC/HTTP3 via pure Erlang. 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_statem process. 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.
  • Automatic decompression - Transparently decompress gzip/deflate responses with {auto_decompress, true}.

Quick Start

%% 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.

Installation

Rebar3

{deps, [hackney]}.

Mix

{:hackney, "~> 3.0"}

Documentation

| 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 |

Features

HTTP Methods

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).

Connection Pooling

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}]).

Streaming

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.

Async Responses

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.

WebSocket

{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

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 (Experimental)

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.

Multipart

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).

Proxy Support

%% 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

Redirects

%% Follow redirects automatically
hackney:get(URL, [], <<>>, [{follow_redirect, true}, {max_redirect, 5}]).

Timeouts

hackney:get(URL, [], <<>>, [
    {connect_timeout, 5000},  %% Connection timeout
    {recv_timeout, 30000}     %% Response timeout
]).

Automatic Decompression

%% Automatically decompress gzip/deflate responses
hackney:get(URL, [], <<>>, [{auto_decompress, true}, with_body]).

SSL Options

%% Custom CA certificate
hackney:get(URL, [], <<>>, [
    {ssl_options, [{cacertfile, "/path/to/ca.pem"}]}
]).

%% Skip verification (development only)
hackney:get(URL, [], <<>>, [insecure]).

Modules

| 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 |

Requirements

Erlang/OTP 27+

Contributing

See CONTRIBUTING.md for guidelines on pull requests and development setup.

Issues and pull requests welcome at https://github.com/benoitc/hackney

Support

hackney is critical infrastructure for many Erlang and Elixir applications. If your company relies on it, consider sponsoring its maintenance:

Sponsor

Sponsorship ensures continued development, timely security patches, and compatibility with OTP releases.

Corporate sponsors: If hackney is part of your infrastructure, reach out for sponsored support options.

License

Apache 2.0 - See LICENSE and NOTICE

Copyright (c) 2012-2026 Benoit Chesneau

View on GitHub
GitHub Stars1.4k
CategoryDevelopment
Updated7d ago
Forks442

Languages

Erlang

Security Score

85/100

Audited on Mar 24, 2026

No findings