IndexedDB
IndexedDB는 브라우저 안에서 구조화된 데이터를 비동기로 저장하고 조회할 수 있게 해주는 클라이언트 측 데이터베이스 API입니다. 단순 문자열만 저장하는 Web Storage와 달리 객체 형태 레코드, 인덱스 검색, 트랜잭션을 지원하므로 오프라인 데이터, 대용량 캐시, 검색 가능한 로컬 상태를 다룰 때 적합합니다.
▶아키텍처 다이어그램
🔍 구조 다이어그램점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다
브라우저에 데이터를 저장해야 한다고 해서 항상 Web Storage로 충분한 것은 아닙니다. localStorage는 문자열 키-값 저장소라 구조화된 데이터를 다루기 불편하고, 동기 API라 큰 데이터를 읽고 쓰면 메인 스레드가 멈춥니다. 사용자 메일 수백 통, 오프라인 편집 초안, 검색 가능한 목록처럼 데이터 양이 커지면 단순한 설정 저장소로는 버티기 어렵습니다. 특히 네트워크가 잠깐 끊겨도 계속 동작해야 하는 웹 앱에서는 서버 응답을 그대로 메모리에만 들고 있을 수 없습니다. 브라우저 안에 더 큰 용량으로, 검색 가능하게, 비동기로 저장할 수 있는 구조가 필요해집니다.
웹이 문서 뷰어를 넘어 애플리케이션 플랫폼이 되면서 브라우저 안에서 다뤄야 하는 상태의 양도 급격히 늘었습니다. 초기에는 쿠키와 localStorage 같은 단순 저장소가 이 역할을 일부 맡았지만, 오프라인 메일, 지도, 문서 편집기처럼 데이터량이 큰 앱이 등장하자 한계가 분명해졌습니다. 한때는 Web SQL처럼 브라우저 안에 SQL 데이터베이스를 넣으려는 시도도 있었지만, 특정 엔진에 종속된다는 이유로 표준화가 멈췄습니다. 대신 브라우저가 자체적으로 구조화된 레코드 저장소와 인덱스를 제공하는 IndexedDB가 표준 경로가 됐습니다. HTML5 이후 오프라인 우선과 PWA 흐름이 커지면서 IndexedDB는 브라우저 내부의 사실상 기본 데이터베이스 자리를 차지하게 됐습니다.
IndexedDB는 브라우저 안에 작은 데이터베이스를 두는 방식으로 동작합니다. 먼저 애플리케이션이 데이터베이스를 열면, 브라우저는 이름과 버전을 기준으로 기존 DB를 찾습니다. 버전이 올라간 경우에는 onupgradeneeded 단계가 열리고, 여기서 object store와 index를 만듭니다. object store는 레코드를 담는 기본 단위이고, index는 특정 필드로 빠르게 찾기 위한 보조 구조입니다. 실제 읽기·쓰기는 transaction 안에서 일어납니다. readwrite 트랜잭션을 열고 put, get, delete 같은 작업을 수행하면, 브라우저가 이를 원자적인 단위로 처리합니다. 중간에 실패하면 일부만 반영되지 않고 전체 단위로 취소할 수 있습니다. 중요한 차이는 비동기성입니다. 결과는 즉시 반환되지 않고 이벤트나 Promise 래퍼를 통해 나중에 도착합니다. 덕분에 큰 데이터를 다뤄도 UI가 오래 멈추지 않습니다. 많은 레코드를 훑어야 할 때는 cursor를 열어 순차적으로 읽고, 특정 필드를 기준으로 찾을 때는 index를 사용합니다.
IndexedDB와 Web Storage는 둘 다 브라우저 저장소지만 역할이 다릅니다. Web Storage는 문자열 키-값을 동기적으로 읽고 쓰는 단순 저장소라 테마, 언어, 마지막 탭 같은 작은 설정값에 적합합니다. IndexedDB는 객체 단위 데이터를 비동기로 저장하고 인덱스로 검색할 수 있어, 데이터량이 크거나 조회 조건이 있는 경우에 맞습니다. 또 하나의 경계는 서버 데이터베이스와의 차이입니다. IndexedDB는 브라우저마다 따로 존재하므로 여러 기기 사이에서 자동으로 공유되지 않습니다. 서버의 진실 소스(source of truth)를 대체하는 것이 아니라, 네트워크 왕복을 줄이고 오프라인 상태를 견디기 위한 로컬 복제본에 가깝습니다.
IndexedDB는 오프라인 우선 웹 앱에서 가장 힘을 발휘합니다. 사용자가 문서를 편집하거나 메일을 읽을 때 서버 연결이 잠시 끊겨도, 마지막으로 동기화된 데이터와 아직 전송되지 않은 변경 내역을 브라우저 안에 남겨 둘 수 있습니다. 데이터가 많은 검색 화면에서도 유용합니다. 제품 목록, 메시지 기록, 로컬 캐시된 게시물처럼 수백 건 이상의 데이터를 필드 기준으로 빠르게 찾아야 할 때, 단순 배열을 메모리에만 두는 것보다 IndexedDB 인덱스를 쓰는 편이 안정적입니다. 주의할 점은 보안 경계입니다. IndexedDB는 JavaScript가 접근할 수 있는 저장소라서, 페이지 안에서 XSS가 발생하면 그 안의 데이터도 함께 노출됩니다. 따라서 민감한 비밀 자체를 넣기보다는, 유출돼도 바로 계정 탈취로 이어지지 않는 데이터와 동기화용 작업 기록을 저장하는 쪽이 안전합니다.