Article
SQLite 운영 적용 전 체크리스트, PostgreSQL로 넘어가야 하는 순간

“SQLite는 개발할 때나 쓰는 장난감 DB”라는 말을 아직도 종종 듣습니다. 절반은 오해입니다. SQLite는 애플리케이션에 붙어 들어가는 정식 데이터베이스 엔진이고, 에이전시 시절 급하게 띄운 내부 도구가 SQLite 파일 하나로 몇 년을 버티는 걸 여러 번 봤습니다. 서버를 따로 띄우지 않아도 되고, 로컬 파일 하나로 테스트가 끝나고, 작은 관리자 도구나 내부 앱은 생각보다 오래 갑니다.
진짜 문제는 다른 데 있습니다. “작아서 편하다”는 장점이 운영에 들어간 뒤에는 그대로 제약이 될 수 있다는 점입니다. 그래서 나는 SQLite를 이렇게 정리합니다. 운영에서 못 쓰는 데이터베이스가 아니라, 운영 구조를 좁게 잡아야 편한 데이터베이스. 단일 서버, 읽기 위주, 작은 팀의 내부 도구, 데스크톱·모바일 앱, 프로토타입에는 잘 맞습니다. 반대로 쓰기 요청이 많고, 여러 서버가 같은 DB를 공유해야 하며, 역할별 권한·복제·고가용성이 필요하다면 PostgreSQL이나 MySQL 같은 서버형 데이터베이스가 더 현실적입니다.
이 글은 SQLite 공식 문서의 적합한 사용 사례, WAL, 구현 한계, 백업 문서를 기준으로 삼았습니다. 특정 프레임워크나 ORM을 전제로 하지 않고, 작은 웹 서비스나 내부 도구를 운영하려는 개발자가 판단할 수 있는 기준에 초점을 맞췄습니다. (최종 업데이트: 2026-07-07)
SQLite를 개발용으로만 보면 놓치는 장점
SQLite는 “가벼운 장난감 DB”라기보다 애플리케이션에 붙어 들어가는 데이터베이스 엔진에 가깝습니다. 공식 문서도 SQLite가 별도 서버 없이 동작하고, 설정이 거의 필요 없으며, 파일 하나로 데이터를 다룰 수 있다는 점을 주요 장점으로 설명합니다. 이 구조 덕분에 작은 서비스에서는 운영 부품이 줄어듭니다. (출처: SQLite - Appropriate Uses For SQLite)
PostgreSQL을 쓰면 데이터베이스 서버, 계정, 네트워크, 백업, 접속 제한을 따로 관리해야 합니다. 이게 나쁜 것은 아닙니다. 다만 개인 프로젝트나 작은 내부 도구에서는 그 관리 비용이 기능 개발보다 커질 때가 있습니다. 나는 팀 규모를 기준으로 잡습니다. DB를 전담할 사람이 없는 팀이라면, 관리할 부품이 하나라도 적은 쪽이 대개 옳은 선택입니다. SQLite는 그 반대입니다. 배포 단위가 단순해지고, 로컬과 운영의 차이가 줄어듭니다.
특히 아래 같은 경우에는 SQLite가 꽤 현실적인 선택입니다.
| 상황 | SQLite가 편한 이유 | 먼저 확인할 점 |
|---|---|---|
| 개인 블로그, 작은 CMS, 내부 관리자 도구 | 서버 하나와 DB 파일 하나로 운영 가능 | 쓰기 요청이 얼마나 자주 생기는가 |
| 데스크톱·모바일 앱 | 앱 내부 저장소로 자연스럽게 들어감 | 기기 백업과 데이터 마이그레이션 방식 |
| 프로토타입·MVP | 설치와 운영 비용이 낮음 | 나중에 서버형 DB로 옮길 여지 |
| 읽기 위주 서비스 | 파일 기반 구조가 단순하고 빠름 | 배포 중 파일이 날아가지 않는가 |
여기서 핵심은 “트래픽이 작으면 무조건 SQLite”가 아닙니다. 트래픽보다 중요한 건 쓰기 패턴입니다. 하루 방문자가 많아도 대부분 읽기라면 버틸 수 있습니다. 반대로 방문자는 적어도 결제, 주문, 채팅, 로그처럼 쓰기가 몰리면 빨리 불편해집니다.
운영 전 첫 질문은 데이터 크기가 아니라 쓰기 방식입니다
SQLite를 검토할 때 가장 자주 나오는 질문은 “몇 GB까지 괜찮나요?”입니다. 하지만 실무에서 먼저 막히는 지점은 파일 크기보다 동시 쓰기입니다.
SQLite 공식 한계 문서는 데이터베이스 파일의 이론적 최대 크기를 약 281TB로 설명합니다. 숫자만 보면 웬만한 서비스에는 충분해 보입니다. 다만 공식 문서도 아주 큰 데이터베이스를 생각한다면 여러 파일과 볼륨에 데이터를 나누는 클라이언트/서버 DB 엔진을 검토하라고 말합니다. (출처: SQLite - Implementation Limits, SQLite - Appropriate Uses For SQLite)
그래서 질문을 이렇게 바꾸는 편이 낫습니다.
- 동시에 글을 쓰는 사용자나 작업자가 많은가?
- 짧은 시간에 주문, 결제, 로그, 이벤트가 몰리는가?
- 백그라운드 작업과 웹 요청이 같은 DB 파일에 자주 쓰는가?
- 쓰기 실패나 대기 시간이 사용자 경험에 바로 드러나는가?
이 질문에 많이 걸리면 파일 크기가 작아도 서버형 DB가 더 편합니다. 반대로 데이터가 몇 GB여도 하루에 몇 번만 쓰고 대부분 읽는다면 SQLite를 계속 쓸 수 있습니다. SQLite의 강점은 “작은 데이터만 처리한다”가 아니라 “단순한 접근 패턴에서 관리 비용이 낮다”는 쪽에 가깝습니다.
WAL을 켜면 좋아지지만 만능 동시성 해법은 아닙니다

SQLite 운영 글에서 자주 나오는 설정이 WAL입니다. WAL은 Write-Ahead Logging의 약자로, 변경 내용을 별도 로그 파일에 먼저 기록하는 저널 모드입니다. SQLite 문서는 WAL 모드에서 reader가 writer를 막지 않고, writer도 reader를 막지 않아 읽기와 쓰기가 동시에 진행될 수 있다고 설명합니다. (출처: SQLite - Write-Ahead Logging)
이 말만 보면 동시성 문제가 사라지는 것처럼 느껴집니다. 하지만 그렇게 이해하면 위험합니다. WAL은 읽기와 쓰기의 충돌을 줄여 주는 장치이지, 여러 쓰기 작업이 무제한으로 병렬 처리되는 구조로 바꾸는 기능은 아닙니다. 쓰기 트랜잭션이 길거나, 여러 프로세스가 계속 쓰려고 하면 병목은 여전히 생깁니다.
운영에서 WAL을 켤지 판단할 때는 아래 정도로 보면 됩니다.
PRAGMA journal_mode = WAL;
- 읽기 요청이 많고, 간헐적으로 쓰는 서비스라면 WAL이 도움이 될 가능성이 큽니다.
- 쓰기 트랜잭션은 짧게 유지해야 합니다. 트랜잭션 안에서 외부 API 호출이나 긴 파일 작업을 섞으면 대기 시간이 커집니다.
- DB 파일과 WAL 파일이 같은 저장소 정책 아래 안전하게 보존되는지 확인해야 합니다.
- 네트워크 파일시스템 위에서 여러 서버가 같은 SQLite 파일을 만지는 구조는 피하는 편이 안전합니다.
즉 WAL은 “SQLite를 운영에서 쓸 수 있게 해 주는 기본 점검 항목”이지, “PostgreSQL이 필요 없어지는 버튼”은 아닙니다.
이런 구조라면 SQLite가 잘 맞습니다
SQLite가 빛나는 구조는 생각보다 명확합니다. 서버가 하나이고, 애플리케이션과 DB 파일이 같은 머신에 있으며, 쓰기가 짧고 예측 가능할 때입니다. 이 조건이 맞으면 데이터베이스 서버를 따로 운영하지 않는 단순함이 꽤 큰 장점이 됩니다.
예를 들어 작은 사내 도구를 생각해 볼 수 있습니다. 사용자는 몇 명이고, 하루에 수정되는 데이터는 많지 않습니다. 대부분은 목록을 조회하거나 상태를 확인하는 요청입니다. 이런 서비스에 처음부터 RDS 인스턴스, 보안 그룹, DB 계정 정책, 백업 스냅샷까지 붙이면 운영은 탄탄해지지만 시작 비용도 같이 올라갑니다.
SQLite가 맞는 경우는 보통 이렇습니다.
- 단일 서버 또는 단일 컨테이너에서만 실행한다.
- 사용자가 적고, 쓰기 작업이 짧고 드물다.
- 장애가 나도 복구 목표를 파일 백업 기준으로 설명할 수 있다.
- DB 권한을 사용자별로 세밀하게 나눌 필요가 없다.
- 분석 쿼리나 대용량 집계는 별도 시스템으로 분리할 수 있다.
여기서 마지막 조건을 빼면 판단이 흐려집니다. SQLite 하나로 애플리케이션 저장소, 로그 저장소, 분석 저장소를 모두 처리하려고 하면 금방 무거워집니다. 운영에서 오래 쓰려면 SQLite가 맡을 일을 좁게 정해야 합니다.
이런 신호가 보이면 PostgreSQL 전환을 검토하세요
SQLite를 쓰다가 PostgreSQL로 넘어가야 하는 순간은 보통 성능 수치 하나로 오지 않습니다. 운영 방식이 달라질 때 옵니다. 특히 서버 수, 권한, 백업, 동시 쓰기 요구가 커지면 전환 비용보다 유지 비용이 더 커질 수 있습니다.
아래 신호가 2개 이상 겹치면 전환 검토를 시작하는 편이 좋습니다.
- 웹 서버를 여러 대로 늘려야 한다.
- 같은 DB에 쓰는 백그라운드 작업자가 늘어난다.
- 사용자가 동시에 수정하는 화면이 많아진다.
- DB 사용자별 권한, 감사 로그, 접근 제어가 필요하다.
- 읽기 복제, 장애 조치, 관리형 백업이 필요하다.
- 대용량 집계와 운영 트랜잭션이 같은 DB에서 부딪힌다.
- 파일 백업만으로 복구 목표를 설명하기 어렵다.
이 단계에서 “SQLite가 나쁘다”고 판단할 필요는 없습니다. 데이터베이스의 역할이 달라진 겁니다. SQLite는 애플리케이션 안쪽에 붙어 단순하게 움직일 때 좋고, PostgreSQL은 여러 클라이언트가 네트워크로 접속해 권한과 동시성을 나눠 가져야 할 때 강합니다.
전환이 예상된다면 처음부터 SQL과 ORM 사용을 조금 보수적으로 가져가는 편이 좋습니다. SQLite 전용 함수나 느슨한 타입 처리에 과하게 기대면 나중에 옮길 때 쿼리를 많이 다시 써야 합니다. 반대로 마이그레이션 파일, 테스트 데이터, 백업 복구 절차를 일찍 만들어 두면 전환은 훨씬 덜 아픕니다.
백업은 파일 복사가 아니라 복구 연습까지 포함해야 합니다
SQLite는 파일 하나라서 백업이 쉬워 보입니다. 운영 중인 DB 파일을 그냥 복사하면 될 것 같지만, 쓰기 중인 파일을 무작정 복사하면 일관성 문제가 생길 수 있습니다. 그래서 SQLite는 온라인 백업 API와 VACUUM INTO 같은 백업 방법을 문서로 안내합니다. (출처: SQLite - Online Backup API)
운영에서 최소한 정해야 할 것은 세 가지입니다.
- 언제 백업할 것인가: 매일 새벽인지, 배포 전인지, 중요한 작업 전인지
- 어디에 보관할 것인가: 같은 서버 디스크인지, 외부 스토리지인지
- 어떻게 복구할 것인가: 새 서버에서 몇 분 안에 실제로 띄울 수 있는지
작은 서비스일수록 백업은 “나중에”로 밀리기 쉽습니다. 하지만 SQLite는 DB가 파일 하나라 파일 손상, 디스크 장애, 잘못된 배포의 영향이 직접적입니다. 파일 하나라서 쉬운 만큼, 복구 명령도 문서화해 두는 게 좋습니다. 넘겨받은 프로젝트에서 백업 파일은 꼬박꼬박 쌓여 있는데 막상 복구는 한 번도 해 본 적 없는 경우를 여러 번 봤습니다. 그런 백업은 사고가 났을 때 위안은 되어도 도움은 안 됩니다.
간단한 점검 예시는 이렇습니다.
# 예시: 운영 DB를 백업 파일로 복사한 뒤 무결성 확인
sqlite3 app.db ".backup 'backup/app-$(date +%Y%m%d).db'"
sqlite3 backup/app-20260707.db "PRAGMA integrity_check;"
이 명령 자체보다 중요한 건 복구 리허설입니다. 백업 파일이 있어도 새 환경에서 애플리케이션이 그 파일을 읽고 정상 동작하는지 확인하지 않으면 백업이 아니라 보관물에 가깝습니다.
배포 구조를 먼저 그려 보면 답이 빨라집니다
SQLite 선택은 데이터베이스 엔진 비교보다 배포 구조 문제에 가깝습니다. 서버가 하나인지, 컨테이너가 자주 교체되는지, 파일시스템이 영구 보존되는지, 배포 때 DB 파일이 함께 날아가지 않는지부터 봐야 합니다.
예를 들어 PaaS나 컨테이너 환경에서 임시 파일시스템만 제공한다면 SQLite 운영은 조심해야 합니다. 애플리케이션이 재시작될 때 파일이 사라지거나, 새 인스턴스가 뜨면서 다른 빈 DB 파일을 볼 수 있기 때문입니다. 이런 구조에서는 영구 볼륨을 명확히 붙이거나, 처음부터 서버형 DB를 쓰는 편이 단순합니다.
배포 전에는 아래 질문을 체크하세요.
- DB 파일은 코드 배포 산출물 밖에 있는가?
- 재배포해도 DB 파일이 삭제되지 않는가?
- 백업 파일과 WAL 파일까지 같은 정책으로 보존되는가?
- 서버를 두 대 이상 띄우면 각각 다른 DB 파일을 보게 되지 않는가?
- 롤백할 때 애플리케이션 버전과 DB 마이그레이션 버전이 맞는가?
이 질문에 답하기 어렵다면 SQLite를 쓰기 전에 배포 구조부터 정리해야 합니다. SQLite는 단순하지만, 그 단순함은 파일 위치가 분명할 때만 장점으로 작동합니다.
운영 적용 전 체크리스트
아래 체크리스트를 대부분 통과한다면 SQLite를 운영에 올리는 판단이 더 명확해집니다. 하나라도 답이 흐리면 금지라는 뜻은 아니지만, 그 항목을 먼저 설계해야 합니다.
- 서비스는 단일 서버 또는 단일 writer 구조로 설명할 수 있다.
- 쓰기 트랜잭션은 짧고, 외부 API 호출을 트랜잭션 안에 넣지 않는다.
- WAL 사용 여부와 파일 보존 정책을 정했다.
- DB 파일은 배포 산출물과 분리된 영구 저장소에 있다.
- 백업 명령뿐 아니라 복구 절차를 테스트했다.
-
PRAGMA integrity_check;같은 기본 점검을 운영 절차에 넣었다. - 서버형 DB로 옮길 때 필요한 마이그레이션 파일과 테스트가 있다.
- 사용자별 DB 권한, 읽기 복제, 자동 장애 조치가 당장 필요하지 않다.
체크리스트의 목적은 SQLite를 포기하게 만드는 것이 아닙니다. 오히려 반대입니다. 작은 서비스에서 SQLite를 오래 쓰려면, SQLite가 잘하는 범위 안에 문제를 가둬야 합니다.
FAQ
SQLite는 운영에서 쓰면 안 되나요?
그렇지 않습니다. SQLite 공식 문서도 중저트래픽 웹사이트, 임베디드 시스템, 애플리케이션 파일 포맷 등 여러 적합한 사용 사례를 설명합니다. 다만 여러 서버가 동시에 붙는 구조, 강한 권한 관리, 높은 동시 쓰기 요구가 있으면 서버형 DB가 더 맞습니다. (출처: SQLite - Appropriate Uses For SQLite)
WAL만 켜면 동시성 문제는 해결되나요?
아닙니다. WAL은 reader와 writer의 충돌을 줄여 읽기·쓰기 동시성을 개선합니다. 하지만 쓰기 작업이 길거나 여러 writer가 계속 몰리는 구조라면 병목이 남습니다. WAL은 기본 점검 항목이지 만능 해법은 아닙니다.
SQLite 파일이 커지면 바로 PostgreSQL로 옮겨야 하나요?
파일 크기만으로 판단하기는 어렵습니다. 공식 한계는 매우 크지만, 실무에서는 쿼리 패턴, 인덱스, 백업 시간, 복구 시간, 쓰기 대기 시간이 먼저 문제가 됩니다. “몇 GB인가”보다 “운영 중 백업과 복구가 가능한가”를 먼저 보세요.
컨테이너 환경에서도 SQLite를 쓸 수 있나요?
쓸 수는 있지만 영구 볼륨이 분명해야 합니다. 컨테이너가 교체될 때 DB 파일이 사라지거나, 여러 인스턴스가 각자 다른 파일을 보면 운영 데이터가 갈라집니다. 서버를 여러 대로 늘릴 계획이 있다면 서버형 DB가 보통 더 단순합니다.
처음에는 SQLite로 시작하고 나중에 PostgreSQL로 옮겨도 될까요?
가능합니다. 대신 처음부터 마이그레이션 파일을 남기고, SQLite 전용 동작에 과하게 의존하지 않는 편이 좋습니다. 작은 서비스라면 SQLite로 빠르게 시작하되, 동시 쓰기와 배포 구조가 바뀌는 시점에 전환 판단을 다시 하면 됩니다.
우리 상황이라면 어느 쪽인가
마지막으로 판단을 한 장에 눌러 담으면 이렇습니다.
| 우리 상황 | 손이 가는 쪽 |
|---|---|
| 단일 서버, 읽기 위주, 짧은 쓰기 | SQLite로 충분 |
| 배포마다 컨테이너가 교체되는 구조 | 영구 볼륨 확보가 먼저, 아니면 서버형 DB |
| 동시 쓰기·다중 서버·권한 분리 요구 | PostgreSQL / MySQL 검토 |
| 대용량 집계와 운영 트랜잭션이 한 DB에서 충돌 | 저장소 역할 분리 또는 서버형 DB |
| 파일 백업만으로 복구를 설명하기 어려움 | 관리형 백업이 있는 서버형 DB |
결국 물어야 할 건 “SQLite가 운영에서 되느냐”가 아니라 “우리 운영 구조가 SQLite에 맞느냐”입니다. 서비스의 쓰기 흐름을 한 문장으로 설명할 수 있으면 SQLite는 오래 버팁니다. 누가, 언제, 얼마나 자주 같은 DB 파일에 쓰는지가 그 문장입니다. 설명이 길어지기 시작하면, 그건 DB를 키울 때가 아니라 운영 구조를 다시 그릴 때라는 신호입니다.
댓글