Introduction

What Connect-Ktor is, who it is for, and how it relates to Connect-Kotlin.

Introduction

Connect-Kotlin already gives JVM and Android clients a typed Connect client. Connect-Ktor answers the other half of that sentence: a Ktor server that can accept those calls without abandoning the REST routes already in production.

It is an unofficial community library — useful and conformance-tested, but not a ConnectRPC organization product.

These pages cover the Ktor server side. For Connect itself, Connect-Kotlin clients, or the protocol rules, prefer the official material:

The gap it fills

Connect has strong client libraries and a clear protocol story. On the JVM server side, many teams still run Ktor with handwritten JSON REST.

Rewriting that surface as gRPC is often the wrong trade. gRPC wants HTTP/2 end-to-end, a different tooling culture, and a sharper break from browser-friendly APIs.

Connect sits closer to ordinary HTTP. Unary calls look like POST (or GET when idempotent). JSON and binary Protobuf both work. That is why it fits an existing Ktor app: you add handlers, you do not replace the transport stack.

What you get today

  • Unary, client-streaming, server-streaming, and half-duplex bidi Connect handlers on CIO and Netty
  • connectJson() / connectProto() ContentNegotiation codecs
  • Generated Ktor route interfaces via protoc-gen-connect-ktor
  • Optional protovalidate request checks, body size limits, and gzip guards

Full-duplex bidi streaming is supported with Netty over HTTP/2. gRPC/gRPC-Web are still out of scope. See Known limitations for the honest matrix, and Conformance for what the suite actually exercises.

Relationship to Connect-Kotlin

Connect-Ktor reuses Connect-Kotlin types and serialization strategies on the server. Handlers return ResponseMessage, throw ConnectException, and speak the same error model clients already expect.

Client APIs, interceptors, transports, and Android setup belong in the official Connect-Kotlin docs and the connect-kotlin repository — this site does not restate them.

Code generation is split on purpose:

  • protoc-gen-connect-kotlin (official) produces clients
  • protoc-gen-connect-ktor (this project) produces Ktor route handler interfaces

Both read the same .proto services. A React app on Connect-ES and a Ktor service on Connect-Ktor can share one Buf module without inventing a parallel schema.

Who it is for

  • Teams with a Ktor REST API who want Protobuf RPCs for new or hot paths
  • Stacks that already pair React (Connect-ES) with Kotlin/Ktor
  • Services that need Connect conformance for unary, client-streaming, server-streaming, and bidirectional RPCs

Full-duplex streams are supported with Netty over HTTP/2. It is a poor fit if you need gRPC wire compatibility. See Known limitations for engine and streaming constraints.

Design stance

Prefer coexistence over conversion. A single embeddedServer can expose /api/v1/... REST routes and /package.Service/Method Connect procedures at once.

Prefer protocol honesty over completeness theater. Unsupported axes stay ❌ in the matrix until the implementation and the conformance pins agree.

When the mental model clicks, Getting started is the shortest path to a handler running beside REST.