Home › Ktor (Kotlin) › Ktor server rules

Ktor server rules

Cursor rules for Ktor 3 servers in Kotlin: modules, plugins, routing, serialization, auth, StatusPages, and testApplication.

CursorKtor (Kotlin)

How to use

Save this as .cursor/rules/ktor.mdc in your repository root, commit it, and your agent will pick it up automatically. Edit the commands to match your project.

Note: Review and test before use. Provided as is, without warranty. See Terms.

.cursor/rules/ktor.mdcDownload  
---
description: Ktor server conventions
globs: ["src/main/kotlin/**/*.kt","src/main/resources/application.yaml"]
alwaysApply: false
---

# Ktor 3 server

- Entry via `EngineMain` with `application.yaml`, or `embeddedServer(Netty, port = 8080, module = Application::module)`. Each feature is an extension `fun Application.configureOrders(service: OrderService)` called from `module()`.
- Install plugins once: `ContentNegotiation { json() }` (kotlinx.serialization), `StatusPages`, `CallLogging`, `Authentication`, `CORS` (explicit hosts), `RequestValidation`, `DefaultHeaders`.
- Routes grouped with `route("/orders") { get { } post { } }` in `routing { }`, split into `Route.orderRoutes()` extension functions.
- DTOs are `@Serializable data class`es. Read with `call.receive<CreateOrder>()`, validate (RequestValidation or explicit checks), respond with `call.respond(HttpStatusCode.Created, dto)`.
- Path params: `call.parameters["id"]?.toLongOrNull() ?: throw BadRequestException("bad id")`.
- Map exceptions in `StatusPages { exception<NotFoundException> { call, e -> call.respond(HttpStatusCode.NotFound, ErrorDto(e.message)) } }`; don't leak stack traces.
- Auth: `authenticate("jwt") { ... }` blocks around protected routes; get the user from `call.principal<JWTPrincipal>()`.
- Handlers are `suspend`; blocking DB calls go in `withContext(Dispatchers.IO)` or use a suspending driver (Exposed `suspendTransaction`, R2DBC).
- Config from `environment.config` / env vars; no hard-coded secrets.

## Done when
`./gradlew test` passes with `testApplication { application { module() }; client.get(...) }` tests for each route, and `./gradlew ktlintCheck` (or detekt) is clean.

More: all Ktor (Kotlin) rules · all Cursor rules

Related rules

Cloudflare Agents SDK rules

Cursor rules for stateful AI agents on Cloudflare (agents package): Durable Object state, SQL, scheduling, and WebSockets.

CursorCloudflare Workers / Hono

Django Ninja API rules

Cursor rules for Django Ninja APIs on Django 5.2: routers, Pydantic schemas, auth, async views, and tests.

CursorDjango

Django REST Framework rules

Cursor rules for Django 5 + Django REST Framework APIs: serializers, viewsets, permissions, and query performance.

CursorDjango

Fastify 5 API rules

Cursor rules for Fastify 5 APIs in TypeScript: plugins and encapsulation, JSON schema validation, hooks, and inject tests.

CursorNode.js / TypeScript

Go gRPC service rules

Cursor rules for gRPC services in Go with protobuf, buf for codegen and linting, interceptors, and status errors.

CursorGo

GraphQL server (Apollo) rules

Cursor rules for schema-first GraphQL servers with Apollo Server, codegen types, DataLoader, and safe errors.

CursorGraphQL

Get new rules weekly

One email a week: fresh rule files, agent tips, and what's changing in Cursor, Claude Code and Copilot. Free, unsubscribe anytime.

Opens the Rulestack Newsletter on beehiiv in a new tab. Or subscribe directly on beehiiv.