Rust 백엔드 DB 라이브러리 4종 비교
(aarambhdevhub.medium.com)Rust로 백엔드를 제대로 만들어본 사람이라면 한 번쯤 이 벽에 부딪혔을 것이다. 데이터베이스가 필요한 순간, 네 개의 라이브러리가 각자의 철학과 트레이드오프, 그리고 Reddit의 추종자 무리를 등에 업고 당신을 빤히 바라보는 것이다.
나도 그랬다. 지난 1년간 Diesel, SQLx, SeaORM, Rusqlite로 실제 프로덕션을 배포해봤다. 선택이 잘 맞은 것도 있고, 다시 한다면 다른 걸 고를 것도 있다. 몇 가지는 정말 의외였다.
마케팅 담론도, "상황에 따라 다르죠" 같은 얼버무림도 없다. 네 개를 모두 실제 운영 코드에 써본 사람의 솔직한 후기를 들려주겠다.
2026년, 왜 Rust로 DB 작업을 하는가?
먼저 이걸 넘어가자. 왜 Python에 SQLAlchemy나 Node에 Prisma를 쓰지 않는가?
DB 중심 애플리케이션에서 Rust를 고르게 만드는 건 세 가지다.
컴파일 시점 안전성은 여기서 다른 차원이다. 이 라이브러리들 중 일부는 말 그대로 SQL 쿼리를 DB 스키마와 대조해 컴파일 타임에 검증한다. 컬럼명에 오타가 났다? 컴파일러가 잡는다. WHERE 절에 타입이 안 맞는다? 코드 실행 전에 걸러진다. 새벽 3시의 디버깅을 얼마나 줄여줬는지 강조해도 모자르다.
비동기가 드디어 성숙했다. 몇 년 전만 해도 Rust의 비동기 DB 접근은 거칠었다. 빌림 검사기와 씨름하고, 수명을 저글링하고, 완성도 떨어지는 라이브러리들을 다뤄야 했다. 2026년의 지금? 그냥 된다. Tokio는 탄탄하고, 라이브러리들도 길을 찾았다.
성능을 신경 쓸 필요가 없다. ORM 오버헤드가 요청 예산을 깎아먹지 않는다. 가비지 컬렉터가 트랜잭션 도중 멈추지 않는다. 쿼리가 실행되고 결과가 돌아오고, 메모리는 결정적으로 해제된다. 지루할 정도로 잘 돌아간다.
네 개의 주자
2026년 2월 기준 최신 버전과 함께 살펴보자.
- Diesel (v2.3.6, 2026년 1월) — 컴파일 타임 SQL을 갖춘 풀 ORM
- SQLx (v0.8.6, 현재 안정판) — 비동기 SQL 툴킷 (ORM 아님)
- SeaORM (v2.0, 2026년 1월) — 비동기 우선의 동적 ORM
- Rusqlite (v0.38.0, 2025년 12월) — 경량 SQLite 래퍼
이들은 관련된 문제를 푸는 근본적으로 다른 도구들이다. 하나씩 설명하겠다.
Diesel: 버그를 당신보다 먼저 잡는 녀석
가장 잘 맞는 경우: 컴파일 시점 안전성을 극대화하고 싶고, 스키마가 안정적인 팀
Diesel은 2015년부터 존재했다. Rust 세계에서 이는 고대에 가깝다. 그리고 그 성숙도가 가장 좋은 의미로 드러난다.
핵심은 이렇다. Diesel 코드가 컴파일되면 SQL은 유효하다. 이건 마케팅 문구가 아니라, 말 그대로 그렇게 작동한다. Diesel은 DB 스키마에서 Rust 타입을 생성하고, 컴파일러가 작성하는 모든 쿼리를 그 타입과 대조해 검증한다.
Diesel이 계속 내 마음을 사로잡는 이유
컴파일 타임 검증은 중독성이 있다. "컴파일러가 테스트 돌리기도 전에 잘못된 JOIN을 잡아냈다"는 경험을 한 번보면, 문자열 기반 SQL로 돌아가는 건 무모하게 느껴진다. 지난달 스키마를 리팩토링했는데—컬럼 세 개의 이름을 바꾸고 타입을 변경했는데—Diesel은 컴파일 시점에 수정이 필요한 모든 쿼리를 하나도 빠짐없이 보여줬다. 하나도. 빠짐없이.
제로 코스트 추상화는 슬로건이 아니다. Diesel이 생성하는 SQL은 손으로 쓴 것과 본질적으로 같다. 실행 계획을 비교해봤는데, 동일했다. ORM의 안전성과 raw SQL의 성능을 동시에 얻는다.
마이그레이션이 제대로 된다. 낮은 기준처럼 들리겠지만, 다른 생태계의 마이그레이션 도구와 싸워본 뒤 Diesel의 마이그레이션 시스템은 상쾌하게 견고하게 느껴진다. 생성, 실행, 되돌리기—그냥 된다.
솔직한 단점
비동기는 덧붙인 것이지 원래 내장된 게 아니다. Diesel 자체는 동기적이다. 비동기를 쓰려면 diesel-async가 필요한데, 이건 잘 작동하지만 의존성 하나가 더 추가되고 정신적 부담이 있다. SQLx나 SeaORM의 네이티브 비동기에서 오면 눈에 띈다.
러닝 커브가 가파르다. Diesel의 타입 시스템은 강력하고, 강력한 것은 복잡하다. 쿼리를 망치면 컴파일러 에러는 기술적으로 정확하지만, 40줄짜리 제네릭 타입 구토일 수도 있다. 읽는 법을 익히지만, 첫 주는 힘들다.
동적 쿼리는 고통스럽다. 런타임에 구조가 바뀌는 쿼리—선택적 필터가 있는 검색 엔드포인트 같은 걸—만들려면 Diesel이 저항한다. 정적인 쿼리 모양을 원한다. 쿼리가 동적일 때는 비즈니스 로직보다 타입 시스템과 씨름하는 데 시간을 더 쓴다.
Diesel을 고르는 순간
- PostgreSQL이나 MySQL 프로젝트고 스키마가 매주 바뀌지 않는다
- 컴파일 시점 안전성은 절대 타협할 수 없다
- 프로덕션에서 수년간 살아남을 코드고 정확성이 중요하다
- 다른 이유가 없다면 기본 선택지
SQLx: SQL을 쓰면 안전성은 덤으로 따라온다
가장 잘 맞는 경우: SQL 퍼스트 개발자로서, DSL을 배우지 않고 컴파일 타임 검증을 원하는 경우
솔직히 말하자. SQLx는 ORM이 아니다. 쿼리를 생성해주지 않고, 관계를 관리하지 않는다. SQL 툴킷이다. 하지만 많은 사람이 ORM 대신 쓰는 위치에 쓰고, 솔직히? 많은 프로젝트에서 더 나은 선택이다.
마법은 이렇게 작동한다. raw SQL 쿼리를 문자열로 쓴다. SQLx는 컴파일 시점에 실제 DB에 연결해 그 쿼리를 검증한다. 테이블이 없거나, 컬럼명이 틀리거나, 타입이 안 맞으면—컴파일 에러. Diesel 수준의 안전성을 얻으면서 평범한 SQL을 쓰는 것이다.
SQLx가 진짜로 훌륭한 점
SQL을 알면 SQLx를 안다. 배울 쿼리 DSL이 없다. 새로운 정신 모델이 없다. 이미 아는 SQL을 쓰고 매크로를 조금 뿌리면, 컴파일러가 나머지를 처리한다. SQLx 프로젝트에 주니어 개발자를 투입한 경험으로 보면 몇 시간이면 된다. 며칠이 아니라.
첫날부터 비동기. SQLx는 비동기 Rust를 위해 만들어졌다. Tokio든 async-std든, 런타임을 골라서 쓰면 된다. 별도의 크레이트나 호환성 레이어가 없다. 비동기 DB 접근이 이래야 한다.
QueryBuilder가 동적 쿼리를 처리한다. 이건 SQLx가 조용히 Diesel을 이기는 부분이다. 사용자가 12개 필드 중 어떤 조합으로든 필터링하는 검색 엔드포인트가 필요한가? SQLx의 QueryBuilder는 그런 동적 쿼리를 직관적으로 구성하게 해준다. 쿼리를 조각조각 만들어도 여전히 인젝션으로부터 파라미터화된다.
솔직한 단점
컴파일 중에 DB가 켜져 있어야 한다. 이건 SQLx에 대해 가장 논쟁적인 부분이다. CI 파이프라인에 DB 접근이 필요하고, 신규 개발자는 컴파일 전에 DB를 띄워야 한다. 오프라인 모드가 쿼리 메타데이터를 캐싱해주지만, 이건 기억해야 할 추가 워크플로우 단계다.
고수준 ORM 기능이 없다. 관계 로딩이 없다. 즉시/지연 로딩이 없다. 자동 JOIN이 없다. 중첩된 관계를 가진 복잡한 데이터 모델이라면 모든 SQL을 직접 써야 한다. 단순 CRUD라면 괜찮다. 복잡한 데이터 그래프라면 지루해진다.
오프라인 모드는 의식이 필요하다. DB 없이 빌드하려면 cargo sqlx prepare로 .sqlx 파일을 생성한다. 이 파일들은 캐싱된 쿼리 메타데이터를 담는다. 쿼리를 바꾸고 재생성하는 걸 잊으면? 낡은 빌드. 작동은 하지만 마찰이 있다.
SQLx를 고르는 순간
- 팀이 이미 SQL로 사고하고 추상화 레이어를 원하지 않는다
- 동적 쿼리가 핵심 요구사항이다
- 새 프로젝트를 시작하고 작동하는 DB 코드까지 최단 경로를 원한다
- 타협 없는 비동기 DB 접근이 필요하다
SeaORM: 익숙하게 느껴지는 녀석
가장 잘 맞는 경우: 비동기와 동적 쿼리를 갖춘 현대적 ORM 경험을 원하는 개발자
Django ORM, ActiveRecord, Eloquent를 써봤다면 SeaORM은 익숙하게 느껴질 것이다. 그리고 2026년 1월의 2.0 릴리즈를 기준으로, 이건 진짜로 프로덕션 준비가 되었다.
SeaORM은 Diesel과 정반대의 접근을 취한다. 컴파일 타임 검증 대신 런타임에서 작동한다. 안전성을 약간 잃는 대신, 다른 라이브러리가 따라올 수 없는 유연성을 얻는다.
SeaORM 2.0이 주목할 만한 이유
관계가 기대하는 대로 작동한다. 일대다, 다대다, 즉시 로딩, 지연 로딩—SeaORM이 모두 처리한다. 사용자-게시물-댓글-태그 같은 복잡한 데이터 모델이 있다면, SeaORM은 그 관계를 자연스럽게 탐색하게 해준다. DB와 싸우는 느낌이 아니다.
동적 쿼리는 일급 시민이다. 선택적 필터? 조건부 정렬? 페이지네이션? SeaORM은 이 모두를 의식 없이 처리한다. 쿼리 빌더는 런타임에 작동하므로 구조가 자유롭게 바뀐다. 이건 Diesel이 고통받는 부분이고 SeaORM이 빛나는 부분이다.
2.0의 기능들은 진짜 쓸모 있다. Entity Loader가 N+1 문제를 우아하게 해결한다—관련 엔티티를 개별 쿼리로 날리는 대신 효율적으로 배치 로드한다. sea-orm-sync는 CLI 도구와 스크립트를 위한 동기 변형을 제공한다. Nested ActiveModel은 복잡한 삽입을 깔끔하게 만든다.
엔티티 생성이 실제 시간을 아껴준다. sea-orm-cli를 DB에 가리키면 Rust 엔티티를 생성한다. 스키마가 바뀌면? 재생성하면 된다. 화려한 작업은 아니지만 자동화하면 수동 구조체 정의에서 나오는 버그가 줄어든다.
솔직한 단점
런타임 에러는 실재한다. Diesel이나 SQLx와 달리, SeaORM은 스키마 불일치를 컴파일 시점에 잡지 않는다. 컬럼 이름을 바꾸고 엔티티 업데이트를 잊으면? 런타임 에러. 이를 보완하려면 충분한 테스트 커버리지가 필요하다.
비교적 새롭다. SeaORM 2.0은 안정적이지만 생태계는 작다. 블로그 글이 적고, Stack Overflow 답변이 적고, "나도 같은 문제 있었어" 스레드가 적다. 공식 문서와 Discord에 더 의존하게 된다.
약간의 런타임 오버헤드. 동적 쿼리 빌드에는 비용이 든다. 작다—99%의 애플리케이션에서는 무시할 수준이다—하지만 매 마이크로초를 쥐어짜낸다면 Diesel이나 SQLx가 더 빠르다.
SeaORM을 고르는 순간
- 엔티티 간 복잡한 관계를 가진 웹 API를 만든다
- 동적 검색/필터링이 주요 기능이다
- 팀이 Django나 Rails, Laravel 출신이고 익숙한 패턴을 원한다
- 컴파일 타임 보장보다 개발 속도가 더 중요하다
Rusqlite: 당연한 선택 (SQLite용)
가장 잘 맞는 경우: CLI 도구, 데스크톱 앱, 임베디드 시스템, SQLite를 쓰는 모든 것
Rusqlite를 "ORM"이라 부르는 건 너그러운 표현이다. SQLite를 감싸는 래퍼다. 하지만 그게 바로 강점이다—한 가지를 하고, 완벽하게 한다.
프로젝트가 SQLite를 쓴다면—그리고 Rust 프로젝트 많은 것이 그렇다—Rusqlite는 논쟁의 여지가 없는, 명백한 선택이다.
Rusqlite가 그냥 잘 되는 이유
번들된 SQLite는 기가 막히다. bundled 피처 플래그를 켜면 Rusqlite가 SQLite를 바이너리에 직접 컴파일한다. 시스템 의존성이 없다. "sqlite3-dev를 설치해주세요" 같은 소리가 없다. 바이너리는 어디서든 돈다. 아무것도 없는 머신에 CLI 도구를 배포해봤는데, 그냥 작동했다.
적절하게 얇다. Rusqlite는 영리해지려 하지 않는다. 연결, 준비된 문장, 트랜잭션을 제공하고, 그 위에 Rust의 타입 안전성을 얹는다. 빌림 검사기가 리소스 오용을 막는다. 준비된 문장이 인젝션을 막는다. 끝이다. 이게 이 라이브러리의 전부다.
SQLite 전용 기능이 노출된다. 사용자 정의 SQL 함수, 가상 테이블, 전문 검색, JSON 확장—Rusqlite는 SQLite 기능 전체에 접근하게 해준다. 범용 ORM은 이들을 추상화 뒤에 숨긴다. Rusqlite는 직접 쓰게 해준다.
솔직한 단점
SQLite만 된다. PostgreSQL이나 MySQL이 필요하면 Rusqlite는 당신의 라이브러리가 아니다. 논의 끝.
ORM의 편의가 없다. 쿼리 빌더가 없다. 관계 처리가 없다. 마이그레이션이 없다(물론 refinery나 rusqlite_migration을 쓸 수는 있다). SQL 문자열을 직접 쓰고 결과를 수동으로 매핑한다.
동기만 된다. Rusqlite는 비동기를 하지 않는다. CLI 도구나 데스크톱 앱에서는 보통 문제가 안 된다. 웹 서버라면 SQLx의 SQLite 지원을 쓰거나 스레드 풀로 감싸야 한다.
Rusqlite를 고르는 순간
- 로컬 저장소가 필요한 CLI 도구를 만든다
- 임베디드 DB를 가진 데스크톱 애플리케이션이다
- SQLite가 맞는 DB 선택인 모든 프로젝트
- DB 서버를 설치할 수 없는 환경에 배포한다
내가 실제로 결정하는 법
네 개를 모두 운영에 써본 뒤의 내 머릿속 프레임워크는 이렇다.
SQLite냐? → Rusqlite. 끝. 고민하지 마라.
컴파일 타임 SQL 검증 + 쿼리 DSL을 원하냐? → Diesel. 오래 살아남을 코드베이스에서 가장 안전한 베팅이다.
컴파일 타임 검증은 원하는데 raw SQL을 선호하냐? → SQLx. 모든 안전성에 DSL 학습 곡선은 없다.
동적 쿼리와 관계, 현대적 비동기 ORM이 필요하냐? → SeaORM 2.0. 특히 Django나 Rails 출신이라면.
새 프로젝트의 기본 선택? → 보통 Diesel로 시작한다. 다른 이유가 없다면. 컴파일 시점 안전성이 너무 많이 살려줬다.
불편한 진실
Rust 커뮤니티에서 아무도 인정하지 않으려는 게 하나 있다: 대부분의 프로젝트에서는 이 중 아무거나 써도 잘 돌아간다.
모두 잘 관리된다. 모두 SQL 인젝션을 막는다. 모두 신경 쓰는 DB와 작동한다(각자의 범위 안에서). 차이는 주변부에서 발생하고, 우리 대부분은 주변부에 있지 않다.
당신의 뇌가 작동하는 방식과 맞는 걸 고르라. SQL로 사고한다면 SQLx를 써라. 컴파일러가 당신을 돌봐주길 원한다면 Diesel을 써라. 이미 알고 있는 ORM 같은 느낌을 원한다면 SeaORM을 써라. SQLite라면 Rusqlite를 써라.
그리고 연구는 그만하고, 빌드를 시작하라.