KtKit
A comprehensive Kotlin multiplatform toolkit for building server applications with Ktor.
🏠 Homepage (under construction)
Usage
implementation("io.github.smyrgeorge:ktkit:x.y.z")Overview
KtKit is a Kotlin multiplatform toolkit designed to speed up server-side application development with Ktor. It brings together several libraries into a cohesive set of tools that handle the repetitive aspects of backend development.
Note
Early Stage Project: KtKit is actively evolving. APIs may change between versions as we refine the abstractions based on real-world usage. Production use is possible but expect some breaking changes. Feedback and contributions are highly appreciated!
What it does (today):
- Provides a small application bootstrap around Ktor with DI, JSON, and auto-registered REST handlers
- Standardizes request handling with tracing, auth/permissions hooks, and RFC 9457-style API errors
- Exposes basic health and metrics endpoints for services built on the toolkit
- Offers TOML configuration loading with environment-variable interpolation and file/resource merging
- Adds convenience helpers for retries, JSON/TOML utilities, and KMP-friendly file/http/process access
- Uses Arrow (Raise/Either) and Kotlin context parameters to keep error handling and context passing lightweight
Planned features:
- Integration with Arrow's resilience libraries (e.g. Retry, Resource, Circuit Breaker)
- Write extensive examples
- Write extensive tests
- Write extensive documentation
- BearerPrincipalExtractor for JWT authentication
- sqlx4k integration
- PGMQ integration
- Extend this list with more ideas 🧐!
Modules and features
Core (ktkit)
Applicationwrapper for Ktor server startup/shutdown, JSON setup, Koin DI, and routingAbstractRestHandlerwith typed request helpers,ExecContextpropagation, and error mapping- Built-in
/api/status/healthand/api/status/metricsendpoints - Error model (
ErrorSpec/ApiError) aligned with RFC 9457 conventions - Config loader for TOML with environment substitution and layered overrides
Security: X-Real-Name Header Authentication
Warning
The XRealNamePrincipalExtractor and XRealNameRestClient use a base64-encoded JSON header (x-real-name) to
identify the authenticated user. This mechanism is not safe to expose directly to the internet.
This pattern assumes a trusted reverse proxy or API gateway sits in front of your application and:
- Authenticates the user (e.g., via OAuth, JWT, or session cookies)
- Strips any incoming
x-real-nameheader from client requests - Sets the
x-real-nameheader with the authenticated user's information before forwarding
If your application is exposed directly to the internet without such a proxy, any client can forge the header and impersonate any user. Only use this extractor when your application runs behind a trusted infrastructure layer that controls this header.
TOML Configuration Loading
ConfigPropertiesToml loads and deserializes TOML files into @Serializable data classes. It supports environment
variable interpolation (${VAR_NAME}), loading from resources or the filesystem, and merging a base config with an
override file (override values take precedence).
The load() method reads application.toml from resources as the base, then looks for an override in this order:
application.toml, config/application.toml, application.local.toml, config/application.local.toml.
// Define your config as a @Serializable data class @Serializable data class AppConfig(val server: ServerConfig, val database: DatabaseConfig) @Serializable data class ServerConfig(val host: String, val port: Int) @Serializable data class DatabaseConfig(val url: String, val maxConnections: Int)
# src/commonMain/resources/application.toml (base config) [server] host = "localhost" port = 8080 [database] url = "postgresql://${DB_HOST}/mydb" maxConnections = 10
# config/application.local.toml (local override) [database] maxConnections = 50
// Auto-load with layered overrides val config: AppConfig = ConfigPropertiesToml.load() // Or load from a specific file val config: AppConfig = ConfigPropertiesToml.loadFromFileSystem("path/to/config.toml") // Or merge two files explicitly val config: AppConfig = ConfigPropertiesToml.loadFromFileSystem( base = "base.toml", override = "override.toml" )
Ktor HTTP Client (ktkit-ktor-httpclient)
A multiplatform REST client abstraction built on Ktor's HttpClient with functional error handling via Arrow's Raise.
HttpClientFactoryfor creating pre-configured HttpClient instances with timeouts, connection pooling, and JSON setupAbstractRestClientbase class with typed HTTP methods (GET, POST, PUT, PATCH, DELETE, etc.)- Built-in implementations:
BearerRestClient(Bearer token auth) andXRealNameRestClient(X-Real-Name header auth) - Error handling via sealed
RestClientErrorSpechierarchy
sqlx4k integration (ktkit-sqlx4k)
A coroutine-first SQL toolkit with compile-time query validations for Kotlin Multiplatform. PostgreSQL, MySQL/MariaDB, and SQLite supported.
DatabaseServicehelpers for error mapping and traced transactionsAuditableRepositoryhooks forcreatedAt/createdBy/updatedAt/updatedByAuditableDatabaseServiceinterface for services with auditable entities and asave()extensionJsonSupportutility for JSON column serialization with sqlx4k'sValueEncodersystem
PGMQ integration (ktkit-sqlx4k-pgmq)
A lightweight message queue. Like AWS SQS and RSMQ but on Postgres.
Pgmqwrapper andAbstractPgmqEventHandlerwith trace/user propagation- Consumer lifecycle helpers with retry + shutdown handling
Ergonomics (Arrow + context-parameters)
The example module shows how Arrow's Raise and Kotlin context parameters keep service code compact while
preserving explicitness around errors and execution context:
class TestService( override val db: Driver, override val repo: TestRepository, ) : AuditableDatabaseService<Test> { val log = Logger.of(this::class) context(_: ExecContext, _: QueryExecutor) private suspend fun findAll(): List<Test> = db { repo.findAll() } context(_: ExecContext, _: Transaction) suspend fun test(): List<Test> { log.info { "Fetching all tests" } return findAll().also { log.info { "Fetched ${it.size} tests" } } } }
The execution context is a coroutine context element that also implements Arrow's Raise and log4k's tracing context:
class ExecContext( val reqId: String, val reqTs: Instant, val principal: Principal, // Only a part of the context is presented here. // Check the documentation for more information. ) : Raise<ErrorSpec>, TracingContext by tracing, CoroutineContext.Element
This lets handlers and services raise domain errors, access tracing, and carry request metadata without threading
parameters manually. The context is propagated in two ways at once: via CoroutineContext and via context
parameters in function signatures.
Example
Check the example application here.
Building & Development
Build
# Build all modules, for Jvm and your current platform ./gradlew build # Build all modules for all supported platforms ./gradlew build -Ptargets=all #
Docker Setup
The project includes a docker-compose.yml for PostgreSQL:
Contributing
This is an open-source project. Contributions are welcome!
License
Check the repository for license information.
Related Projects
Author
Yorgos S. (@smyrgeorge)