Two things in one repo:
- **A precompiled C distribution of Cloudflare quiche
- BoringSSL** for eight
platforms — every GitHub release ships ready-to-link
libquiche.a/libssl.a/libcrypto.a(orquiche.lib/ssl.lib/crypto.libon Windows) plus their public headers. No Rust, CMake, NASM, or Apple /Android SDK required on the consumer side. You can use this directly from C, C++, Go, Swift, or any other language with FFI — see Use from C/C++ below.
- BoringSSL** for eight
platforms — every GitHub release ships ready-to-link
- A Zig 0.16 wrapper that lazily fetches the matching tarball from
the release, links it, and exposes two independent modules:
@import("quiche")— RAII wrappers around quiche's QUIC/HTTP3 FFI; raw C bindings remain available underquiche.c.@import("boringssl")— raw BoringSSL bindings (<openssl/ssl.h>and everything it transitively pulls in) underboringssl.c. Useful when you want TLS or crypto without the rest of quiche.
Either way, end users only need a working toolchain — Zig 0.16 for Zig
consumers, or any C/C++ compiler for direct C consumers. The prebuilt
artifacts are produced fresh by prebuilt.yml on each tag push.
| Target | Prebuilt artifact | Zig build/test in CI |
|---|---|---|
| linux-x86_64 | ✅ | ✅ build + test + handshake smoke |
| linux-aarch64 | ✅ | ✅ build + test + handshake smoke |
| macos-arm64 | ✅ | ✅ build + test + handshake smoke |
| ios-arm64 | ✅ | |
| windows-x86_64 | ✅ | addTranslateC bug with the bundled clang's avx512 headers |
| windows-arm64 | ✅ | |
| android-arm64 | ✅ | |
| android-x86_64 | ✅ |
The prebuilt column tracks prebuilt-v0.28.0 — every artifact is produced
fresh by the prebuilt.yml workflow on each tag push. The CI column tracks
what ci.yml actually exercises on every commit.
Heads up on the upstream version: cloudflare/quiche stopped writing release notes after
0.24.5, so their Releases page looks stuck in mid-2025 even though newer tags exist. The actual currentquichecrate version lives on the Tags page — that's whatQUICHE_VERSIONinprebuilt.ymltracks, so don't be surprised if our pin looks ahead of their Releases page.
Each quiche-<platform>.tar.gz in a release expands to:
quiche-<platform>/
├── lib/
│ ├── libquiche.a (or quiche.lib on Windows MSVC)
│ ├── libssl.a (or ssl.lib)
│ └── libcrypto.a (or crypto.lib)
└── include/
├── quiche.h
└── openssl/ (BoringSSL public headers — ssl.h, crypto.h,
evp.h, x509.h, …)
The tarballs are self-contained: BoringSSL is statically linked into both
libssl.a and libcrypto.a, and libquiche.a already pulls those in as
dependencies. You only need to add the OS-level system libraries listed
below when linking.
Pick the tarball that matches your target from the latest release:
https://github.com/zoptia/quiche-zig/releases/latest
Verify it against the SHA256SUMS asset, extract, then point your build
system at lib/ and include/. Minimal example with plain cc:
TARBALL=quiche-linux-x86_64.tar.gz
curl -fsSL -O "https://github.com/zoptia/quiche-zig/releases/download/prebuilt-v0.28.0/${TARBALL}"
curl -fsSL "https://github.com/zoptia/quiche-zig/releases/download/prebuilt-v0.28.0/SHA256SUMS" \
| grep "${TARBALL}" | sha256sum -c -
tar -xzf "${TARBALL}"
cc -o myapp main.c \
-I quiche-linux-x86_64/include \
quiche-linux-x86_64/lib/libquiche.a \
quiche-linux-x86_64/lib/libssl.a \
quiche-linux-x86_64/lib/libcrypto.a \
-lpthread -ldl -lm -lrt -lutil -lgcc_sPer-platform link line for the system libraries:
| Platform | System libraries |
|---|---|
| linux | -lpthread -ldl -lm -lrt -lutil -lgcc_s |
| macos / ios | -framework Security -framework CoreFoundation -framework SystemConfiguration |
| windows-msvc | ws2_32.lib userenv.lib ntdll.lib bcrypt.lib crypt32.lib secur32.lib advapi32.lib |
| android | -lc (NDK supplies the rest) |
You can #include <quiche.h> for the QUIC/H3 API and #include <openssl/ssl.h>
(et al.) for the BoringSSL API from the same translation unit.
zig fetch --save git+https://github.com/zoptia/quiche-zigThen in your build.zig:
const quiche_dep = b.dependency("quiche_zig", .{
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "myapp",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "quiche", .module = quiche_dep.module("quiche") },
// Optional — only needed if you call BoringSSL directly.
.{ .name = "boringssl", .module = quiche_dep.module("boringssl") },
},
}),
});
b.installArtifact(exe);const std = @import("std");
const quiche = @import("quiche");
pub fn main() !void {
var cfg = try quiche.Config.init(quiche.PROTOCOL_VERSION);
defer cfg.deinit();
cfg.verifyPeer(false);
try cfg.setApplicationProtos(quiche.H3_APPLICATION_PROTOCOL);
cfg.setMaxIdleTimeout(5_000);
// … additional transport-parameter setters live as setXxx methods.
std.debug.print("quiche version: {s}\n", .{quiche.version()});
}Config, Connection, H3Config, and H3Connection are RAII handles
around the corresponding quiche_* C types. Errors translate from the
QUICHE_ERR_* codes into the quiche.Error set. When the wrapper isn't
expressive enough, quiche.c re-exports the raw @cImported bindings so
you can drop down to the C API for anything we don't cover.
See examples/client.zig for a complete client that performs a QUIC
handshake against cloudflare-quic.com:443 and prints the negotiated
ALPN, and examples/server.zig for a minimal echo server.
For raw BoringSSL from Zig:
const std = @import("std");
const ssl = @import("boringssl");
pub fn main() !void {
_ = ssl.c.OPENSSL_init_ssl(0, null);
const ctx = ssl.c.SSL_CTX_new(ssl.c.TLS_method())
orelse return error.SslCtxNewFailed;
defer ssl.c.SSL_CTX_free(ctx);
std.debug.print("OpenSSL version: 0x{x}\n", .{ssl.c.OPENSSL_VERSION_NUMBER});
}If your target isn't in the matrix, or you want to test against your own
fork of quiche, build quiche with cargo build --release --features ffi
and pass the resulting prefix to zig build:
zig build -Dquiche-prefix=/path/to/your/quiche-outquiche-prefix should be a directory with the layout
prefix/
├── lib/
│ ├── libquiche.a (or quiche.lib on Windows)
│ ├── libssl.a
│ └── libcrypto.a
└── include/
├── quiche.h
└── openssl/ (BoringSSL public headers; only needed if you
import the boringssl module)
When -Dquiche-prefix is set, the lazy dependency download is skipped
entirely, so you can develop offline.
- Update
QUICHE_VERSIONat the top of.github/workflows/prebuilt.yml. - Bump the
prebuilt-v<VER>references inbuild.zig.zonand.github/workflows/ci.yml(search forprebuilt-v0.). - Push a tag named
prebuilt-v<VER>. Theprebuilt.ymlworkflow produces fresh per-platform tarballs and creates a GitHub release. - Run
zig fetch --save=quiche_linux_x86_64 https://github.com/zoptia/quiche-zig/releases/download/prebuilt-v<VER>/quiche-linux-x86_64.tar.gz(and the equivalent for the other seven platforms) to refresh the hashes inbuild.zig.zon. Commit the result.
This wrapper repo is BSD-2-Clause, matching upstream quiche.
The prebuilt tarballs distribute three things together:
- Cloudflare quiche (BSD-2-Clause, https://github.com/cloudflare/quiche)
- BoringSSL (OpenSSL/SSLeay license, ISC, BSD; see https://boringssl.googlesource.com/boringssl/+/HEAD/LICENSE)
- Bits of the Rust standard library statically linked into
libquiche.a(MIT/Apache-2.0, see https://www.rust-lang.org/policies/licenses)
If you redistribute a binary that links any of the prebuilt artifacts,
you inherit the corresponding attribution requirements. The bundled
LICENSE file in this repo carries the high-level pointers.