# Dual-Mode Persistence Guide
AbsurderSQL is a **dual-mode** library that supports both **Browser (IndexedDB)** and **Native (filesystem)** persistence. This unique capability allows you to build offline-first web applications while maintaining full CLI/server access to the same data.
## Browser Mode (WASM)
**Target:** Web applications running in browsers
**Storage Backend:** IndexedDB via custom SQLite VFS
**Key Features:**
- Full SQLite functionality in the browser
- Multi-tab coordination with leader election
- Optimistic updates and write queuing
- Crash consistency and checksums
- Works without CORS headers or SharedArrayBuffer
**Usage:**
```javascript
import init, { Database } from '@npiesco/absurder-sql';
await init();
const db = await Database.newDatabase('my_app');
await db.execute('CREATE TABLE users (id INTEGER, name TEXT)');
await db.execute("INSERT INTO users VALUES (1, 'Alice')");
const result = await db.execute('SELECT * FROM users');
```
**Data Location:** Browser IndexedDB (`IndexedDB → <db_name>`)
---
## Native Mode (Rust CLI/Server)
**Target:** Command-line tools, servers, desktop applications
**Storage Backend:** Traditional filesystem with SQLite .db files
**Key Features:**
- Standard SQLite database files (`.sqlite`)
- Compatible with all SQLite tools (sqlite3, DB Browser, etc.)
- BlockStorage metadata for integrity
- Same Rust API as browser mode
- Full filesystem persistence
**Usage:**
```rust
use absurder_sql::database::SqliteIndexedDB;
use absurder_sql::types::{DatabaseConfig, ColumnValue};
let config = DatabaseConfig {
name: "my_app.db".to_string(),
cache_size: Some(2000),
page_size: None,
journal_mode: None,
auto_vacuum: None,
version: Some(1),
};
let mut db = SqliteIndexedDB::new(config).await?;
db.execute("CREATE TABLE users (id INTEGER, name TEXT)").await?;
db.execute("INSERT INTO users VALUES (1, 'Alice')").await?;
let result = db.execute("SELECT * FROM users").await?;
```
**Data Location:** `./absurdersql_storage/<db_name>/`
**Filesystem Structure:**
```
absurdersql_storage/
└── my_app/
├── database.sqlite # Standard SQLite database file
├── blocks/ # BlockStorage blocks (4KB each)
│ ├── block_0.bin
│ ├── block_1.bin
│ └── ...
├── metadata.json # Block metadata with checksums
└── allocations.json # Block allocation tracking
```
---
## Use Cases
### 1. Offline-First Web Apps with Server Sync
**Scenario:** Build a web app that works offline, with optional server synchronization.
**Architecture:**
- **Browser:** Users work with data stored in IndexedDB
- **Server:** Periodic sync using CLI tool to process/backup data
- **Benefit:** App works offline, server handles sync/backup when needed
**Example:**
```javascript
// Browser: User creates todo
await db.execute("INSERT INTO todos (text, done) VALUES ('Buy milk', 0)");
// Server: Periodic sync (Rust)
let result = db.execute("SELECT * FROM todos WHERE synced = 0").await?;
// Process and mark as synced
```
### 2. Debug Production Data Locally
**Scenario:** Users report bugs with their data - download and debug locally.
**Workflow:**
1. User exports IndexedDB from browser (built-in browser tools)
2. Developer loads data into local AbsurderSQL CLI
3. Query and analyze using standard SQLite tools
4. Reproduce issue with actual user data
**Example:**
```bash
# Export from browser DevTools → Application → IndexedDB
# Import to local CLI
cargo run --bin cli_query --features fs_persist -- "SELECT * FROM users WHERE issue = 'bug'"
```
### 3. Desktop Apps with Web Preview
**Scenario:** Build desktop apps (Tauri, Electron) with web preview functionality.
**Architecture:**
- **Desktop:** Native AbsurderSQL with filesystem persistence
- **Web Preview:** WASM AbsurderSQL with IndexedDB
- **Benefit:** Same codebase, different persistence backends
### 4. Development Tools
**Scenario:** Inspect browser data using CLI tools during development.
**Workflow:**
```bash
# While web app is running in browser...
# Query the data from CLI
cargo run --bin cli_query --features fs_persist -- ".tables"
cargo run --bin cli_query --features fs_persist -- "SELECT COUNT(*) FROM users"
```
---
## CLI Query Tool
AbsurderSQL includes a production-ready CLI tool for querying filesystem databases:
**Installation:**
```bash
cargo build --bin cli_query --features fs_persist --release
```
**Usage:**
```bash
# Create table
cargo run --bin cli_query --features fs_persist -- \
"CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)"
# Insert data
cargo run --bin cli_query --features fs_persist -- \
"INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com')"
# Query data
cargo run --bin cli_query --features fs_persist -- \
"SELECT * FROM users"
# Special commands
cargo run --bin cli_query --features fs_persist -- ".tables"
cargo run --bin cli_query --features fs_persist -- ".schema"
```
**Output:**
```
AbsurderSQL CLI Query Tool
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Database: cli_demo.db
[STORAGE] ./absurdersql_storage/cli_demo/
[EXEC] Executing: SELECT * FROM users
┌────────────────────────────────────────────────────────────┐
│ id │ name │ email │
├────────────────────────────────────────────────────────────┤
│ 1 │ Alice │ alice@example.com │
└────────────────────────────────────────────────────────────┘
1 row(s) returned
Execution time: 0.02ms
```
**Environment Variables:**
- `ABSURDERSQL_FS_BASE`: Override base storage directory (default: `./absurdersql_storage`)
---
## Comparison with absurd-sql
| **Browser Support** | **[✓]** Yes | **[✓]** Yes |
| **Native/CLI Support** | **[X]** No | **[✓]** Yes |
| **Filesystem .db files** | **[X]** No | **[✓]** Yes |
| **Standard SQLite tools** | **[X]** No | **[✓]** Yes |
| **Debug production data locally** | **[X]** No | **[✓]** Yes |
| **Server-side processing** | **[X]** No | **[✓]** Yes |
**Key Advantage:** AbsurderSQL supports both modes, absurd-sql is **browser-only**.
---
## Testing
AbsurderSQL includes comprehensive tests for dual-mode functionality:
**Unit Tests (Native):**
```bash
cargo test --features fs_persist native_database_persistence_tests
```
**E2E Tests (Browser + CLI):**
```bash
npx playwright test dual_mode_persistence
```
**Manual Testing:**
```bash
# Browser: Open web app, create data in IndexedDB
# CLI: Query filesystem database
cargo run --bin cli_query --features fs_persist -- "SELECT * FROM my_table"
```
---
## Technical Details
### Browser Mode Implementation
- Uses `wasm-bindgen` for JavaScript interop
- Custom SQLite VFS redirects to IndexedDB
- BlockStorage manages 4KB blocks in IndexedDB
- Multi-tab coordination via localStorage + BroadcastChannel
### Native Mode Implementation
- Uses `rusqlite` for SQLite C API
- Direct filesystem I/O via `std::fs`
- BlockStorage writes to `./absurdersql_storage/`
- Single-threaded (no multi-process coordination needed)
### Shared Components
- Same Rust core (`AbsurderSQL Core`)
- Same BlockStorage architecture
- Same metadata format
- Same integrity checks (checksums, MVCC)
### Feature Flags
- **Browser:** Default build (WASM target)
- **Native:** Requires `fs_persist` feature flag
**Build Commands:**
```bash
# Browser (WASM)
wasm-pack build --target web
# Native (CLI)
cargo build --features fs_persist
```
---
## Getting Started
### Browser Setup
```bash
wasm-pack build --target web
# Use pkg/absurder_sql.js in your web app
```
### Native Setup
```bash
cargo add absurder-sql
# Enable fs_persist feature in Cargo.toml:
# absurder-sql = { version = "0.1", features = ["fs_persist"] }
```
### Example Projects
- **Browser:** `examples/vite-app/` - Full-featured web app
- **Native:** `examples/cli_query.rs` - CLI query tool
- **E2E:** `tests/e2e/dual_mode_persistence.spec.js` - Both modes
---
## Best Practices
1. **Use consistent database names** between browser and native modes
2. **Enable checksums** for data integrity in both modes
3. **Test both modes** if your app uses dual-mode functionality
4. **Document storage locations** for users/operators
5. **Implement export/import** if users need to migrate data between modes
---
## Related Documentation
- [Multi-Tab Coordination Guide](MULTI_TAB_GUIDE.md) - Browser multi-tab features
- [Transaction Support](TRANSACTION_SUPPORT.md) - Transaction handling
- [Benchmark Results](BENCHMARK.md) - Performance metrics
- [Demo Guide](../examples/DEMO_GUIDE.md) - Interactive examples
---
## Summary
AbsurderSQL's **dual-mode persistence** is a unique capability that allows you to:
**[✓]** Build offline-first web apps with IndexedDB
**[✓]** Query the same data from CLI/server with filesystem access
**[✓]** Debug production data locally using standard SQLite tools
**[✓]** Run the same Rust codebase in browser AND on server
**[✓]** Maintain data integrity with checksums in both modes
**No other library** (including absurd-sql) provides this flexibility. AbsurderSQL is truly **universal SQLite**.