Open-source project
ninenines/cowboy avatar
ninenines/cowboy

Cowboy: an Erlang/OTP HTTP server for embedded, low-latency stacks

Small, fast, modern HTTP server for Erlang/OTP.

7,522 stars1,172 forksErlangISC

At a glance

What is it?
Cowboy is a small HTTP server for Erlang/OTP that provides routing, HTTP/1.1, HTTP/2 and HTTP/3, and WebSocket handling in one application. It suits teams already running Erlang or Elixir who want the HTTP layer inside their own supervision tree rather than behind a separate process.
Who is it for?
Adopt Cowboy if your service already runs on Erlang/OTP and you want HTTP handled in-process with routing and WebSocket support from the same application. Do not adopt it if your team has no Erlang or Elixir experience, or if you need a general-purpose application server with a large middleware ecosystem; the handler model is Erlang modules, not plugins in another language.
Can I use it commercially?
Yes. ISC is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Erlang, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Cowboy replaces in an Erlang stack

The README states the goal directly: Cowboy aims to provide a complete HTTP stack in a small code base, optimized for low latency and low memory usage, partly by using binary strings. That sentence is the whole pitch. The problem it addresses is that Erlang and Elixir applications usually need an HTTP listener, and the alternatives either pull in a large framework or leave protocol handling to code you write yourself.

Cowboy sits in the middle. It handles the protocol, the connection lifecycle and the dispatch of a request to a handler module you write. Routing is part of the server, so you do not need a separate router. Because it uses Ranch for connection management, the README notes that Cowboy can be embedded in any other application. That is the practical difference: the server is a supervised component of your release, not a process you run beside it.

The audience is narrow and specific. You need to be writing Erlang or Elixir. If you are not, the value proposition does not apply, because handlers are Erlang modules and the configuration is application environment and start arguments.

How Cowboy dispatches a request to your handler

The mechanism visible from the repository is a two-layer split. Ranch accepts and manages connections; Cowboy speaks HTTP on top of them and then routes. The README describes routing as selectively dispatching requests to handlers written in Erlang. In practice you configure a dispatch table of host and path patterns, and each match names a handler module plus its initial state.

The handler is a module implementing a small set of callbacks. The examples directory shows the shape of this: examples/hello_world, examples/echo_get, examples/echo_post, examples/rest_hello_world, examples/rest_basic_auth, examples/websocket and examples/eventsource each demonstrate a different callback surface. Plain handlers and REST handlers are separate behaviours, which matters because REST handlers get content negotiation and method dispatch built in, while plain handlers get a single entry point and you branch yourself.

Protocol support is not an afterthought in the layout. The repository topics list HTTP/2, HTTP/3, WebSocket and WebTransport. HTTP/3 is conditional: the Makefile only adds the quicer dependency when COWBOY_QUICER=1, so a default build does not include it. That is a deliberate build-time switch rather than something enabled by default.

Installing Cowboy and serving a first request

Cowboy is published on Hex, and the Makefile pins its own dependencies: cowlib at 2.20.0 and ranch at 1.8.1, with Hex requirements of cowlib >= 2.20.0 and < 3.0.0 and ranch >= 1.8.0 and < 3.0.0. Add it to your rebar.config deps and let the resolver pick compatible versions. The dependency entries below are the ones the Makefile itself declares.

erlang
DEPS = cowlib ranch
dep_cowlib = git https://github.com/ninenines/cowlib 2.20.0
dep_ranch = git https://github.com/ninenines/ranch 1.8.1

The Makefile also gates HTTP/3 behind an environment variable, so a default build leaves quicer out entirely.

makefile
ifeq ($(COWBOY_QUICER),1)
DEPS += quicer
dep_quicer = git https://github.com/emqx/quic main
endif

The repository ships runnable examples rather than a single canonical snippet, and the README points at them: examples/hello_world, examples/echo_get, examples/echo_post, examples/rest_hello_world, examples/rest_basic_auth, examples/websocket and examples/eventsource. Build the project with the Makefile target the README names for documentation, and read the guide it produces.

bash
make docs

Offline documentation lands in doc/, with the user guide in PDF and HTML and the function reference man pages in doc/man3 and doc/man7. The README also gives make install-docs for installing those man pages on your system.

Where Cowboy is the wrong choice

The most obvious boundary is language. If your service is not on the BEAM, Cowboy is not a candidate at all, and no amount of protocol support changes that. Handlers are Erlang modules, and the configuration lives in Erlang terms.

The second boundary is operational. Cowboy is a library you embed, which means you own the release, the supervision tree and the upgrade path. Teams used to a standalone server binary with a configuration file will find that the server has no independent lifecycle. Restarting HTTP means restarting part of your application.

The third is documentation coverage of failure modes. The README lists the user guide, the function reference, offline docs and the examples, and the Makefile names doc/src/guide/security_model.asciidoc and doc/src/guide/security_checklist.asciidoc as files shipped in the Hex tarball. What the README does not document is rollback or upgrade procedure for a running listener. If your deployment depends on draining connections during a release upgrade, that behaviour is not described in the README, and you would need to read the guide in doc/ before assuming it is handled.

Finally, HTTP/3 is opt-in at build time. A default build will not have it, so a project that assumes HTTP/3 works out of the box will be surprised.

Cowboy compared with a framework-based HTTP layer

The natural alternative for an Erlang or Elixir team is a full web framework that bundles its own HTTP server, routing, templates and a plugin ecosystem. The difference is where the abstraction sits. A framework gives you conventions and generators; Cowboy gives you a protocol implementation and a routing table, and expects you to build the rest.

That trade is real in both directions. With Cowboy you get a smaller dependency surface and direct control over the request path, which is consistent with the stated goal of a small code base optimized for low latency. With a framework you get middleware, session handling and a project structure without writing them. If your application is mostly CRUD with an admin interface, the framework saves more time than Cowboy's smaller footprint returns. If your application is a service that happens to expose HTTP, the inverse holds.

A second comparison point is the connection layer. Cowboy delegates to Ranch, which the README names explicitly as the reason it can be embedded. A framework that owns its whole stack does not expose that seam, and you cannot reuse its connection handling for a non-HTTP protocol without forking.

Licence, dependencies and what upgrades cost you

Cowboy is ISC licensed. The Makefile also declares licenses => [<<"ISC">>] in the Hex tarball metadata, so the package metadata and the repository agree. ISC is a permissive licence, but this is not legal advice and you should confirm obligations with your own counsel if you redistribute modified sources.

The dependency chain is short and pinned: cowlib and ranch, plus quicer only when COWBOY_QUICER=1. That narrowness is the main upgrade advantage, because a version bump touches few moving parts. The cost is that the Hex requirement ranges are bounded at the major version, so a cowlib 3.0.0 release will require a Cowboy change rather than resolving silently.

makefile
hex_req_ranch = >= 1.8.0 and < 3.0.0
hex_req_cowlib = >= 2.20.0 and < 3.0.0

Build tooling is another cost. The project uses erlang.mk, with rebar.config present as well, and CI is configured through dep_ci.erlang.mk with AUTO_CI_OTP and AUTO_CI_WINDOWS set to OTP-LATEST-27+. If your own toolchain is older than that line, you are outside the configuration the project tests against. The Makefile also shows that the examples, http_perf, ws_autobahn and ws_perf test suites are excluded unless FULL is defined, so a default test run does not cover them. The last push to the repository was on 2026-09-16.

Editorial conclusion

Adopt Cowboy if your service already runs on Erlang/OTP and you want HTTP handled in-process with routing and WebSocket support from the same application. Do not adopt it if your team has no Erlang or Elixir experience, or if you need a general-purpose application server with a large middleware ecosystem; the handler model is Erlang modules, not plugins in another language. Before committing, check that your dependency resolver picks cowlib 2.20.0 or later and ranch 1.8.0 or later, confirm which OTP release your CI targets against the AUTO_CI_OTP setting in the Makefile, and read doc/src/guide/security_checklist.asciidoc, which the Makefile ships inside the Hex tarball.

Frequently asked questions

What is Cowboy in Erlang/OTP?

Cowboy is an HTTP server for Erlang/OTP that the README describes as small, fast and modern, providing a complete HTTP stack with routing that dispatches requests to handlers written in Erlang. It uses Ranch for connection management, which is why it can be embedded in another application.

How do I install Cowboy in a rebar3 project?

The Makefile declares cowlib 2.20.0 and ranch 1.8.1 as its dependencies, with Hex requirements of cowlib >= 2.20.0 and < 3.0.0 and ranch >= 1.8.0 and < 3.0.0. The README points to the user guide and function reference for version 2.19 as the starting documentation.

Does Cowboy support HTTP/2, HTTP/3 and WebSocket?

The repository topics list HTTP/2, HTTP/3, WebSocket and WebTransport, and the examples directory includes a websocket example. HTTP/3 is conditional: the Makefile adds the quicer dependency only when COWBOY_QUICER=1, so a default build does not include it.

What licence does Cowboy use?

Cowboy is ISC licensed. The Makefile also sets licenses => [<<"ISC">>] in the Hex tarball metadata, so the package metadata matches the repository licence.

Where can I find Cowboy documentation and examples?

The README links the user guide and function reference at ninenines.eu for version 2.19, and notes that make docs generates offline documentation in doc/, with man pages in doc/man3 and doc/man7. Runnable examples are in the examples/ directory, including hello_world, echo_get, rest_hello_world and websocket.

Official sources

  1. Issues
  2. License: ISC
  3. ninenines/cowboy on GitHub
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ninenines-cowboy.svg)](https://hysenlabs.com/projects/ninenines-cowboy)