{"id":50207637,"url":"https://github.com/arizona-framework/roadrunner","last_synced_at":"2026-05-26T02:10:29.403Z","repository":{"id":356160486,"uuid":"1227346376","full_name":"arizona-framework/roadrunner","owner":"arizona-framework","description":"Pure-Erlang HTTP and WebSocket server. Beep beep.","archived":false,"fork":false,"pushed_at":"2026-05-21T02:12:08.000Z","size":1829,"stargazers_count":15,"open_issues_count":1,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-21T05:55:29.110Z","etag":null,"topics":["autobahn","beam","erlang","erlang-otp","h2spec","http","http-server","http2","http2-server","https","otp","rfc-6455","rfc-7541","rfc-7692","rfc-9110","rfc-9112","rfc-9113","tls","web-server","websocket"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/roadrunner","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arizona-framework.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["williamthome"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":["https://www.buymeacoffee.com/williamthome"]}},"created_at":"2026-05-02T14:58:27.000Z","updated_at":"2026-05-21T02:12:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/arizona-framework/roadrunner","commit_stats":null,"previous_names":["arizona-framework/roadrunner"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/arizona-framework/roadrunner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arizona-framework%2Froadrunner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arizona-framework%2Froadrunner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arizona-framework%2Froadrunner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arizona-framework%2Froadrunner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arizona-framework","download_url":"https://codeload.github.com/arizona-framework/roadrunner/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arizona-framework%2Froadrunner/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33500473,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-25T14:31:05.219Z","status":"online","status_checked_at":"2026-05-26T02:00:06.821Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["autobahn","beam","erlang","erlang-otp","h2spec","http","http-server","http2","http2-server","https","otp","rfc-6455","rfc-7541","rfc-7692","rfc-9110","rfc-9112","rfc-9113","tls","web-server","websocket"],"created_at":"2026-05-26T02:10:28.769Z","updated_at":"2026-05-26T02:10:29.388Z","avatar_url":"https://github.com/arizona-framework.png","language":"Erlang","funding_links":["https://github.com/sponsors/williamthome","https://www.buymeacoffee.com/williamthome"],"categories":[],"sub_categories":[],"readme":"# Roadrunner\n\n[![Erlang CI](https://github.com/arizona-framework/roadrunner/actions/workflows/erlang.yml/badge.svg?branch=main)](https://github.com/arizona-framework/roadrunner/actions/workflows/erlang.yml)\n[![Hex.pm](https://img.shields.io/hexpm/v/roadrunner.svg)](https://hex.pm/packages/roadrunner)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/roadrunner/)\n[![License](https://img.shields.io/hexpm/l/roadrunner.svg)](https://github.com/arizona-framework/roadrunner/blob/main/LICENSE.md)\n\n![roadrunner logo](https://raw.githubusercontent.com/arizona-framework/roadrunner/main/assets/logo.jpg)\n\nPure-Erlang HTTP/1.1 + HTTP/2 + HTTP/3 + WebSocket server for OTP 29+.\n**Built for low tail latency at sustained load.** Beep beep.\n\nRoadrunner is the HTTP backbone of the\n[arizona-framework](https://github.com/arizona-framework/arizona).\nStrict RFC 9110 / 9112 / 9113 parsing, with **strict 100 %\n[h2spec](https://github.com/summerwind/h2spec)** (HTTP/2 conformance)\nand **strict 100 %\n[Autobahn fuzzingclient](https://github.com/crossbario/autobahn-testsuite)**\n(WebSocket, no exclusions). The user-facing API is a handler\nbehaviour, request/response accessors, listener controls, and a\nhandful of opt-in helpers (cookies, qs, multipart, SSE, WebSocket).\nModern OTP idioms throughout, with predictable per-connection\nlifecycle observability.\n\n## Requirements\n\nRequires **OTP 29 or newer**.\n\n## 🚧 Status\n\nRoadrunner is in `0.x`. The core is functional and covered by tests,\nbut the API may change between minor versions. Pin an exact version\nin your deps if you need stability across upgrades.\n\n## Conformance\n\nStrict 100 % h2spec (HTTP/2) and Autobahn fuzzingclient across the full\nWebSocket matrix (no exclusions). HTTP/1.1 parsers stress-tested against\nthe [llhttp](https://github.com/nodejs/llhttp) test corpus and the\ncanonical [PortSwigger](https://portswigger.net/web-security/request-smuggling)\nrequest-smuggling vectors.\n\nStandards conformance:\n\n- **HTTP/1.1**: RFC 9110 (semantics) + RFC 9112 (syntax).\n- **HTTP/2**: RFC 9113 (frames + multiplexing) + RFC 7541 (HPACK).\n  Opt-in per listener via `protocols =\u003e [http1, http2]` (or\n  `[http2]` for h2c prior-knowledge on plain TCP). Conformance\n  harness: [`scripts/h2spec.sh`](https://github.com/arizona-framework/roadrunner/blob/main/scripts/h2spec.sh) (drives\n  [h2spec](https://github.com/summerwind/h2spec)).\n- **HTTP/3** (experimental): RFC 9114 over QUIC with QPACK (RFC 9204)\n  static-table compression. Enable per listener via\n  `protocols =\u003e [http3]` (requires `tls`; QUIC mandates TLS 1.3); it\n  co-serves with h1/h2 on the same port number (TCP for h1/h2, UDP for\n  h3) and advertises `Alt-Svc` so browsers upgrade. Built on the\n  pure-Erlang [`quic`](https://github.com/benoitc/erlang_quic) transport\n  (still 1.x), so treat HTTP/3 as experimental.\n- **Content-Encoding** (RFC 9110 §8.4.1): gzip + deflate with\n  qvalue-aware `Accept-Encoding` negotiation (RFC 9110 §12.5.3),\n  works unchanged over HTTP/2.\n- **WebSocket**: RFC 6455. Conformance harness:\n  [`scripts/autobahn.escript`](https://github.com/arizona-framework/roadrunner/blob/main/scripts/autobahn.escript) (drives the\n  [Autobahn|Testsuite](https://github.com/crossbario/autobahn-testsuite)\n  fuzzingclient).\n- **WebSocket compression**: RFC 7692 `permessage-deflate`,\n  including `*_max_window_bits` and `*_no_context_takeover`.\n\n## Performance at a glance\n\nMedian req/s over HTTP/1.1 on a 12th-gen i9-12900HX, 50 clients,\n2 s warmup + 5 s measure, loopback. HTTP/2 numbers, p50 / p99\npercentiles, and memory shape sit in\n[`docs/bench_results.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/bench_results.md)\nand [`docs/comparison.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/comparison.md).\n\n| scenario                  | roadrunner    | cowboy        | elli          |\n|---------------------------|--------------:|--------------:|--------------:|\n| `hello`                   |   **307 k**   |       201 k   |       299 k   |\n| `json`                    |       299 k   |       189 k   |   **304 k**   |\n| `echo`                    |   **304 k**   |       162 k   |       282 k   |\n| `headers_heavy`           |   **257 k**   |       141 k   |       253 k   |\n| `large_response`          |   **124 k**   |        98 k   |       123 k   |\n| `multi_request_body`      |       262 k   |       125 k   |   **274 k**   |\n| `varied_paths_router`     |   **290 k**   |       175 k   |          —    |\n| `post_4kb_form`           |   **193 k**   |        98 k   |          —    |\n| `large_post_streaming`    |    **20 k**   |       6.9 k   |          —    |\n| `pipelined_h1`            |   **580 k**   |       371 k   |       4.8 k   |\n| `websocket_msg_throughput`|   **232 k**   |       179 k   |          —    |\n| `gzip_response`           |   **138 k**   |       111 k   |          —    |\n\nBold = fastest in row. `—` means the elli fixture doesn't expose\nthat workload (no router, no gzip middleware, no WebSocket, no\nstreaming-POST endpoint). On simple GETs and small POSTs\nRoadrunner and elli are within the bench's ~15 % variance band on\nthose rows; the comparison doc has the full honest framing.\n\n### Tail latency at sustained load\n\nOpen-loop, Coordinated-Omission-corrected (wrk2, `hello`, 8 threads,\n50 connections, 3-run median): Roadrunner sustains **291 k req/s**\nat p50 1.07 ms, p99 2.31 ms, p99.99 4.70 ms. Full per-scenario\nmatrix with all four rate-points per server in\n[`docs/wrk2_results.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/wrk2_results.md).\n\nThe throughput numbers above are from `scripts/bench.escript`\n(closed-loop); the comparison doc has the full methodology\nbreakdown.\n\n## Comparison\n\nIf your workload needs a feature, the server has to ship it. `—`\nmeans achievable in user code but no helper / option built in; `✗`\nmeans out of scope for that server.\n\n| feature                                   | roadrunner | cowboy | elli |\n|-------------------------------------------|:----------:|:------:|:----:|\n| HTTP/1.1                                  |     ✓      |   ✓    |  ✓   |\n| HTTP/2 + HPACK                            |     ✓      |   ✓    |  ✗   |\n| HTTP/3 (QUIC, experimental)               |     ✓      |   ✗    |  ✗   |\n| WebSocket (RFC 6455)                      |     ✓      |   ✓    |  —   |\n| permessage-deflate (RFC 7692)             |     ✓      |   ✓    |  ✗   |\n| Native router                             |     ✓      |   ✓    |  ✗   |\n| gzip / deflate response negotiation       |     ✓      |   ✓    |  —   |\n| Streaming request bodies                  |     ✓      |   ✓    |  —   |\n| Native qs / cookie / multipart            |     ✓      |   ✓    |  —   |\n| Server-Sent Events helper                 |     ✓      |   —    |  —   |\n| Sendfile                                  |     ✓      |   ✓    |  ✓   |\n| Static handler (ETag / Range / IMS)       |     ✓      |   ✓    |  —   |\n| Graceful drain with deadline + broadcast  |     ✓      |   —    |  ✗   |\n| Per-request `request_id` in logger meta   |     ✓      |   —    |  ✗   |\n\n## Quickstart\n\nAdd to `rebar.config`:\n\n```erlang\n{deps, [\n    {roadrunner, \"0.2.1\"}\n]}.\n```\n\nWrite a handler — the third route element is per-route state, threaded\nto the handler via `roadrunner_req:state/1`:\n\n```erlang\n-module(hello_handler).\n-behaviour(roadrunner_handler).\n-export([handle/1]).\n\nhandle(Req) -\u003e\n    #{greeting := Greeting} = roadrunner_req:state(Req),\n    {roadrunner_resp:text(200, \u003c\u003cGreeting/binary, \", roadrunner!\"\u003e\u003e), Req}.\n```\n\nBoot a listener:\n\n```erlang\n1\u003e application:ensure_all_started(roadrunner).\n2\u003e roadrunner:start_listener(my_listener, #{\n       port =\u003e 8080,\n       routes =\u003e [{~\"/\", hello_handler, #{greeting =\u003e ~\"hello\"}}]\n   }).\n```\n\n```\n$ curl -i localhost:8080\nHTTP/1.1 200 OK\ncontent-type: text/plain; charset=utf-8\ncontent-length: 18\n\nhello, roadrunner!\n```\n\nFor HTTP/2 over TLS, add a cert and list both protocols. ALPN is\nderived from `protocols` automatically:\n\n```erlang\n3\u003e roadrunner:start_listener(my_tls_listener, #{\n       port =\u003e 8443,\n       protocols =\u003e [http1, http2],\n       tls =\u003e [\n           {certfile, \"cert.pem\"},\n           {keyfile, \"key.pem\"}\n       ],\n       routes =\u003e [{~\"/\", hello_handler, #{greeting =\u003e ~\"hello\"}}]\n   }).\n```\n\nALPN routes `h2` clients to the HTTP/2 path and `http/1.1` clients (or\nno-ALPN) to the HTTP/1.1 path on the same listener. Drop `http2` from\nthe list to disable HTTP/2. For HTTP/2 on plain TCP (h2c\nprior-knowledge per RFC 7540 §3.4), use `protocols =\u003e [http2]` without\nthe `tls` opt.\n\nFor HTTP/3 (experimental), add `http3` to a TLS listener's `protocols`\n(e.g. `protocols =\u003e [http1, http2, http3]`). It serves h3 over UDP on the\nsame port number and advertises `Alt-Svc` so browsers upgrade from TCP;\nthe `quic` transport starts on demand, so h1/h2-only listeners never boot\nit.\n\nFor listeners that don't need routing, `routes =\u003e Mod` (or\n`{Mod, State}` to seed handler state) skips the router entirely and\ndispatches every request to `Mod:handle/1`:\n\n```erlang\nroadrunner:start_listener(my_listener, #{\n    port =\u003e 8080,\n    routes =\u003e {hello_handler, #{greeting =\u003e ~\"hello\"}}\n}).\n```\n\n## Configuration\n\nAll listener options live in the\n[`roadrunner_listener:opts/0`](https://hexdocs.pm/roadrunner/roadrunner_listener.html#t:opts/0)\ntype, with per-key defaults and tuning rationale. Beyond `port`,\n`protocols`, `tls`, and `routes` from the Quickstart, the type covers:\n\n- **DoS bounds** — `max_clients`, `max_content_length`,\n  `request_timeout`, `keep_alive_timeout`,\n  `min_bytes_per_second`, `max_keep_alive_requests`\n- **Middleware** — `middlewares`\n- **Body buffering** — `body_buffering`\n- **Graceful drain** — `graceful_drain`, `slot_reconciliation`\n- **Per-conn hibernation** — `hibernate_after`\n- **HTTP/2 tunables** (under the `{http2, Opts}` entry in\n  `protocols`) — `conn_window`, `stream_window`,\n  `window_refill_threshold`\n- **HTTP/3 tunables** (under the `{http3, Opts}` entry in\n  `protocols`) — `listeners` (reuseport pool size)\n\n## Features\n\n### Handlers\n\n- **Buffered responses:** `{Status, Headers, Body}` — `roadrunner_resp:text/2`,\n  `:html/2`, `:json/2`, `:redirect/2`, plus empty-status shortcuts.\n- **Streaming:** `{stream, Status, Headers, Fun}` — chunked transfer with a\n  `Send/2` callback; supports trailer headers per RFC 7230 §4.1.2.\n- **Loop / SSE:** `{loop, Status, Headers, State}` + optional\n  `handle_info/3` callback for message-driven push.\n- **WebSocket:** `{websocket, Module, State}` upgrade with\n  `roadrunner_ws_handler` callback.\n- **Sendfile:** `{sendfile, Status, Headers, {Filename, Offset, Length}}` —\n  zero-copy file body via `file:sendfile/5` (TCP) or chunked `ssl:send`\n  fallback (TLS).\n\n### Routing\n\n- `roadrunner_router` with literal / `:param` / `*wildcard` segments.\n- Routes published to `persistent_term` for O(1) lookup;\n  `roadrunner_listener:reload_routes/2` swaps the table without restart.\n\n### Middleware\n\n- Continuation-style `(Req, Next) -\u003e {Response, Req2}` — listener-level +\n  per-route, first-in-list = outermost.\n\n### Built-in handlers\n\n- `roadrunner_static` for file serving with ETag, `If-None-Match`, `Range`,\n  `Last-Modified`, `If-Modified-Since`, and configurable symlink policy\n  (`refuse_escapes` default).\n\n### Hardening\n\n- Strict RFC 9110 / 9112 parsing, with defenses grouped by subsystem:\n    - **Request smuggling / framing:** CL+TE conflict, multiple-CL,\n      chunk-size leading-whitespace rejection.\n    - **Header / control-frame injection:** header CRLF / NUL rejection,\n      SSE event-line CRLF rejection, trailer-header CRLF rejection,\n      RFC 6455 §5.5 control-frame limits, RFC 6265 cookie OWS handling.\n    - **Sendfile path safety:** path traversal + symlink escape defenses.\n- TLS hardened defaults — TLS 1.2 / 1.3 only, AEAD-only cipher filter,\n  client renegotiation off, post-quantum hybrid `x25519mlkem768` first\n  when the OpenSSL build supports it. Full settings list in the\n  `roadrunner_listener` module docs.\n- DoS bounds — `max_clients`, `max_content_length`,\n  `min_bytes_per_second`, `request_timeout`, `keep_alive_timeout`,\n  `max_keep_alive_requests`.\n\n### Observability\n\n- `telemetry` events covering request, response, listener\n  accept / close, slot reconciliation, ws upgrade and frames, and\n  drain ack (opt-in via `roadrunner:acknowledge_drain/1`). Full event\n  list with measurements / metadata in the `roadrunner_telemetry`\n  module docs.\n- Per-request `request_id` attached to `logger:set_process_metadata/1`\n  so any `?LOG_*` from middleware/handlers is auto-correlated.\n- `roadrunner_listener:info/1` for pull-side `active_clients` /\n  `requests_served` metrics.\n- `proc_lib:set_label/1` per-listener / per-acceptor / per-conn for\n  legible `observer` process trees.\n\n### Lifecycle\n\n- `roadrunner_listener:drain/2` — graceful shutdown with timeout. Closes\n  the listen socket, broadcasts `{roadrunner_drain, Deadline}` to in-flight\n  conns via `pg`, polls until idle or deadline, then `exit(Pid, shutdown)`\n  for stragglers.\n- `roadrunner_listener:status/1` — `accepting | draining`.\n- Optional `slot_reconciliation =\u003e #{interval =\u003e N}` listener opt — a\n  periodic reaper that compares `client_counter` against the conn `pg`\n  group and releases slots orphaned by `kill`-style exits. Off by default;\n  enable in production where you can't trust every exit path to run\n  `terminate/3` (`kill` signals, OOM kills, supervisor brutal-kill).\n\n## Documentation\n\n- [`docs/comparison.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/comparison.md) — full side-by-side\n  benchmarks vs cowboy and elli (throughput, latency, architectural\n  trade-offs, reproduction commands).\n- [`docs/bench_results.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/bench_results.md) — full per-protocol\n  matrix with p50 / p99 across every scenario.\n- [`docs/bench_internals.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/bench_internals.md) — loadgen worker\n  model, latency aggregation, when the loader becomes the bottleneck.\n- [`docs/wrk2_results.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/wrk2_results.md) — open-loop,\n  Coordinated-Omission-corrected tail-latency tables (full per-scenario,\n  all rate-points per server).\n- [`docs/resource_results.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/resource_results.md) — memory + CPU\n  shape per scenario.\n- [`docs/conn_lifecycle_investigation.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/conn_lifecycle_investigation.md)\n  — the connection-process model trade-offs and the one h2 case\n  cowboy still wins.\n- [`docs/roadmap.md`](https://github.com/arizona-framework/roadrunner/blob/main/docs/roadmap.md) — deferred items, with rough\n  effort estimates for each.\n\n## Design philosophy\n\n- **RFC-correct, hostile-input-safe.** Parsers are pure incremental\n  binary matchers; only programmer errors raise, wire input always\n  becomes `{error, _}`. Malformed bytes are bounded by length and\n  rejected before reaching application code.\n- **Modern OTP idioms.** Sigils for binary literals, body recursion (cons\n  on the way out), binary keys for wire-derived data, `-doc` /\n  `-moduledoc` markdown, dialyzer-clean specs. No `binary_to_atom` on\n  parsed names.\n- **Continuation-style middleware.** `(Req, Next) -\u003e {Response, Req2}`,\n  composable at listener and per-route level. Outermost first.\n- **Telemetry over custom callbacks.** `telemetry` is the de facto\n  standard (Phoenix, Ecto, gleam_otp); zero-overhead when no subscribers,\n  integrates with prometheus / opentelemetry / datadog out of the box.\n- **No external deps unless stdlib genuinely can't.** Only runtime dep\n  is `telemetry` (tiny, no transitive deps); only dev-time dep is the\n  `erlfmt` plugin.\n\n## Sponsors\n\nRoadrunner is open source and maintained on personal time. If you or your company find it useful,\nconsider [sponsoring](https://github.com/sponsors/williamthome).\n\nI also accept coffees ☕\n\n[![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/williamthome)\n\n\u003ca href=\"https://github.com/sponsors/williamthome\"\u003e\n  \u003cimg\n    src=\"https://raw.githubusercontent.com/williamthome/williamthome/sponsorkit/sponsors.svg\"\n    alt=\"Sponsors\"\n  /\u003e\n\u003c/a\u003e\n\n## Contributing\n\nContributions are welcome! Please see [CONTRIBUTING.md](https://github.com/arizona-framework/roadrunner/blob/main/CONTRIBUTING.md) for development setup,\ntesting guidelines, and contribution workflow.\n\n### Contributors\n\n\u003ca href=\"https://github.com/arizona-framework/roadrunner/graphs/contributors\"\u003e\n  \u003cimg\n    src=\"https://contrib.rocks/image?repo=arizona-framework/roadrunner\u0026max=100\u0026columns=10\"\n    width=\"15%\"\n    alt=\"Contributors\"\n  /\u003e\n\u003c/a\u003e\n\n## Star History\n\n\u003ca href=\"https://star-history.com/#arizona-framework/roadrunner\"\u003e\n  \u003cpicture\u003e\n    \u003csource\n      media=\"(prefers-color-scheme: dark)\"\n      srcset=\"https://api.star-history.com/svg?repos=arizona-framework/roadrunner\u0026type=Date\u0026theme=dark\"\n    /\u003e\n    \u003csource\n      media=\"(prefers-color-scheme: light)\"\n      srcset=\"https://api.star-history.com/svg?repos=arizona-framework/roadrunner\u0026type=Date\"\n    /\u003e\n    \u003cimg\n      src=\"https://api.star-history.com/svg?repos=arizona-framework/roadrunner\u0026type=Date\"\n      alt=\"Star History Chart\"\n      width=\"100%\"\n    /\u003e\n  \u003c/picture\u003e\n\u003c/a\u003e\n\n## License\n\nCopyright (c) 2026 [William Fank Thomé](https://github.com/williamthome)\n\nRoadrunner is open-source under the Apache 2.0 License on\n[GitHub](https://github.com/arizona-framework/roadrunner).\n\nSee [LICENSE.md](https://github.com/arizona-framework/roadrunner/blob/main/LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farizona-framework%2Froadrunner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farizona-framework%2Froadrunner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farizona-framework%2Froadrunner/lists"}