Framework
zio/zio-http avatar
zio/zio-http

ZIO HTTP: a Scala HTTP framework where endpoints are functions

A next-generation Scala framework for building scalable, correct, and efficient HTTP clients and servers

876 stars491 forksScalaApache-2.0

At a glance

What is it?
ZIO HTTP is a Scala framework for HTTP clients and servers built on ZIO and Netty, and the organising idea is that a server or a client is a function from a request to a response. It offers a declarative endpoint description that is type checked against the implementation, middleware, WebSockets, a testkit that needs no live server, and codecs for JSON, Protobuf, Avro and Thrift.
Who is it for?
ZIO HTTP suits a Scala team that wants effectful, type safe HTTP code and is prepared to learn ZIO, since the framework inherits its composability and testability model rather than hiding it. It does not suit a team that wants plain Scala without an effect system, and the version history is worth checking before you start, because the coordinates changed when the project moved to the ZIO organisation.
Can I use it commercially?
Yes. Apache-2.0 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 2 days ago.
What is it written in?
Mainly Scala, according to GitHub's language statistics.

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

Editorial analysis

HTTP as function, in both directions

The design statement is that ZIO HTTP is designed in terms of HTTP as function, where both the server and the client are a function from a request to a response, with a focus on type safety, composability and testability. That framing is more than a slogan, because it is what makes a client and a server symmetric in the API. The project describes itself as a next-generation Scala framework for building scalable, correct and efficient HTTP clients and servers, powered by ZIO and Netty, and calls itself the de facto solution for writing highly scalable and performant web applications in idiomatic Scala. The primary language is Scala, the licence is Apache-2.0, the last push was on 2026-10-20, and the recent releases are v3.11.6, v3.11.5 and v3.11.4 across August and September 2026. The homepage is ziohttp.com, and the project carries a Production Ready stage badge.

Declarative endpoints, and the compiler checks the description

The feature that distinguishes this framework is the type-driven API design, where a declarative description of an endpoint is separated from its logic and the implementation is type checked against the description. So a mismatch between what an endpoint claims to accept and what it actually accepts is a compile error rather than a runtime surprise. There is also an imperative style, where the shape of the endpoint and the logic are defined together, and the documentation is explicit that developers can choose the style that fits. The rest of the feature list explains the supporting cast. Middleware covers cross-cutting concerns such as logging, metrics and authentication. There is built-in error handling at the HTTP layer that distinguishes handled from unhandled errors. WebSockets are supported for real-time applications. And a testkit provides first-class testing utilities that let you write tests without a live server instance, which is the practical payoff of the function framing, since the function is something you can call directly in a test.

A greeting server in about fifteen lines

The getting started example is small enough to read in one go, and it shows the shape of the imperative endpoint style. The server object defines its routes with a Routes block, where a method and a path are matched to a handler, and the root path responds with a fixed string while a /greet path reads a query parameter and builds a greeting from it. The last line serves those routes with the default server configuration:

scala
import zio._
import zio.http._

object GreetingServer extends ZIOAppDefault {
  val routes =
    Routes(
      Method.GET / Root -> handler(Response.text("Greetings at your service")),
      Method.GET / "greet" -> handler { (req: Request) =>
        val name = req.queryOrElse[String]("name", "World")
        Response.text(s"Hello $name!")
      }
    )

  def run = Server.serve(routes).provide(Server.default)
}

The query parameter is read with a fallback, so a request without a name still gets an answer, and the handlers return a Response value rather than writing to an output stream. The whole application is an object extending ZIOAppDefault, and the run method is where the effect is provided, which is the usual ZIO shape of separating a description of what to do from how it runs.

The client is the same shape, with batching

The client example mirrors the server one, and it is short:

scala
import zio._
import zio.http._

object GreetingClient extends ZIOAppDefault {

  val app =
    for {
      client   <- ZIO.serviceWith[Client](_.host("localhost").port(8080))
      request  =  Request.get("greet").addQueryParam("name", "John")
      response <- client.batched(request)
      _        <- response.body.asString.debug("Response")
    } yield ()

  def run = app.provide(Client.default)
}

Two details are worth pulling out. The client is obtained from the environment with a configured host and port rather than constructed directly, which is what makes it substitutable in a test, and the request is built with a query parameter added to it. The call is client.batched, and the body is read as a string and handed to debug for printing, so the response never has to be closed by hand. That is a small instance of the resource management that the framework inherits from ZIO, and it is the difference between a client that leaks connections and one that does not.

The dependency line, and an organisation that changed

Setup is one line in build.sbt:

scala
libraryDependencies += "dev.zio" %% "zio-http" % "3.3.2"

The version notes under it explain a piece of history that will bite anyone following an old tutorial. The older 1.x and 2.x library versions, with the organisation io.d11, are derived from Dream11, the organisation that donated ZIO HTTP to the ZIO organisation in 2022. The newer versions, starting in 2023 from the ZIO organisation, started with 0.0.x and reached 1.0.0 release candidates in April 2023. So the coordinates changed twice, and a dependency line copied from a 2022 blog post will not resolve. The current coordinate is dev.zio with a binary version suffix, and the project is on the 3.x line now, so the example in the readme is behind the current release.

Codecs, templates and OpenAPI in both directions

The data handling is broader than JSON. Built-in support for ZIO Schema enables encoding and decoding of request and response bodies, supporting various data types including JSON, Protobuf, Avro and Thrift, which is a short list that covers most of what a service boundary sees. There is a template system, a built-in DSL for writing HTML templates using Scala code rather than a separate template language. OpenAPI support works in both directions, generating OpenAPI documentation for HTTP applications and conversely generating HTTP endpoints from OpenAPI documentation, so a specification can be the source of the server rather than an artefact produced by it. And ZIO CLI is the route to command line applications that talk to HTTP APIs, which makes the framework useful for a tool rather than only for a service. The repository also carries a datastar SDK, an htmx module, a STOMP module, a metrics module and a gRPC project, so the ecosystem around it is broader than the core.

The repository is a workshop of examples

The top level of the repository is the clearest guide to what the framework covers. There is the core zio-http directory, then a tools directory, a testkit, a metrics module, an htmx module, a STOMP module, a gen directory for code generation, a CLI project, a datastar SDK, and a docs project. Then there is a run of example applications, and their names are a list of authentication schemes: basic auth, cookie auth, digest auth, JWT with a bearer token, JWT with a bearer token and refresh, OAuth bearer token, opaque bearer token, and WebAuthn, plus an example for testing and a plain example. Each is a separate directory, which means each is a small runnable application rather than a snippet in a document, and that is the format to learn from. There is also a docs directory, a website, a benchmarks project, a profiling directory, a specs directory and a grpc project, plus a global.sbt and aliases.sbt for the build, and a .scalafix.conf and .scalafmt.conf so the project lints and formats its own code with the Scala tools.

Editorial conclusion

ZIO HTTP suits a Scala team that wants effectful, type safe HTTP code and is prepared to learn ZIO, since the framework inherits its composability and testability model rather than hiding it. It does not suit a team that wants plain Scala without an effect system, and the version history is worth checking before you start, because the coordinates changed when the project moved to the ZIO organisation. Before you depend on it, read the versioning notes, since the 1.x and 2.x lines are published under a different organisation, and read the usage document for the declarative endpoint style rather than assuming the imperative one is the only way in.

Frequently asked questions

What is the central idea behind ZIO HTTP?

HTTP as function, where both the server and the client are a function from a request to a response. That framing is what makes the two symmetric in the API, and it is the basis of the composability and testability the project claims, since the function can be called directly in a test rather than through a running server.

What does the declarative endpoint style in ZIO HTTP give you?

The description of an endpoint is separated from its logic, and the implementation is type checked against the description, so a mismatch is caught at compile time. An imperative style is also available, where the shape of the endpoint and the logic are defined together, and developers can pick either.

How do I add ZIO HTTP to a build?

With one line in build.sbt, libraryDependencies += "dev.zio" %% "zio-http" % "3.3.2". Note that the coordinates changed when the project was donated to the ZIO organisation in 2022, since the older 1.x and 2.x lines were published under the io.d11 organisation from Dream11.

What codecs and formats does ZIO HTTP support?

ZIO Schema provides built-in encoding and decoding of request and response bodies, supporting data types including JSON, Protobuf, Avro and Thrift. There is also a template system for writing HTML templates in Scala code, OpenAPI support that works in both directions, and built-in WebSocket support.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. zio/zio-http on GitHub
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/zio-zio-http.svg)](https://hysenlabs.com/projects/zio-zio-http)

Was this useful?