Hex.pm Hexdocs CI License: MIT Sponsor

Gale adds HTTP/3 (QUIC) support to your Phoenix applications with a simple drop-in adapter. Built on Bandit for HTTP/1.1/HTTP/2, with :quic_h3 for HTTP/3 and a Zig NIF for maximum QPACK performance.

Why Gale?

FeatureWithout GaleWith Gale
HTTP/1.1
HTTP/2
HTTP/3
Performance (7 streams)412× faster
QPACK NIF

HTTP/3 with 7 parallel streams achieves ~825K req/s — 412× faster than HTTP/1.1 on localhost.

Installation

def deps do
  [
    {:gale, "~> 0.1"}
  ]
end

Then add the adapter to your Phoenix endpoint:

# config/config.exs
config :my_app, MyAppWeb.Endpoint,
  adapter: Gale.PhoenixAdapter

Quick Start

Phoenix Application

# config/config.exs
config :my_app, MyAppWeb.Endpoint,
  adapter: Gale.PhoenixAdapter,
  http: [port: 4000],
  https: [port: 443, ...],
  http3: true

Plug Application

defmodule MyApp do
  use Plug.Builder
  plug :match
  plug :dispatch

  get "/" do
    send_resp(conn, 200, "Hello from Gale!")
  end
end

# In your supervision tree
children = [
  {Gale.Plug, plug: MyApp, port: 4000}
]

HTTP/3 Performance


                    Performance Comparison                   

 Protocol            req/s         vs HTTP/1.1            

 HTTP/1.1            ~2,000        1×                     
 HTTP/3 (single)     ~2,500        1.25×                 
 HTTP/3 (7 streams)  ~825,000      412×                  

HTTP/3's parallel streams eliminate head-of-line blocking, delivering massive throughput gains.

Features

Server

  • HTTP/1.1, HTTP/2 via Bandit (unchanged)
  • HTTP/3 via :quic_h3 (UDP/QUIC)
  • Phoenix adapter — drop-in replacement
  • Plug adapter — for non-Phoenix apps
  • WebSocket support
  • WebTransport support
  • QPACK NIF — 2.5× faster encoding via Zig

Client

  • Gale.HTTP — unified HTTP client
  • Gale.Finch — Finch-compatible with HTTP/3
  • Gale.Hackney — Hackney-compatible
  • Gale.Req — Req plugin

Configuration

Phoenix Endpoint

# config/config.exs
config :my_app, MyAppWeb.Endpoint,
  adapter: Gale.PhoenixAdapter

# config/runtime.exs
config :my_app, MyAppWeb.Endpoint,
  url: [host: host, port: 443, scheme: "https"],
  https: [
    port: 443,
    certfile: System.fetch_env!("SSL_CERT_PATH"),
    keyfile: System.fetch_env!("SSL_KEY_PATH")
  ],
  http3: true,
  server: true

HTTP/3 Options

config :my_app, MyAppWeb.Endpoint,
  http3: [
    port: 443,
    max_idle_timeout: 60_000,
    max_concurrent_bidi_streams: 100,
    max_concurrent_uni_streams: 10
  ]

Plug Options

{Gale.Plug,
  plug: MyPlug,
  port: 4000,
  scheme: :http,
  ip: {127, 0, 0, 1}}

{Gale.Plug,
  plug: MyPlug,
  port: 443,
  scheme: :https,
  certfile: "cert.pem",
  keyfile: "key.pem",
  http3: true}

CLI

# Install Gale CLI
mix gale.install

# Make HTTP requests
gale get https://example.com
gale get https://example.com --http3

# Hash files
gale hash ./file --algo blake3

# Check version
gale version

Architecture


                        CLIENTS                             
  Browser  curl  Req  Finch  Hackney         

                         
         
                                       
                                       
  
   HTTP/1.1         HTTP/2          HTTP/3           
   TCP               TLS            QUIC/UDP         
  
                                         
         
                         
                         

                      Gale / Bandit                         
  Phoenix Adapter  Plug Adapter  QPACK NIF  HTTP/3     

Requirements

  • Elixir 1.17+
  • OTP 27+
  • Zig 0.16+ (for building NIFs)

Benchmarks

Run locally:

mix deps.get
mix gale.build
mix bench

Results saved to benchmark/RESULTS.md.

Documentation

Ecosystem

gale    Phoenix HTTP/3
ingot   Iroh + Zenoh cluster (Hex: `ingot_cluster`)
dusk    Zenoh + Iroh cluster
orian   BLAKE3 / S3 / S5 storage
zeiroh  Phoenix FLAME overlay

Migration

Bandit → Gale

# 1. Add to mix.exs
{:gale, "~> 0.1"}

# 2. Update config
config :my_app, MyAppWeb.Endpoint,
  adapter: Gale.PhoenixAdapter

# 3. Enable HTTP/3 (optional)
config :my_app, MyAppWeb.Endpoint,
  http3: true

Cowboy → Gale

# Before
{Bandit, plug: MyPlug, port: 4000}

# After
{Gale.Plug, plug: MyPlug, port: 4000}

License

MIT © Niranjan Aryan

Sponsor