# What Database Technologies Are Used by Meetily? SQLite and SQLx Explained

> Discover how Meetily leverages SQLite and SQLx for local offline meeting data storage. Explore their async Rust ORM integration for efficient data management.

- Repository: [Zackriya Solutions/meetily](https://github.com/Zackriya-Solutions/meetily)
- Tags: internals
- Published: 2026-07-29

---

**Meetily stores all persistent data in an embedded SQLite database and interacts with it exclusively through the async Rust ORM sqlx, keeping every meeting record local and offline.**

Zackriya-Solutions/meetily is a privacy-first meeting assistant that keeps all data on the user's machine. The database technologies used by Meetily center on a lightweight pairing of **SQLite** for file-based storage and **SQLx** for type-safe async queries.

## The Core Database Technologies Behind Meetily

### SQLite: The Local Relational Engine

Meetily persists every meeting, transcript, summary, and setting into a single **SQLite** file named `meeting_minutes.sqlite`. Because SQLite is a serverless, file-based database engine, Meetily never contacts an external database server. The entire data layer lives inside the user's application-data directory, making the app fully offline-first.

### SQLx: Compile-Time Checked Async ORM

All database interactions flow through **`sqlx`** version `0.8` with the features `runtime-tokio`, `sqlite`, and `chrono` enabled. According to the [`frontend/src-tauri/Cargo.toml`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/Cargo.toml) manifest, this setup provides **async** connection pooling via `SqlitePool`, compile-time-checked queries, and built-in migration support. The `DatabaseManager` type in the source code wraps these capabilities into a reusable interface.

## Initializing the Database on App Startup

When the Tauri application launches, `initialize_database_on_startup` in [`frontend/src-tauri/src/database/setup.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/setup.rs) decides whether this is the user's first run or a normal startup. If it is not the first launch, the function creates a `DatabaseManager` and injects it into the shared application state.

```rust
// src/database/setup.rs
pub async fn initialize_database_on_startup(app: &AppHandle) -> Result<(), String> {
    // Detect first launch → emit event or initialise immediately
    let is_first_launch = DatabaseManager::is_first_launch(app).await?;
    if is_first_launch {
        // First‑run path – UI can show onboarding
    } else {
        // Normal start – create manager and inject into shared state
        let db_manager = DatabaseManager::new_from_app_handle(app)
            .await
            .map_err(|e| format!("Failed to init DB: {}", e))?;
        app.manage(AppState { db_manager });
    }
    Ok(())
}

```

This pattern ensures that the SQLite file is ready before any UI component attempts to query data.

## Creating the SQLite File and Running Migrations

The `DatabaseManager::new` function in [`frontend/src-tauri/src/database/manager.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/manager.rs) handles the physical database file. It creates the parent directory if needed, copies an existing database or creates a new one with `Sqlite::create_database`, connects a `SqlitePool`, and then applies migrations.

```rust
// src/database/manager.rs
pub async fn new(tauri_db_path: &str, backend_db_path: &str) -> Result<Self> {
    // Ensure parent directory exists
    if let Some(parent) = Path::new(tauri_db_path).parent() {
        fs::create_dir_all(parent)?;
    }

    // Create or copy the DB file
    if !Path::new(tauri_db_path).exists() {
        if Path::new(backend_db_path).exists() {
            fs::copy(backend_db_path, tauri_db_path)?;
        } else {
            Sqlite::create_database(tauri_db_path).await?;
        }
    }

    // Build a connection pool and run migrations
    let pool = SqlitePool::connect(tauri_db_path).await?;
    sqlx::migrate!("./migrations").run(&pool).await?;
    Ok(DatabaseManager { pool })
}

```

Migrations live in `frontend/src-tauri/migrations` and are referenced by the macro `sqlx::migrate!("./migrations")`. This guarantees that schema changes stay up-to-date across releases.

## Querying Meeting Data with SQLx

Actual CRUD operations are performed in modules like [`frontend/src-tauri/src/database/commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/commands.rs). The following simplified example shows how Meetily fetches every meeting record using `sqlx::query_as` and maps rows to a `MeetingModel` struct.

```rust
// src/database/commands.rs (simplified)
pub async fn get_all_meetings(db: &DatabaseManager) -> Result<Vec<MeetingModel>> {
    sqlx::query_as::<_, MeetingModel>("SELECT * FROM meeting")
        .fetch_all(db.pool())
        .await
}

```

The `MeetingModel` type is defined in [`frontend/src-tauri/src/database/models.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/models.rs) alongside other `#[derive(sqlx::FromRow)]` structs such as `Transcript` and `SummaryProcess`. Repository-specific logic is further organized under `frontend/src-tauri/src/database/repositories/`.

## Key Source Files in Meetily's Database Layer

- **[`frontend/src-tauri/Cargo.toml`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/Cargo.toml)** — Declares the `sqlx` dependency with the `sqlite` feature.
- **[`frontend/src-tauri/src/database/mod.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/mod.rs)** — Re-exports the database submodules for the rest of the application.
- **[`frontend/src-tauri/src/database/manager.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/manager.rs)** — Contains the `DatabaseManager` struct that manages the `SqlitePool` and migrations.
- **[`frontend/src-tauri/src/database/setup.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/setup.rs)** — Boots the database on startup and detects first-launch scenarios.
- **[`frontend/src-tauri/src/database/models.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/models.rs)** — Defines `sqlx::FromRow` structs that map SQLite tables to Rust types.
- **[`frontend/src-tauri/src/database/commands.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/commands.rs)** — Provides high-level async functions for CRUD operations.
- **`frontend/src-tauri/src/database/repositories/*`** — Implements the repository pattern for entities like meetings and transcripts.
- **`frontend/src-tauri/migrations/`** — Holds SQL migration scripts applied automatically at runtime.

## Summary

- Meetily relies on an **embedded SQLite** database stored in a local `meeting_minutes.sqlite` file.
- The **SQLx** async ORM handles all queries, pooling, and migrations via `SqlitePool`.
- The `DatabaseManager` type in [`manager.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/manager.rs) creates the database file, establishes the pool, and runs `sqlx::migrate!` on startup.
- All meeting data stays on the user's machine because Meetily never connects to an external database server.

## Frequently Asked Questions

### Does Meetily use PostgreSQL or MySQL?

No. Meetily uses only **SQLite** as implemented in the project source code. The `sqlx` crate is compiled with the `sqlite` feature alone, and the application is intentionally designed to remain offline-first without external database servers.

### Where is the Meetily database file stored on disk?

The SQLite file is named `meeting_minutes.sqlite` and resides in the user's application-data directory. The exact path is determined at runtime by the `DatabaseManager` and passed as `tauri_db_path` in [`frontend/src-tauri/src/database/manager.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/manager.rs).

### How does Meetily handle database schema changes?

Schema changes are managed through versioned SQL migration scripts stored in `frontend/src-tauri/migrations`. The `DatabaseManager` automatically executes `sqlx::migrate!("./migrations").run(&pool)` whenever the application starts, ensuring the schema is current.

### What Rust crate does Meetily use for database access?

Meetily uses **`sqlx`** version `0.8` with the `runtime-tokio`, `sqlite`, and `chrono` features. This crate provides the `SqlitePool`, compile-time query checking, and migration runner that power the entire data layer.