# How Meetily Stores Meetings, Transcripts, and Summaries in SQLite

> Discover how Meetily stores meeting data, transcripts, and summaries in its SQLite database. Learn about the DatabaseManager struct and sqlx for efficient data management.

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

---

**Meetily persists all meeting-related data—including transcripts, summaries, and metadata—in a local SQLite database managed by the `DatabaseManager` struct in the Tauri backend, using `sqlx` for migrations and connection pooling.**

The open-source meeting assistant Meetily (Zackriya-Solutions/meetily) stores every recording, transcription, and AI-generated summary locally using SQLite. This architecture ensures your sensitive meeting data never leaves your device while providing fast, reliable access to historical records. Understanding how Meetily structures its SQLite database reveals the robust data layer powering this privacy-focused application.

## Database Architecture and Initialization

The database lifecycle is orchestrated by `DatabaseManager` in [`frontend/src-tauri/src/database/manager.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/manager.rs). This Rust struct handles path resolution, connection pooling, and schema migrations automatically when the application starts.

### DatabaseManager and Connection Pooling

When the app launches, `DatabaseManager::new_from_app_handle` constructs the full path to `meeting_minutes.sqlite` in the user's application-data directory (e.g., `~/Library/Application Support/Meetily/` on macOS). It initializes a pooled `SqlitePool` connection using `SqlitePool::connect` and provides a `with_transaction` helper for atomic operations. The manager also performs WAL (Write-Ahead Logging) cleanup on shutdown via `PRAGMA wal_checkpoint(TRUNCATE)` to flush pending writes and remove temporary files.

### Migration System

Meetily uses `sqlx::migrate!("./migrations")` to apply version-controlled schema changes located in `frontend/src-tauri/migrations`. The system automatically runs migration scripts on startup, ensuring the database schema stays synchronized with the application code. Initial schema creation happens in [`20250916100000_initial_schema.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20250916100000_initial_schema.sql), while subsequent files like [`20251101000000_add_summary_backup.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20251101000000_add_summary_backup.sql) and [`20251223000000_add_meeting_notes.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20251223000000_add_meeting_notes.sql) incrementally add tables for summaries and notes.

## Core Database Schema

The SQLite schema separates concerns across specialized tables to maintain data integrity and query performance.

### Meetings Table

The `meetings` table stores high-level session metadata including `id`, `title`, `start_ts`, and `end_ts`. Later migrations such as [`20251006000000_add_audio_sync_fields.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20251006000000_add_audio_sync_fields.sql) extend this table with audio synchronization metadata like `audio_offset`.

### Transcripts and Speakers Tables

Raw transcription data lives in the `transcripts` table with columns for `meeting_id`, `speaker_id`, `text`, and `ts` (timestamp). The [`20251110000001_add_speaker_field.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20251110000001_add_speaker_field.sql) migration enhanced speaker tracking, while the `speakers` table maintains distinct speaker identities with `id` and `name` columns.

### Summaries and Notes Tables

AI-generated meeting summaries are stored in the `summaries` table (added via [`20251101000000_add_summary_backup.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20251101000000_add_summary_backup.sql)), while user-created notes reside in `meeting_notes` (from [`20251223000000_add_meeting_notes.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20251223000000_add_meeting_notes.sql)). Both tables maintain foreign key relationships to the `meetings` table.

## Data Persistence Flow

Meetily's storage pipeline moves audio data through transcription and into SQLite via Tauri commands.

1. **Audio Capture**: The application records raw microphone and system audio streams.
2. **Transcription**: Speech segments are processed by the Whisper engine, returning text fragments.
3. **Storage**: Tauri commands insert transcript rows into the `transcripts` table, linking them to the active `meeting_id` and identified `speaker_id`.
4. **Summary Generation**: Post-meeting, AI-generated summaries are written to the `summaries` table for persistent retrieval.

## Working with the Database

Developers can interact with Meetily's storage layer using the `DatabaseManager` API and `sqlx` query macros.

To insert a new meeting:

```rust
let db = DatabaseManager::new_from_app_handle(&app_handle).await?;

sqlx::query!(
    "INSERT INTO meetings (title, start_ts) VALUES (?, ?)",
    "Team Stand‑up",
    chrono::Utc::now().timestamp()
)
.execute(db.pool())
.await?;

```

To save transcript fragments during recording:

```rust
sqlx::query!(
    "INSERT INTO transcripts (meeting_id, speaker_id, text, ts) VALUES (?, ?, ?, ?)",
    meeting_id,
    speaker_id,
    "We need to finalize the budget.",
    chrono::Utc::now().timestamp()
)
.execute(db.pool())
.await?;

```

To retrieve transcripts for playback or export:

```rust
let rows = sqlx::query!(
    "SELECT text, ts FROM transcripts WHERE meeting_id = ? ORDER BY ts",
    meeting_id
)
.fetch_all(db.pool())
.await?;

```

## Summary

- Meetily uses a local SQLite database (`meeting_minutes.sqlite`) managed by the `DatabaseManager` struct in [`frontend/src-tauri/src/database/manager.rs`](https://github.com/Zackriya-Solutions/meetily/blob/main/frontend/src-tauri/src/database/manager.rs).
- The `sqlx` migration system in `frontend/src-tauri/migrations` handles schema evolution, including tables for `meetings`, `transcripts`, `speakers`, `summaries`, and `meeting_notes`.
- Connection pooling via `SqlitePool` ensures efficient concurrent access, while WAL management guarantees data durability.
- All meeting metadata, transcription segments, and AI summaries are stored locally with foreign key relationships maintaining data consistency.

## Frequently Asked Questions

### Where is the Meetily SQLite database stored?

Meetily stores the `meeting_minutes.sqlite` file in the user's application-data directory, such as `~/Library/Application Support/Meetily/` on macOS or the equivalent Windows/Linux paths. The `DatabaseManager::new_from_app_handle` function constructs this path dynamically based on the Tauri app handle.

### How does Meetily handle database schema updates?

Meetily uses `sqlx::migrate!("./migrations")` to automatically apply migration scripts from `frontend/src-tauri/migrations` on application startup. This system runs incremental SQL files—like [`20250916100000_initial_schema.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20250916100000_initial_schema.sql) for initial tables and [`20251101000000_add_summary_backup.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20251101000000_add_summary_backup.sql) for summary support—ensuring seamless schema evolution without data loss.

### What tables does Meetily use to store meeting data?

The core tables include `meetings` (session metadata), `transcripts` (speech-to-text segments), `speakers` (participant identities), `summaries` (AI-generated meeting recaps), and `meeting_notes` (user annotations). Additional tables like `settings` store API keys and configuration data added via migrations such as [`20250920155811_add_openrouter_api_key.sql`](https://github.com/Zackriya-Solutions/meetily/blob/main/20250920155811_add_openrouter_api_key.sql).

### How does Meetily ensure data integrity during writes?

The `DatabaseManager` provides a `with_transaction` helper that wraps operations in SQLite transactions, ensuring atomic commits or rollbacks. Additionally, WAL (Write-Ahead Logging) mode is used for concurrent read/write safety, and `PRAGMA wal_checkpoint(TRUNCATE)` runs on shutdown to flush pending changes and prevent corruption.