Skip to main content
rule

kotlin-ktor-development-cursorrules-prompt-file — Cursor rule

This Cursor rule guides Kotlin projects built with Ktor. Use it when shaping API layers, feature folders, error handling, and tests.

Install into Cursor · Manually: put the files in place All methods and platforms ↓
.cursor/rules/kotlin-ktor-development-cursorrules-prompt-file.mdc
Open on GitHub

What kotlin-ktor-development-cursorrules-prompt-file does

The rule applies to **/* and steers the project toward business-feature folders rather than technical layers. It separates route handlers, services, repositories, entities, and DTOs, while keeping related code under each feature. Constructor injection, validation, repository interfaces, and StatusPages error handling are part of the guidance.

Its stack targets Kotlin 2.1.20+, Ktor, JDK 21, and Gradle with Kotlin DSL. It also names Exposed, HikariCP, kotlinx.serialization, Koin, kotlin-logging, and Kotest. Testing guidance covers unit tests, Ktor 3.x route tests, edge cases, failure paths, and coverage targets of 80% overall and 90% for repositories, services, and validation. Projects outside this stack will need adjusted instructions.

What it helps with

  • organize Kotlin code by business feature
  • separate route, service, and repository responsibilities
  • handle API failures with StatusPages
  • test services and Ktor routes with Kotest
  • structure a project around Gradle Kotlin DSL

Example prompts for the agent

  • Organize a new users module by business feature, with separate routes, services, and repositories.
  • Add GET /api/users/{id} with UUID validation and a testApplication route test.
  • Write service tests for an existing user and for ResourceNotFoundException.

How to install kotlin-ktor-development-cursorrules-prompt-file

Manually: put the files in place

.cursor/rules/kotlin-ktor-development-cursorrules-prompt-file.mdc

Frontmatter: description, globs, alwaysApply

Step by step, with commands for each platform: Cursor rules: .mdc files, four modes and what replaced .cursorrules

Questions about kotlin-ktor-development-cursorrules-prompt-file

How do I install kotlin-ktor-development-cursorrules-prompt-file in Cursor?

Save the rule at .cursor/rules/kotlin-ktor-development-cursorrules-prompt-file.mdc in the project.

What does kotlin-ktor-development-cursorrules-prompt-file do?

It guides Cursor through Ktor application structure, layer boundaries, error handling, dependency injection, and testing practices.

Which Kotlin and Ktor stack does the rule target?

It targets Kotlin 2.1.20+, JDK 21, Ktor, and Gradle with Kotlin DSL. The listed libraries include Exposed, HikariCP, kotlinx.serialization, Koin, kotlin-logging, and Kotest.

Source text

kotlin-ktor-development-cursorrules-prompt-file.mdc · CC0-1.0
---
description: "Cursor rules for Kotlin development with Ktor integration."
globs: **/*
alwaysApply: false
---
## Instruction to developer: save this file as .cursorrules and place it on the root project directory

## Core Principles
- Follow **SOLID**, **DRY**, **KISS**, and **YAGNI** principles
- Adhere to **OWASP** security best practices
- Break tasks into smallest units and solve problems step-by-step

## Technology Stack
- **Framework**: Kotlin Ktor with Kotlin 2.1.20+
- **JDK**: 21 (LTS)
- **Build**: Gradle with Kotlin DSL
- **Dependencies**: Ktor Server Core/Netty, kotlinx.serialization, Exposed, HikariCP, kotlin-logging, Koin, Kotest

## Application Structure (Feature-Based)
- **Organize by business features, not technical layers**
- Each feature is self-contained with all related components
- Promotes modularity, reusability, and better team collaboration
- Makes codebase easier to navigate and maintain
- Enables parallel development on different features
```
src/main/kotlin/com/company/app/
├── common/              # Shared utilities, extensions
├── config/              # Application configuration, DI
└── features/
    ├── auth/            # Feature directory
    │   ├── models/
    │   ├── repositories/
    │   ├── services/
    │   └── routes/
    └── users/           # Another feature
        ├── ...
```

Test structure mirrors the feature-based organization:
```
src/test/kotlin/com/company/app/
├── common/
└── features/
    ├── auth/
    │   ├── models/
    │   ├── repositories/
    │   ├── services/
    │   └── routes/
    └── users/
        ├── ...
```

## Application Logic Design
1. Route handlers: Handle requests/responses only
2. Services: Contain business logic, call repositories
3. Repositories: Handle database operations
4. Entity classes: Data classes for database models
5. DTOs: Data transfer between layers

## Entities & Data Classes
- Use Kotlin data classes with proper validation
- Define Table objects when using Exposed ORM
- Use UUID or auto-incrementing integers for IDs

## Repository Pattern
```kotlin
interface UserRepository {
    suspend fun findById(id: UUID): UserDTO?
    suspend fun create(user: CreateUserRequest): UserDTO
    suspend fun update(id: UUID, user: UpdateUserRequest): UserDTO?
    suspend fun delete(id: UUID): Boolean
}

class UserRepositoryImpl : UserRepository {
    override suspend fun findById(id: UUID): UserDTO? = withContext(Dispatchers.IO) {
        transaction {
            Users.select { Users.id eq id }
                .mapNotNull { it.toUserDTO() }
                .singleOrNull()
        }
    }
    // Other implementations...
}
```

## Service Layer
```kotlin
interface UserService {
    suspend fun getUserById(id: UUID): UserDTO
    suspend fun createUser(request: CreateUserRequest): UserDTO
    suspend fun updateUser(id: UUID, request: UpdateUserRequest): UserDTO
    suspend fun deleteUser(id: UUID)
}

class UserServiceImpl(
    private val userRepository: UserRepository
) : UserService {
    override suspend fun getUserById(id: UUID): UserDTO {
        return userRepository.findById(id) ?: throw ResourceNotFoundException("User", id.toString())
    }
    // Other implementations...
}
```

## Route Handlers
```kotlin
fun Application.configureUserRoutes(userService: UserService) {
    routing {
        route("/api/users") {
            get("/{id}") {
                val id = call.parameters["id"]?.let { UUID.fromString(it) }
                    ?: throw ValidationException("Invalid ID format")
                val user = userService.getUserById(id)
                call.respond(ApiResponse("SUCCESS", "User retrieved", user))
            }
            // Other routes...
        }
    }
}
```

## Error Handling
```kotlin
open class ApplicationException(
    message: String,
    val statusCode: HttpStatusCode = HttpStatusCode.InternalServerError
) : RuntimeException(message)

class ResourceNotFoundException(resource: String, id: String) :
    ApplicationException("$resource with ID $id not found", HttpStatusCode.NotFound)

fun Application.configureExceptions() {
    install(StatusPages) {
        exception<ResourceNotFoundException> { call, cause ->
            call.respond(cause.statusCode, ApiResponse("ERROR", cause.message ?: "Resource not found"))
        }
        exception<Throwable> { call, cause ->
            call.respond(HttpStatusCode.InternalServerError, ApiResponse("ERROR", "An internal error occurred"))
        }
    }
}
```

## Testing Strategies and Coverage Requirements

### Test Coverage Requirements
- **Minimum coverage**: 80% overall code coverage required
- **Critical components**: 90%+ coverage for repositories, services, and validation
- **Test all edge cases**: Empty collections, null values, boundary conditions
- **Test failure paths**: Exception handling, validation errors, timeouts
- **All public APIs**: Must have integration tests
- **Performance-critical paths**: Must have benchmarking tests

### Unit Testing with Kotest
```kotlin
class UserServiceTest : DescribeSpec({
    describe("UserService") {
        val mockRepository = mockk<UserRepository>()
        val userService = UserServiceImpl(mockRepository)

        it("should return user when exists") {
            val userId = UUID.randomUUID()
            val user = UserDTO(userId.toString(), "Test User", "[email protected]")
            coEvery { mockRepository.findById(userId) } returns user

            val result = runBlocking { userService.getUserById(userId) }

            result shouldBe user
        }

        it("should throw exception when user not found") {
            val userId = UUID.randomUUID()
            coEvery { mockRepository.findById(userId) } returns null

            shouldThrow<ResourceNotFoundException> {
                runBlocking { userService.getUserById(userId) }
            }
        }
    }
})
```

## Route Testing with Ktor 3.x
```kotlin
class UserRoutesTest : FunSpec({
    test("GET /api/users/{id} returns 200 when user exists") {
        val mockService = mockk<UserService>()
        val userId = UUID.randomUUID()
        val user = UserDTO(userId.toString(), "Test User", "[email protected]")

        coEvery { mockService.getUserById(userId) } returns user

        testApplication {
            application {
                configureRouting()
                configureDI { single { mockService } }
            }

            client.get("/api/users/$userId").apply {
                status shouldBe HttpStatusCode.OK
                bodyAsText().let {
                    Json.decodeFromString<ApiResponse<UserDTO>>(it)
                }.data shouldBe user
            }
        }
    }
})
```

## Key Principles for Testable Code
1. **Single Responsibility**: Each method should do one thing well
2. **Pure Functions**: Same input always produces same output
3. **Dependency Injection**: Constructor injection for testable components
4. **Clear Boundaries**: Well-defined inputs and outputs
5. **Small Methods**: Extract complex logic into testable helper functions

## Configuration Management
```kotlin
// Type-safe configuration
interface AppConfig {
    val database: DatabaseConfig
    val security: SecurityConfig
}

data class DatabaseConfig(
    val driver: String,
    val url: String,
    val user: String,
    val password: String
)

// Access in application
fun Application.configureDI() {
    val appConfig = HoconAppConfig(environment.config)

    install(Koin) {
        modules(module {
            single<AppConfig> { appConfig }
            single { appConfig.database }
        })
    }
}
```

## Security Best Practices
```kotlin
fun Application.configureSecurity() {
    install(Authentication) {
        jwt("auth-jwt") {
            // JWT configuration
        }
    }

    install(DefaultHeaders) {
        header(HttpHeaders.XContentTypeOptions, "nosniff")
        header(HttpHeaders.XFrameOptions, "DENY")
        header(HttpHeaders.ContentSecurityPolicy, "default-src 'self'")
        header("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
    }
}
```

## Health Checks & Monitoring
```kotlin
fun Application.configureMonitoring() {
    val startTime = System.currentTimeMillis()

    routing {
        get("/health") {
            call.respond(mapOf("status" to "UP", "uptime" to "${(System.currentTimeMillis() - startTime) / 1000}s"))
        }

        get("/metrics") {
            call.respond(prometheusRegistry.scrape())
        }
    }

    install(MicrometerMetrics) {
        registry = PrometheusMeterRegistry(PrometheusConfig.DEFAULT)
        meterBinders = listOf(
            JvmMemoryMetrics(),
            JvmGcMetrics(),
            ProcessorMetrics(),
            JvmThreadMetrics()
        )
    }
}
```

## Performance Tuning
- **JVM Settings**: `-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:MaxRAMPercentage=75.0`
- **Connection Pooling**: Configure HikariCP with proper sizing based on workload
- **Caching**: Use Caffeine for in-memory caching of frequently accessed data
- **Coroutines**: Use structured concurrency for asynchronous processing
- **Database Queries**: Optimize with proper indexing, batch operations, pagination

© PatrickJS · CC0-1.0 · PatrickJS/awesome-cursorrules

Similar IDE rules

All IDE rules for Backend and APIs →

From the same set210

landing-page-image-quality-cursorrules-prompt-file Stops Cursor from injecting placeholder image URLs into user-facing pages, requiring real project assets, fixed dimensions, and valid alt attributes. ★ 41,024repo stars kubestellar-console Rules for KubeStellar Console development across its React/TypeScript frontend and Go backend. Useful for dashboard cards and multi-cluster queries. ★ 41,024repo stars kubernetes-mkdocs-documentation-cursorrules-prompt A Cursor rule that turns the agent into a technical writer for Kubernetes and cloud native docs built with Markdown and MkDocs. ★ 41,024repo stars kotlin-springboot-best-practices-cursorrules-prompt-file A Cursor rule for Kotlin and Spring Boot projects. It enforces layered package structure, constructor injection, and idiomatic Kotlin conventions. ★ 41,024repo stars knative-istio-typesense-gpu-cursorrules-prompt-fil A Cursor rule that turns the assistant into a helper for serverless projects built on Knative with Istio, Typesense and HTMX. Useful when your search app runs on that stack. ★ 41,024repo stars jest-unit-testing-cursorrules-prompt-file Guides Cursor to generate structured Jest unit tests in JavaScript and TypeScript. Enforces dependency mocking before imports and covers edge cases. ★ 41,024repo stars javascript-typescript-code-quality-cursorrules-pro A Cursor rule for cleaner JavaScript and TypeScript work. It guides code structure, comments, function order, and narrowly scoped edits. ★ 41,024repo stars javascript-chrome-apis-cursorrules-prompt-file A Cursor rule that points the AI agent at Chrome extension work: manifest, architecture, Chrome API usage. ★ 41,024repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor