Rust 백엔드 DB 라이브러리 비교
핵심 요약
Rust 백엔드에서 자주 비교되는 DB 라이브러리는 Diesel, SQLx, SeaORM, Rusqlite다. 네 라이브러리는 모두 “DB 접근”이라는 같은 문제를 다루지만 철학이 다르다.
- Diesel: 컴파일 타임 안전성을 극대화한 풀 ORM.
- SQLx: raw SQL을 유지하면서 컴파일 타임 검증을 제공하는 비동기 SQL 툴킷.
- SeaORM: 동적 쿼리와 관계 모델링에 강한 비동기 ORM.
- Rusqlite: SQLite 전용의 얇고 견고한 래퍼.
실전 선택 기준은 단순하다.
- SQLite면 Rusqlite.
- 컴파일 타임 안전성이 최우선이면 Diesel.
- SQL을 직접 쓰고 싶으면 SQLx.
- 동적 쿼리와 관계 중심 ORM이 필요하면 SeaORM.
Rust로 DB를 다루는 이유
Rust가 DB 중심 백엔드에서 매력적인 이유는 세 가지다.
첫째, 컴파일 시점 안전성이다. 일부 라이브러리는 SQL 쿼리를 실제 DB 스키마와 대조해 컴파일 타임에 검증한다. 컬럼명 오타, 타입 불일치, 잘못된 WHERE 절을 실행 전에 잡을 수 있다.
둘째, 비동기 생태계가 성숙했다. Tokio와 주요 DB 라이브러리들이 안정화되면서, 예전처럼 수명과 빌림 검사기 때문에 DB 접근 자체가 고통스러운 단계는 많이 줄었다.
셋째, 성능 예측 가능성이다. ORM 오버헤드나 GC 정지 시간이 요청 예산을 갉아먹는 일이 적고, 메모리 해제와 리소스 관리가 결정적이다.
Diesel
Diesel은 Rust 생태계의 오래된 풀 ORM이다. 핵심 강점은 컴파일 타임 SQL 검증이다.
Diesel은 DB 스키마에서 Rust 타입을 생성하고, 쿼리 DSL로 작성한 모든 쿼리를 컴파일러가 타입과 대조한다. 코드가 컴파일되면 적어도 스키마와 타입 관점에서는 SQL이 유효하다는 강한 보장을 얻는다.
장점
- 컴파일 타임에 잘못된 JOIN, 컬럼명, 타입 불일치를 잡는다.
- 스키마 리팩터링 시 수정해야 할 쿼리를 컴파일 에러로 모두 드러낸다.
- 생성 SQL이 손으로 작성한 SQL과 거의 같은 실행 계획을 낼 수 있다.
- 마이그레이션 시스템이 견고하다.
- 장기간 유지될 프로덕션 코드에서 안전성이 크다.
단점
- Diesel 자체는 동기 중심이고, 비동기는
diesel-async를 추가로 써야 한다. - 타입 시스템이 복잡해 컴파일 에러가 길고 읽기 어렵다.
- 선택적 필터가 많은 동적 쿼리에 약하다.
- 쿼리 형태가 정적일 때 가장 편하다.
적합한 경우
- PostgreSQL/MySQL 기반 백엔드.
- 스키마가 비교적 안정적이다.
- 정확성과 컴파일 타임 보장이 중요하다.
- 운영 수명이 긴 서비스 코드다.
SQLx
SQLx는 ORM이 아니라 SQL 툴킷이다. 쿼리 생성, 관계 관리, ActiveRecord 패턴을 제공하지 않는다. 대신 raw SQL을 직접 쓰면서 컴파일 타임 검증을 제공한다.
SQLx 매크로는 컴파일 시점에 실제 DB에 접속해 쿼리를 검증한다. 테이블이 없거나 컬럼명이 틀리거나 타입이 맞지 않으면 컴파일 에러가 난다.
장점
- SQL을 알면 바로 사용할 수 있다.
- 별도 ORM DSL을 배울 필요가 없다.
- 비동기 우선으로 설계됐다.
- Tokio/async-std 기반 백엔드와 잘 맞는다.
QueryBuilder로 동적 쿼리를 비교적 자연스럽게 구성할 수 있다.- 파라미터 바인딩으로 SQL 인젝션을 방지한다.
단점
- 컴파일 중 검증을 위해 DB가 떠 있어야 한다.
- 오프라인 빌드를 하려면
cargo sqlx prepare로.sqlx메타데이터를 갱신해야 한다. - 관계 로딩, lazy/eager loading, 자동 JOIN 같은 ORM 편의 기능은 없다.
- 복잡한 데이터 그래프는 SQL을 직접 많이 작성해야 한다.
적합한 경우
- 팀이 SQL로 사고한다.
- ORM 추상화보다 명시적 SQL을 선호한다.
- 비동기 DB 접근이 필수다.
- 동적 필터/검색 API가 중요하다.
- 빠르게 시작하면서도 컴파일 타임 검증을 원한다.
SeaORM
SeaORM은 비동기 우선의 현대적 ORM이다. Django ORM, Rails ActiveRecord, Laravel Eloquent 같은 패턴에 익숙한 개발자에게 가장 친숙하다.
Diesel이나 SQLx처럼 쿼리를 컴파일 시점에 DB 스키마와 엄격히 검증하기보다는, 런타임 유연성을 택한다.
장점
- 일대다, 다대다, eager/lazy loading 같은 관계 처리가 자연스럽다.
- 동적 쿼리, 선택적 필터, 조건부 정렬, 페이지네이션에 강하다.
sea-orm-cli로 DB 스키마에서 엔티티를 생성할 수 있다.- SeaORM 2.0의 Entity Loader는 N+1 문제를 줄이는 데 유용하다.
- Django/Rails/Laravel 출신 팀에게 러닝 커브가 낮다.
단점
- 스키마 불일치를 컴파일 타임에 잡지 못한다.
- 컬럼명 변경 후 엔티티 갱신을 잊으면 런타임 에러가 난다.
- 생태계와 자료가 Diesel/SQLx보다 작다.
- 동적 ORM 구조라 약간의 런타임 오버헤드가 있다.
적합한 경우
- 관계가 복잡한 웹 API.
- 동적 검색과 필터링이 핵심 기능이다.
- 팀이 전통 ORM 패턴을 선호한다.
- 개발 속도가 컴파일 타임 보장보다 중요하다.
Rusqlite
Rusqlite는 SQLite 전용 래퍼다. ORM이라기보다는 SQLite C API를 Rust답게 감싼 라이브러리에 가깝다.
SQLite를 쓴다면 가장 단순하고 확실한 선택지다.
장점
bundledfeature로 SQLite를 바이너리에 포함할 수 있다.- 시스템 SQLite 의존성 없이 배포 가능하다.
- 연결, prepared statement, 트랜잭션을 얇게 제공한다.
- SQLite의 FTS, JSON, 사용자 정의 함수, 가상 테이블 같은 기능을 직접 활용할 수 있다.
- CLI, 데스크톱 앱, 임베디드 환경에 적합하다.
단점
- SQLite만 지원한다.
- 쿼리 빌더나 관계 관리 같은 ORM 편의 기능은 없다.
- 마이그레이션은 별도 도구가 필요하다.
- 동기 API 중심이라 웹 서버에서는 스레드풀로 감싸거나 SQLx SQLite를 고려해야 한다.
적합한 경우
- CLI 도구.
- 데스크톱 애플리케이션.
- 로컬 저장소.
- 서버 DB 없이 배포해야 하는 환경.
- SQLite가 구조적으로 맞는 프로젝트.
선택 프레임워크
실무 선택 기준은 다음처럼 단순화할 수 있다.
| 상황 | 추천 |
|---|---|
| SQLite를 쓴다 | Rusqlite |
| 컴파일 타임 안전성이 최우선 | Diesel |
| raw SQL을 직접 쓰고 싶다 | SQLx |
| 비동기 SQL 툴킷이 필요하다 | SQLx |
| 복잡한 관계와 ORM 편의가 필요하다 | SeaORM |
| 동적 검색/필터링이 핵심이다 | SQLx 또는 SeaORM |
| Django/Rails/Laravel식 ORM 경험을 원한다 | SeaORM |
| 장기 운영 코드베이스의 안전성이 중요하다 | Diesel |
불편한 진실
대부분의 프로젝트에서는 네 라이브러리 중 무엇을 골라도 충분히 잘 동작한다. 모두 잘 관리되고, SQL 인젝션을 막는 기본 수단을 제공하며, 각자의 범위 안에서 프로덕션 사용이 가능하다.
차이는 극단적인 상황에서 드러난다.
- 안전성의 극단: Diesel.
- SQL 명시성의 극단: SQLx.
- ORM 생산성의 극단: SeaORM.
- SQLite 단순성의 극단: Rusqlite.
중요한 것은 “가장 좋은 라이브러리”가 아니라 팀의 사고방식과 프로젝트 형태에 맞는 라이브러리를 고르는 것이다.