Kotlin으로 백엔드를 개발하려는 순간, 가장 먼저 마주하는 질문이 있습니다.
"Spring Boot를 쓸까, Ktor를 쓸까?"
이 글에서는 두 프레임워크를 다각도로 비교하고, 실제 코드 예제를 통해 어떤 것을 선택해야 하는지 알아보겠습니다.
요즘 전자정부표준프레임워크가 개편되니 마니 하길래 써봅니다.
Spring Boot는 전통적인 엔터프라이즈 애플리케이션을 위해 설계되었습니다. 모든 기능이 이미 구현되어 있고, 설정만 하면 됩니다.
특징
Ktor는 가볍고 유연한 프레임워크를 지향합니다. 필요한 기능만 선택적으로 추가할 수 있습니다.
특징
@SpringBootApplication
class Application
fun main(args: Array<String>) {
runApplication<Application>(*args)
}
@RestController
class HelloController {
@GetMapping("/hello")
fun hello(): String {
return "Hello, Spring Boot!"
}
}
fun main() {
embeddedServer(Netty, port = 8080) {
routing {
get("/hello") {
call.respondText("Hello, Ktor!")
}
}
}.start(wait = true)
}
첫인상
@Entity
data class User(
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
var name: String,
var email: String
)
@Repository
interface UserRepository : JpaRepository<User, Long>
@Service
class UserService(private val userRepository: UserRepository) {
fun createUser(request: CreateUserRequest): User {
return userRepository.save(User(name = request.name, email = request.email))
}
fun getUser(id: Long): User? = userRepository.findById(id).orElse(null)
}
@RestController
@RequestMapping("/api/users")
class UserController(private val userService: UserService) {
@PostMapping
fun createUser(@RequestBody request: CreateUserRequest): ResponseEntity<User> {
return ResponseEntity.status(HttpStatus.CREATED)
.body(userService.createUser(request))
}
@GetMapping("/{id}")
fun getUser(@PathVariable id: Long): ResponseEntity<User> {
return userService.getUser(id)?.let { ResponseEntity.ok(it) }
?: ResponseEntity.notFound().build()
}
}
data class User(val id: Long, val name: String, val email: String)
object UserRepository {
private val users = mutableMapOf<Long, User>()
private var nextId = 1L
fun create(name: String, email: String): User {
val user = User(nextId++, name, email)
users[user.id] = user
return user
}
fun findById(id: Long): User? = users[id]
}
fun Application.configureRouting() {
routing {
route("/api/users") {
post {
val request = call.receive<CreateUserRequest>()
val user = UserRepository.create(request.name, request.email)
call.respond(HttpStatusCode.Created, user)
}
get("/{id}") {
val id = call.parameters["id"]?.toLongOrNull()
?: return@get call.respond(HttpStatusCode.BadRequest)
val user = UserRepository.findById(id)
?: return@get call.respond(HttpStatusCode.NotFound)
call.respond(user)
}
}
}
}
차이점
@Service
class UserService(private val externalApiClient: ExternalApiClient) {
suspend fun getUserWithDetails(id: Long): UserDetails = coroutineScope {
val user = async { userRepository.findById(id) }
val orders = async { externalApiClient.getOrders(id) }
val reviews = async { externalApiClient.getReviews(id) }
UserDetails(user.await(), orders.await(), reviews.await())
}
}
suspend fun getUserWithDetails(id: Long): UserDetails = coroutineScope {
val user = async { userRepository.findById(id) }
val orders = async { externalApiClient.getOrders(id) }
val reviews = async { externalApiClient.getReviews(id) }
UserDetails(user.await(), orders.await(), reviews.await())
}
차이점
Spring Boot
Ktor
Spring Boot
Ktor
벤치마크 결과 Ktor가 약간 더 빠르지만, 실제 애플리케이션에서는 데이터베이스와 외부 API가 병목이므로 프레임워크 성능 차이는 미미합니다.
장점
관련 프로젝트
장점
단점
장점
단점
장점
단점
Spring Cloud 생태계
Spring은 마이크로서비스를 위한 완벽한 생태계를 제공합니다.
// Service Discovery (Eureka)
@EnableEurekaClient
@SpringBootApplication
class UserServiceApplication
// API Gateway (Spring Cloud Gateway)
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE
predicates:
- Path=/api/users/**
// Config Server
@EnableConfigServer
@SpringBootApplication
class ConfigServerApplication
// Circuit Breaker (Resilience4j)
@CircuitBreaker(name = "orderService", fallbackMethod = "fallbackGetOrders")
fun getOrders(userId: Long): List<Order> {
return orderServiceClient.getOrders(userId)
}
Spring Cloud 기능
장점
단점
경량 마이크로서비스
Ktor는 작고 빠른 마이크로서비스를 만드는 데 최적화되어 있습니다.
// 서비스 A
fun main() {
embeddedServer(Netty, port = 8081) {
routing {
get("/api/users/{id}") {
val id = call.parameters["id"]?.toLongOrNull()
?: return@get call.respond(HttpStatusCode.BadRequest)
call.respond(userService.getUser(id))
}
}
}.start(wait = true)
}
// 서비스 B
fun main() {
embeddedServer(Netty, port = 8082) {
val client = HttpClient(CIO)
routing {
get("/api/orders") {
// 서비스 A 호출
val users = client.get("http://user-service:8081/api/users")
call.respond(processOrders(users))
}
}
}.start(wait = true)
}
Ktor + 외부 도구 조합
장점
단점
대규모 엔터프라이즈 MSA (수십~수백 개 서비스)
→ Spring Boot + Spring Cloud
이유:
중소규모 MSA (수개~수십 개 서비스)
→ Ktor + Kubernetes
이유:
하이브리드 접근
Ktor가 유리한 점
Spring Boot의 대응
Ktor
FROM openjdk:11-jre-slim
COPY build/libs/app.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
# 최종 이미지: ~100MB
# 시작 시간: <1초
# 메모리: ~50MB
Spring Boot
FROM openjdk:11-jre-slim
COPY build/libs/app.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
# 최종 이미지: ~200MB
# 시작 시간: 3-5초
# 메모리: ~200MB
컨테이너 밀도
Ktor의 장점
Spring Boot Actuator
2025년 현재 트렌드
이런 트렌드는 Ktor에 유리하게 작용하고 있습니다.
사례 1: 대기업 금융 시스템
사례 2: 전통적인 모놀리식구조
사례 1: 스타트업 MVP
사례 2: 내부 마이크로서비스
사례 3: Real-time 서비스
1단계: Spring 기초
2단계: Spring Boot 핵심
3단계: 데이터 접근
4단계: 보안
5단계: MSA
예상 학습 기간: 3-6개월
1단계: Kotlin 기초
2단계: Ktor 핵심
3단계: 데이터베이스
4단계: 인증
예상 학습 기간: 1-2개월
Spring Boot
Ktor
Spring Boot
Ktor
안정적인 커리어
→ Spring Boot 마스터
차별화 전략
→ Spring Boot + Ktor 모두 경험
스타트업 지향
→ Ktor 집중하고 Ktor 어필 겁나 해야함
제가 실무에서 경험한 바로는, 현재 시점에서 Spring Boot가 여전히 더 현실적인 선택입니다.
이유
1. 생태계의 힘
실무에서는 단순히 REST API만 만드는 게 아닙니다. 보안, 배치 처리, 스케줄링, 모니터링, 로깅 등 수많은 요구사항이 있습니다. Spring Boot는 이 모든 것을 기본 제공하거나 쉽게 통합할 수 있습니다.
2. 팀 협업
혼자 개발하는 것이 아니라 팀으로 일합니다. Spring Boot는 표준화된 구조를 제공하므로 팀원 간 코드 이해가 쉽고, 신입 개발자 온보딩도 수월합니다.
3. 레퍼런스의 중요성
문제가 생겼을 때 검색하면 대부분 해결책이 나옵니다. Ktor는 아직 레퍼런스가 부족해서 시행착오가 많습니다.
4. 취업 시장
현실적으로 대부분의 회사가 Spring을 사용합니다. Ktor만 할 줄 안다면 선택지가 매우 좁아집니다.
1. Kotlin의 성장
Kotlin이 점점 더 많이 채택되면서 Ktor도 함께 성장하고 있습니다.
2. 클라우드 네이티브 시대
컨테이너, 서버리스 환경에서 Ktor의 가벼움은 큰 장점입니다. 비용 측면에서도 유리합니다.
3. 마이크로서비스
작고 빠른 서비스가 필요한 MSA 환경에서 Ktor는 이상적입니다.
초보자라면
→ Spring Boot부터 시작하세요. 취업에도 유리하고, 엔터프라이즈 개발의 전반을 배울 수 있습니다.
Spring Boot를 이미 잘한다면
→ Ktor를 배워보세요. Kotlin을 더 깊게 이해할 수 있고, 차별화 포인트가 됩니다.
스타트업에서 새 프로젝트를 시작한다면
→ Ktor를 고려해보세요. 빠른 개발과 낮은 운영 비용이 장점입니다.
대기업 또는 레거시 시스템이라면
→ Spring Boot가 안전한 선택입니다.
개인적으로는 하이브리드 접근을 선호합니다.
API Gateway: Spring Boot + Spring Cloud Gateway
Core Business Services: Spring Boot
Internal Microservices: Ktor
Background Workers: Ktor
Real-time Services: Ktor
이렇게 하면 각 프레임워크의 장점을 살릴 수 있습니다.
어차피 MSA가 유행이니 MSA를 잘 써먹어야지요.
2025년 현재는, Spring Boot가 여전히 더 현실적이고 안전한 선택입니다.
하지만 Ktor는 특정 영역에서 명확한 장점이 있고, 점점 성장하고 있습니다.
가장 좋은 전략은 Spring Boot를 메인으로 하되, Ktor도 이해하고 있는 것입니다.
둘 다 경험해보고, 상황에 맞게 선택할 수 있는 능력을 갖추는 것이 최선입니다.
Spring Boot
Ktor
커뮤니티
Ktor을 보니 파이썬의 serverless 프레임워크가 생각납니다.
언어 상관없이 서비스를 작은 규모로 개발하는 것이 트렌드이며, 향후에는 시장을 점유하게 될 것 같네요.