1 분 소요

개요

  • SQLite를 WebAssembly로 컴파일해 브라우저 / Node.js / Deno / Bun 등 JavaScript 런타임에서 직접 실행
  • 공식 SQLite 프로젝트가 유지·배포 (sqlite-wasm / @sqlite.org/sqlite-wasm)
  • 서버 없이 클라이언트 쪽에서 풀-SQL 데이터베이스 사용 가능
  • 공식 문서 / npm


특징

  • 표준 SQLite: 동일 SQL 문법·기능, 단일 파일 DB
  • 다중 백엔드: 메모리 / IndexedDB(kvvfs) / OPFS (Origin Private File System) — OPFS가 가장 빠르고 권장
  • 동기 API (OPFS SAH): Web Worker + OPFS Sync Access Handle로 동기 I/O 지원 → 트랜잭션 성능 향상
  • 작은 크기: 약 1MB 미만의 .wasm 바이너리(빌드 옵션에 따라)
  • Worker 모드: 메인 스레드 차단 없이 DB 작업


백엔드(VFS) 비교

백엔드 영속성 성능 크기 한계 비고
Memory (:memory:) 없음 최고 RAM 임시 분석·테스트용
kvvfs (localStorage) 있음 낮음 ~5MB 작은 DB, 동기
kvvfs (sessionStorage) 세션 낮음 ~5MB 세션 한정
OPFS 있음 높음 수 GB+ Worker 필요, 권장 백엔드
OPFS SAH Pool 있음 최고 수 GB+ 동기 I/O, 가장 빠름


설치 및 기본 사용

  • 설치

    npm install @sqlite.org/sqlite-wasm
    
  • 메인 스레드 (간단한 사용)

    import sqlite3InitModule from '@sqlite.org/sqlite-wasm';
    
    const sqlite3 = await sqlite3InitModule();
    const db = new sqlite3.oo1.DB(':memory:');
    
    db.exec(`
      CREATE TABLE t(id INTEGER PRIMARY KEY, name TEXT);
      INSERT INTO t(name) VALUES ('hello'), ('world');
    `);
    
    const rows = db.exec({
      sql: 'SELECT * FROM t',
      rowMode: 'object',
      returnValue: 'resultRows',
    });
    console.log(rows);
    


OPFS (영속 저장)

  • HTTPS 또는 localhost 컨텍스트, COOP/COEP 헤더 권장
  • Web Worker 안에서 사용

    // worker.js
    import sqlite3InitModule from '@sqlite.org/sqlite-wasm';
    
    const sqlite3 = await sqlite3InitModule();
    const db = new sqlite3.oo1.OpfsDb('/mydata.sqlite3');
    
    db.exec("CREATE TABLE IF NOT EXISTS log(t TEXT, msg TEXT)");
    db.exec({
      sql: 'INSERT INTO log VALUES (?, ?)',
      bind: [new Date().toISOString(), 'hello opfs'],
    });
    


필요한 HTTP 헤더 (OPFS SAH)

  • 동기 OPFS API는 cross-origin isolation 필요

    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: require-corp
    


Worker + Promiser API

  • 메인 스레드에서 Worker의 SQLite를 Promise 기반으로 호출

    import { sqlite3Worker1Promiser } from '@sqlite.org/sqlite-wasm';
    
    const promiser = await new Promise((resolve) => {
      const p = sqlite3Worker1Promiser({
        onready: () => resolve(p),
      });
    });
    
    await promiser('open', { filename: 'file:demo?vfs=opfs' });
    await promiser('exec', { sql: 'SELECT 1' });
    


활용 사례

  • 오프라인 우선(Offline-first) 웹 앱
  • 로컬 노트·메모·할 일 앱 (Logseq, Excalidraw 등 패턴)
  • 브라우저 내 분석·BI 대시보드 (DuckDB-WASM과 함께)
  • Electron / Tauri 등 데스크톱 웹뷰 앱의 임베디드 DB
  • PWA의 영속 저장 (IndexedDB 대안)


한계

  • IndexedDB·LocalStorage 대비 도구 생태계 작음
  • OPFS는 origin 단위 저장 — 다른 origin과 공유 불가
  • 동기 OPFS SAH는 Worker + COOP/COEP 필요
  • 모바일 사파리 등 일부 환경에서 OPFS 동작 차이 존재


관련 포스트