# sttp for Scala: HTTP Backends, Effects, and First Request

> sttp is an Apache-2.0 HTTP client library for Scala that supports synchronous, Future-based, and functional-effect styles across JVM, Scala.js, and Scala Native. Its main trade-off is that developers choose both an execution model and a lower-level backend.

**softwaremill/sttp** — The Scala HTTP client you always wanted!

- Repository: https://github.com/softwaremill/sttp
- Website: https://sttp.softwaremill.com
- Stars: 1,507 · Forks: 336
- Language: Scala
- License: Apache-2.0
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/softwaremill-sttp

## What sttp solves for Scala applications

sttp addresses the problem of making HTTP calls without forcing every Scala application into one programming style or transport implementation. The library provides an API for describing requests and interpreting responses. Its documented use cases include JSON APIs, automatic body serialization and deserialization, file uploads and downloads, form submissions, multipart requests, and WebSockets.

The intended audience includes developers building Scala services, command-line programs, reusable libraries, and cross-platform applications. sttp supports direct-style synchronous code, Future-based code, and code built around functional effect systems. The README names cats-effect, ZIO, Monix, Kyo, and scalaz. It supports Scala 2.12, 2.13, and 3, with the JVM implementation requiring Java 11 or later. Scala.js and Scala Native are also listed as supported targets.

This is a Scala-focused HTTP client rather than a thin Java binding. It adds URI interpolation, type-safe HTTP success and error representation, backend selection, and integrations for serialization, logging, metrics, tracing, and streams. That broader abstraction is useful when a codebase needs several HTTP capabilities without exposing transport-specific request APIs throughout the application.

The corresponding cost is dependency and configuration complexity. A basic request can use the preconfigured quick backend, while production code may require an explicit backend and modules for the selected execution and response formats. sttp solves HTTP client access at a library boundary, but it does not make every backend behave identically. Protocol support and connectivity settings depend partly on the implementation underneath sttp.

## How sttp separates requests from transport backends

sttp separates request construction from the component that performs network I/O. In the README quickstart, `quickRequest.get(uri"http://httpbin.org/ip").send()` builds a GET request and sends it through a preconfigured global synchronous backend imported from `sttp.client4.quick`. The expression avoids showing backend setup, which makes it useful for an initial request.

The second README example uses `basicRequest` and `DefaultSyncBackend`. This makes the execution and transport choice explicit. A query value is inserted through URI interpolation, and the documentation states that it is URL-encoded automatically. An optional query parameter whose value is `None` is omitted. After execution, `response.header(...)` returns an `Option[String]`, while `response.body` represents the payload as an `Either[String, String]` in that example.

The repository layout supports this separation. `core/` contains the central client library, while `akka-http-backend/`, `pekk[o]-http-backend/`, `http4s-backend/`, `okhttp-backend/`, `armeria-backend/`, and `finagle-backend/` are separate backend modules. The README also names Java's `HttpClient` as an underlying implementation. Applications can therefore retain sttp's request model while choosing a backend that matches their runtime or existing dependencies.

Optional modules form another layer. The README names JSON libraries including circe, uPickle, jsoniter, json4s, play-json, and ZIO Json. It also lists slf4j, scribe, OpenTelemetry, Prometheus, fs2, ZIO Streams, Akka Streams, and Pekko Streams as integration points. This permits a shared request API without pretending that serialization, logging, metrics, and streaming have no external dependencies.

The boundary remains important. sttp controls its own request and response abstractions, but DNS, connection handling, protocol support, redirects, and other transport behavior can vary by backend. The README does not publish a complete capability matrix, so backend choice should be based on the target platform and application requirements rather than names alone.

## Installing sttp and sending the first request

The README offers scala-cli, Ammonite, and sbt as initial setup paths. For scala-cli, the dependency directive selects the current `core` artifact. Importing `sttp.client4.quick.*` brings in the API and its preconfigured global synchronous backend.

```scala
//> using dep "com.softwaremill.sttp.client4::core:4.0.27"
import sttp.client4.quick.*
quickRequest.get(uri"http://httpbin.org/ip").send()
```

Run this from a suitable scala-cli source file to make the request shown by the README. The library returns a response rather than requiring the application to print it in this example. The documentation does not define the endpoint's response contents as an sttp contract, so applications should inspect the returned response instead of depending on a particular `/ip` payload.

For an sbt build, add the core module to the project dependencies.

```scala
"com.softwaremill.sttp.client4" %% "core" % "4.0.27"
```

Then import the standard sttp API and construct a request with `basicRequest`.

```scala
import sttp.client4.*

val backend = DefaultSyncBackend()
val response = request.send(backend)
println(response.body)
```

This second path is more explicit than the quick helper because it creates a synchronous backend in the example. Applications built around Future or functional effects should not transplant this synchronous pattern without selecting the corresponding sttp module and execution environment. The core dependency supplies the basic client library, while optional functionality requires its respective integration modules.

## Choosing a backend for JVM, Scala.js, or Scala Native

Backend selection determines which lower-level implementation handles connections and network communication. The README identifies Java's `HttpClient`, Akka HTTP, Pekko HTTP, http4s, OkHttp, and Armeria. Repository directories also show dedicated Finagle support. Each option connects a different implementation to sttp's Scala request and response model.

That architecture is useful when an application already depends on one of those stacks. A service built around Akka HTTP may prefer the Akka HTTP backend because it is already aligned with its execution ecosystem. An application seeking a separate transport abstraction can inspect the documented backend modules rather than rewriting every request around an engine-specific client API.

Choice is especially important outside the JVM. sttp supports Scala.js and Scala Native, but the README excerpt does not state that every named backend is available for every platform. It also does not provide a complete comparison of proxy handling, HTTP protocol versions, connection pooling, streaming semantics, or cancellation. Those gaps make the first backend proof of concept more significant than choosing solely by implementation name.

The quick backend is appropriate for experimentation because it requires little setup. For a production service, an explicitly managed backend gives developers a visible lifecycle and a clearer place to investigate transport behavior. That does not mean every project requires separate backend instances. It means the decision between convenience and explicit control is visible in the code.

Backend compatibility must also be checked against Scala versions and external libraries. The repository is organized as a multi-module build, and the README warns that a default compile can include JVM, Native, and JS backends. A project should select the smallest relevant module set and verify that its external runtime dependencies match the chosen backend.

## JSON, effects, observability, and stream module costs

sttp's core API addresses requests and responses, but practical applications often need more. For JSON APIs, the README states that integrations can serialize request bodies and deserialize response bodies automatically. It names circe, uPickle, jsoniter, json4s, play-json, and ZIO Json. Choosing one requires matching its module and execution context to the application. Installing every JSON integration would add dependencies without solving a stated need.

Execution style is another separate decision. The README supports synchronous direct style, Future-based code, and functional effects through cats-effect, ZIO, Monix, Kyo, and scalaz. The repository's `effects/` directory and example projects indicate dedicated organization around these models. Synchronous calls are straightforward when blocking is acceptable, while effect-based applications need cancellation and resource handling to fit their runtime. The README quickstart does not document all differences among effect APIs, so an existing effect system should drive the selection.

Observability modules connect sttp to slf4j, scribe, OpenTelemetry, and Prometheus. Streaming integrations cover fs2, ZIO Streams, Akka Streams, and Pekko Streams. These names establish integration availability, but the excerpt does not state which metrics are emitted automatically, how tracing spans are configured, or whether every streaming module supports every backend. Those details must be verified in the module documentation before an application treats them as an operational contract.

Testing has dedicated repository support under `testing/`, and the README mentions tools for testing HTTP interactions. That is useful when an application needs to control client responses, but no replacement server or exact test procedure is documented in the quickstart. The boundary is clear enough for evaluation: sttp supports the surrounding concerns, while the application still has to choose compatible modules and verify their runtime behavior.

## Maintenance, licensing, and cross-platform build scope

The repository is not archived, its last push was on 2026-10-15, and the listed v4 releases were published on 2026-09-25, 2026-07-08, and 2026-05-29. These facts show recent repository and release activity. The README does not define a long-term support policy, so projects should not infer one from the release sequence.

The repository declares the Apache-2.0 license. That applies to the project as identified by the repository, while applications still need to review the licenses and notices of separately selected backend, JSON, effect, logging, metrics, and tracing dependencies. This is a dependency review point, not a conclusion that every included module has identical obligations.

Upgrades require attention to module compatibility. Moving from one sttp backend to another can affect network behavior without changing request construction. Moving between synchronous and effect-based execution changes application code more substantially. Updating a JSON, observability, or streaming integration also requires checking the external library version rather than changing `core` alone.

The multi-platform build is the clearest documented upgrade constraint. The README warns that default compile and test tasks build JVM, Native, and JS backends and may exhaust memory or encounter missing native dependencies. For JVM-only work on Scala 3, it documents these narrower tasks:

```bash
sbt "compileScoped 3 JVM"
```

Use the documented test counterpart when running the JVM-only test suite.

```bash
sbt "testScoped 3 JVM"
```

These commands do not verify every published platform. A cross-platform release should instead validate each supported target and backend selected by the application.

## sttp adoption limits for small scripts and transport-specific code

sttp is the wrong level of abstraction for a very small script that needs one request and has no Scala requirements beyond compilation. The quick API reduces setup, but it still adds a library dependency and a response model. A direct runtime client may be simpler when the script runs only in one environment and does not benefit from sttp's serialization, effect, or backend options. That is a scope judgement rather than a statement about transport quality.

It can also be unsuitable for an architecture that deliberately standardizes on the native API of one backend. In that case, backend-specific configuration, connection behavior, or instrumentation may be more direct than passing operations through sttp's abstraction. Adding multiple backends has value only when the application can support and test the selected options.

The README does not document all operational details needed for a final adoption decision. It does not provide a complete timeout, redirect, proxy, retry, HTTP version, or connection-pool matrix, nor does it give upgrade compatibility guarantees for external integrations. Those omissions matter for applications with strict network policies.

sttp should be evaluated on the exact combination of Scala version, execution model, backend, and optional modules. A synchronous JVM prototype can be completed quickly with `quickRequest`, but a production service should first confirm backend-specific behavior and optional integration requirements. That sequence avoids treating the quickstart's convenience as proof that every target has identical capabilities.

## Conclusion

sttp is a good fit for Scala applications that want typed request construction, selectable execution models, and interchangeable HTTP backends. It is less suitable for a project that wants one vendor-specific transport with no Scala abstraction. Before adopting it, verify the backend for the target platform, the required synchronous or effect-based execution model, and the modules needed for JSON, logging, metrics, tracing, streaming, or testing.

## FAQ

### How do I install sttp in a Scala project?

For sbt, add `com.softwaremill.sttp.client4` with the `core` module at version `4.0.27`, then import `sttp.client4.*`. The README also provides scala-cli and Ammonite dependency directives.

### Which HTTP backends does sttp support?

The README names Java's `HttpClient`, Akka HTTP, Pekko HTTP, http4s, OkHttp, and Armeria. The repository also contains a `finagle-backend/` directory. Backend behavior and platform availability must be checked for the selected target.

### Does sttp support functional effects and non-JVM Scala platforms?

The README states support for cats-effect, ZIO, Monix, Kyo, and scalaz. It lists Scala 2.12, 2.13, 3, JVM, Scala.js, and Scala Native as supported targets, with Java 11 or later required on the JVM.

## Sources

- [License: Apache-2.0](https://github.com/softwaremill/sttp/blob/master/LICENSE)
- [Project website](https://sttp.softwaremill.com)
- [README](https://github.com/softwaremill/sttp/blob/master/README.md)
- [Releases](https://github.com/softwaremill/sttp/releases)
- [softwaremill/sttp on GitHub](https://github.com/softwaremill/sttp)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/softwaremill-sttp
