# softwaremill/tapir: Typed Scala HTTP APIs with OpenAPI Documentation

> Tapir is a Scala library for defining HTTP endpoints once and using that definition for server routes, clients, OpenAPI documentation, JSON Schema, AsyncAPI, and observability metadata. It fits teams that want typed HTTP contracts without replacing their existing server or client stack.

**softwaremill/tapir** — Rapid development of self-documenting APIs

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

## Tapir's HTTP contract model

Tapir addresses a specific problem in Scala HTTP development: endpoint contracts are often duplicated between route declarations, request parsing, client calls, tests, and documentation. Tapir moves the contract into a declarative endpoint definition that describes inputs, outputs, and errors, while server logic remains separate. The README describes this as separating the shape of an endpoint, the "what", from the server logic, the "how".

The basic unit is an endpoint. Inputs identify path segments, query parameters, headers, and bodies. Outputs describe response bodies, while error outputs can represent expected failures separately from successful responses. A handler then supplies the implementation. The compact README example shows a GET endpoint with a path and a string query parameter:

```scala
endpoint
  .get.in("hello").in(query[String]("name"))
  .out(stringBody)
  .handleSuccess(name => s"Hello, $name!")
```

In this definition, `endpoint` supplies the API context, `get` selects the HTTP method, `in("hello")` adds the path, and `query[String]("name")` declares a required query input. `stringBody` describes the successful response body. `handleSuccess` associates the contract with a Scala function. The resulting definition can be exposed as a server route, consumed through a client, and used as the basis for generated documentation.

That distinction matters for larger services. Endpoint definitions can be reused, composed, or shared with tests and generated clients. The README specifically lists reuse of common endpoint definitions and individual inputs or outputs as a reason to use Tapir. The library does not impose a single application architecture. It can define an entire API or sit beside routes implemented through native mechanisms of the surrounding stack.

## Server, client, and documentation flow

Tapir's main architectural advantage is that one endpoint definition can feed several delivery paths. A server adapter turns the endpoint into an HTTP route and invokes the handler after interpreting the declared inputs. A client adapter uses the same contract to construct requests and interpret responses. Documentation modules turn the contract into OpenAPI, AsyncAPI, or JSON Schema output.

This creates a common metadata layer rather than three independent descriptions. The same information that describes a path and query parameter can support request decoding on a server, request construction in a client, and documentation generation. The README also identifies observability as an output of Tapir metadata, including the ability to report metrics and tracing information. The repository layout reflects separate areas for `server`, `client`, `openapi-codegen`, `metrics`, `observability`, and `tracing`, indicating that these are modular concerns rather than one all-or-nothing runtime.

The integrations are broad, but they are not identical to choosing a complete web framework. Tapir describes itself as a library, not a framework. The README says it supports popular Scala HTTP server implementations and can expose Tapir-managed routes alongside native routes. That makes gradual adoption possible for an existing service, or useful when only selected use cases need typed endpoint definitions. The corresponding trade-off is that developers must understand the adapter and integration modules they select, rather than receiving a fixed server, deployment model, or runtime configuration.

## Installation and the first Tapir endpoint

The repository README does not provide a complete installation command, dependency list, or copy-and-run hello-world project. It directs readers to the documentation for tutorials, runnable examples, and reference material. The Maven Central badge shown in the README refers to `com.softwaremill.sttp.tapir:tapir-core_3`, which identifies the published core artifact for the Scala 3 module, but it does not state the complete build configuration needed for an application.

For a first use, the documentation's hello-world tutorial is the correct starting point because it is where the project provides the surrounding build setup and server wiring. The README itself gives the endpoint definition example below. After defining the endpoint, the remaining steps depend on the selected server integration: bind the handler to a route and provide the server-specific startup configuration. Those details are not present in the README excerpt, so they should not be invented here.

```scala
endpoint
  .get.in("hello").in(query[String]("name"))
  .out(stringBody)
  .handleSuccess(name => s"Hello, $name!")
```

The expected contract is a GET request to `/hello` with a `name` query parameter and a string response containing the greeting. The README does not document a default port, a command for launching the tutorial, or a curl command for calling it. It also does not show how to generate the OpenAPI document in this example. Those operations must be taken from the relevant Tapir documentation and the selected integration.

## OpenAPI, AsyncAPI, and observability metadata

Documentation generation is one of Tapir's clearest differentiators. The README states that documentation can be generated in OpenAPI, AsyncAPI, and JSON Schema formats. OpenAPI is the appropriate format for describing HTTP interfaces, while AsyncAPI is relevant when the endpoint model covers asynchronous interfaces. JSON Schema can describe structured values independently of a complete HTTP document.

The practical benefit is contract reuse, not automatic agreement between generated documentation and deployed behavior. Developers must keep endpoint declarations, input schemas, outputs, and error mappings aligned with the server implementation and serialization configuration. The README does not claim that every integration produces identical output, and it does not document a compatibility policy for generated files in this excerpt.

Observability is handled through metadata as well. Tapir's endpoint definition can expose information used for metrics and tracing, according to the README. This can reduce the need to duplicate route information in monitoring code, but it does not mean that Tapir configures every monitoring backend. The repository contains separate `metrics`, `observability`, and `tracing` areas, suggesting that selecting and wiring those integrations remains part of application setup. Teams should verify which backend and instrumentation library their Scala version supports before adopting the documentation or observability path.

## Constraints and alternatives to Tapir

Tapir's main constraint is the amount of Scala-specific structure it adds around HTTP interfaces. Endpoint definitions require developers to express method, path, inputs, outputs, and errors in Tapir's combinator API. That structure can improve compile-time feedback and make contracts reusable, but it can also be more involved than writing a small route directly with the underlying HTTP library.

Tapir is also the wrong tool when the project is not built in Scala, or when the team specifically wants generated documentation without adopting a typed endpoint model. In that case, an OpenAPI-first workflow may be more direct: write an OpenAPI document, use code generation, and generate server or client interfaces from it. That approach reverses the direction of authority. Tapir starts with Scala definitions and generates or exposes documentation from them; an OpenAPI-first workflow starts with the specification and generates code.

Another limitation is that the README does not document rollback procedures, migration instructions between major versions, or a complete compatibility matrix. It does show recent releases v1.13.31, v1.13.32, and v1.13.33, but release numbers alone do not establish upgrade cost. Projects should inspect the release notes and module-specific documentation for migration details before changing an established API definition.

Tapir also leaves transport choices open. That flexibility is useful when retaining an existing stack, but it means there is no single Netty, Akka HTTP, http4s, Play, or client configuration implied by the core library. The README highlights a Netty-based server as a performance-oriented option, but this excerpt does not provide the configuration or measurements needed to make a comparative performance claim.

## Maintenance and Apache-2.0 implications

The repository is not archived, and the last push was on 2026-10-15. Recent releases include v1.13.33 on 2026-10-07, v1.13.32 on 2026-09-26, and v1.13.31 on 2026-08-07. These facts indicate recent repository activity, but they do not by themselves guarantee compatibility for every integration or eliminate upgrade work.

The project is licensed under Apache-2.0. That license generally provides the permissions and conditions associated with the Apache License 2.0, including use, modification, distribution, and patent-related terms, subject to the license text and its conditions. This article does not provide legal advice. Teams should review the repository `LICENSE` file and any notices for dependencies or generated artifacts used in a particular distribution.

For maintenance planning, the relevant cost is likely concentrated in Scala and library compatibility, adapter upgrades, documentation changes, and any changes to endpoint contracts. The repository includes `build.sbt`, integration modules, tests, examples, and generated documentation, which indicates a sizable multi-module project. Before adopting it for a long-lived service, check the documentation for the exact server, client, JSON, and observability modules, then compare their release compatibility with the versions used by the application.

## Conclusion

Tapir is a strong fit for Scala teams that want reusable HTTP contracts and generated documentation while retaining their preferred server, client, JSON, and observability libraries. It is less suitable when a project does not need a typed contract layer or cannot accept an additional Scala API abstraction. Verify first that the required server, client, serialization, documentation, and observability integrations are available in the selected modules.

## FAQ

### What is softwaremill/tapir used for?

Tapir is a Scala library for declaring HTTP APIs, exposing those definitions as server endpoints, consuming them as clients, and generating documentation such as OpenAPI and JSON Schema. The same endpoint metadata can also support metrics and tracing integrations.

### Does softwaremill/tapir replace an existing Scala HTTP framework?

No. The README describes Tapir as a library rather than a framework and says it can expose Tapir-managed routes alongside native routes. The project supports integration with multiple Scala HTTP server implementations, so it can fit an existing stack.

### How do I install softwaremill/tapir?

The README does not include a complete installation command or dependency configuration. It links to the Tapir tutorials and runnable examples, and shows the Maven Central artifact `com.softwaremill.sttp.tapir:tapir-core_3` in its badge.

## Sources

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

---

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