Deploy Kotlin & Ktor to Europe — EU Hosting for JVM Apps in 2026
Kotlin has become the default language for Android development — and increasingly, the preferred language for JVM-based backends. With its concise syntax, null safety, coroutine-based concurrency, and full Java interoperability, Kotlin lets Android engineers build their own APIs without switching languages. Ktor, the server framework built by JetBrains (the same Czech company behind IntelliJ and Kotlin itself), is the most idiomatic way to run Kotlin on the backend.
But deploying Kotlin and Ktor to production still means navigating a landscape of US-centric platforms. If you're building for European users — or operating under GDPR — the default choices leave compliance gaps that can create real legal exposure.
sota.io is the EU-native PaaS for Kotlin and Ktor. Deploy to Hetzner in Germany in minutes, with managed PostgreSQL and automatic TLS included.
Why Heroku, Railway, and AWS Don't Work for EU Kotlin Apps
Heroku was the original PaaS that made git push deployments possible. But Heroku is a Salesforce product, US-headquartered, with US infrastructure by default. Their European region runs on AWS Frankfurt — but your DPA is with a US entity. Under the GDPR Article 46 standard contractual clauses framework, this creates uncertainty that conservative legal teams and German data protection authorities (Datenschutzbehörde) will flag immediately.
Railway is developer-friendly and Kotlin/JVM-compatible. But Railway is a US company subject to the CLOUD Act. US infrastructure by default, and even EU region deployments process auth and billing through US systems.
AWS Elastic Beanstalk can run in eu-central-1 (Frankfurt), but the sheer operational complexity — IAM roles, VPCs, ALBs, ECS task definitions — means you're not shipping product, you're configuring infrastructure. And AWS is a US entity regardless of region.
JetBrains Space is Kotlin-native and EU-aware, but it's a development platform, not a deployment target.
sota.io is incorporated and operated in the EU. All infrastructure runs on Hetzner's German data centers. Your DPA is with an EU legal entity — no legal gray areas.
Kotlin for the Backend: The Android Developer's Advantage
Kotlin's server ecosystem has matured significantly. If you already know Kotlin from Android development, you can build a production-grade API backend without learning a new language.
Ktor's async-first design maps directly onto what Android developers already know:
// Android: Retrofit + Coroutines
val response = apiService.getUser(userId) // suspend fun
// Ktor backend: same pattern
get("/users/{id}") {
val id = call.parameters["id"]!!
val user = db.getUserById(id) // suspend fun
call.respond(user)
}
The coroutine model is identical. The same suspend functions, launch, async, and withContext patterns work on both sides of the network.
Beyond Android teams, Ktor is also used by:
- JVM microservices teams who find Spring Boot too heavyweight
- Multiplatform projects where Kotlin is already the shared language
- Startups moving from a Kotlin Android app to their own API tier
- European fintechs building event-driven systems with Kotlin Flows
Deploy Ktor to sota.io
1. Containerize Your Ktor App
Create a multi-stage Dockerfile that builds a fat JAR and runs it in a minimal JRE image:
FROM gradle:8.5-jdk21 AS builder
WORKDIR /app
COPY build.gradle.kts settings.gradle.kts ./
COPY gradle ./gradle
RUN gradle dependencies --no-daemon
COPY src ./src
RUN gradle shadowJar --no-daemon
# --- Runtime ---
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=builder /app/build/libs/*-all.jar app.jar
ENV PORT=8080
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
This produces a self-contained image under 200 MB. Use shadow jar (Gradle plugin) to bundle all dependencies.
2. Configure the Application
A minimal Application.kt with environment-based configuration:
fun main() {
embeddedServer(Netty, port = System.getenv("PORT")?.toInt() ?: 8080) {
install(ContentNegotiation) {
json()
}
install(CORS) {
anyHost()
}
configureRouting()
configureDatabase()
}.start(wait = true)
}
3. Connect to PostgreSQL
sota.io injects PostgreSQL credentials via environment variables. Use Exposed (JetBrains' Kotlin ORM) or plain JDBC:
// Using Exposed ORM
fun configureDatabase() {
val databaseUrl = System.getenv("DATABASE_URL")
?: throw RuntimeException("DATABASE_URL not set")
Database.connect(databaseUrl, driver = "org.postgresql.Driver")
transaction {
SchemaUtils.create(Users, Orders)
}
}
object Users : Table("users") {
val id = uuid("id").autoGenerate()
val email = varchar("email", 255)
val createdAt = datetime("created_at").defaultExpression(CurrentDateTime)
override val primaryKey = PrimaryKey(id)
}
For async database access, use newSuspendedTransaction from exposed-kotlin-datetime:
get("/users") {
val users = newSuspendedTransaction {
User.all().toList()
}
call.respond(users)
}
4. Deploy
sota deploy
sota.io builds your Docker image, injects DATABASE_URL, provisions TLS, and routes traffic to your Ktor app.
Ktor vs Spring Boot for EU Deployments
Ktor and Spring Boot are both JVM frameworks with strong EU adoption, but they serve different use cases:
| Ktor | Spring Boot | |
|---|---|---|
| Startup time | ~0.5s | 3–10s (depends on beans) |
| Memory footprint | 50–100 MB | 200–400 MB (typical) |
| Kotlin idiomaticity | Native (coroutines, DSL) | Supported but Java-centric |
| Ecosystem | JetBrains + community | Massive Spring ecosystem |
| Learning curve | Low (for Kotlin devs) | Steeper (annotations, DI) |
| Enterprise use | Growing | Dominant |
For new projects where the team knows Kotlin, Ktor is typically faster to production. For large DACH enterprise teams with existing Spring expertise, Spring Boot on sota.io is also a strong option — see our Java/Spring Boot EU guide.
Comparison: sota.io vs Heroku vs Railway vs AWS
| sota.io | Heroku | Railway | AWS Beanstalk | |
|---|---|---|---|---|
| EU Data Residency | ✅ Germany (default) | ⚠️ AWS Frankfurt, US entity | ⚠️ EU region, US entity | ✅ eu-central-1, US entity |
| GDPR EU DPA | ✅ EU entity | ❌ US entity | ❌ US entity | ❌ US entity |
| Pricing | Flat €9/mo, 2 GB | Usage-based (expensive at scale) | Usage-based | Complex (compute + ALB + data transfer) |
| Kotlin/JVM Support | ✅ Docker-based | ✅ Buildpacks | ✅ Docker | ✅ Supported |
| Managed PostgreSQL | ✅ Included | ✅ Add-on (€) | ✅ Add-on (€) | ✅ RDS (€€) |
| Setup complexity | Low (1 command) | Low | Low | High |
| Cold start | None | ❌ Free tier sleeps | None | None |
GDPR and the JVM Enterprise Niche
Kotlin and the JVM have particularly strong adoption in sectors with strict data residency requirements:
- German/Austrian insurance (Versicherungen): Spring Boot and increasingly Ktor are common choices. BaFin requires EU data processing for policyholder data.
- DACH banking (Banken): Microservices in Kotlin for transaction processing. ECB/EBA data residency requirements are non-negotiable.
- Healthcare (eHealth/ePA): Germany's Telematik-Infrastruktur and the digital patient record (ePA) mandate EU storage for all health data.
- Android + Backend shops: Teams building mobile-first EU consumer apps who want a shared codebase language.
If you're in any of these verticals, the combination of Ktor's JVM reliability and sota.io's German infrastructure closes the compliance gap that US platforms cannot address.
What sota.io Gives You
- EU by default — Your app deploys to Hetzner Germany, no configuration needed
- Automatic TLS — Let's Encrypt certificates, auto-renewed
- Managed PostgreSQL 17 — Connection string injected as
DATABASE_URL - Flat pricing — €9/month, 2 GB RAM, 10 GB storage. No egress fees.
- Open source CLI —
sota deployfrom your terminal or CI/CD
npm install -g @sota-io/cli
sota auth login
sota deploy
Your Ktor app is live in Germany.
See also: Deploy Java & Spring Boot to Europe · Deploy Go to Europe · Deploy Rust to Europe