Flow Browser stores local app data in SQLite. The schema is defined in src/main/saving/db/schema.ts, generated migration SQL lives in drizzle/, and the app applies migrations automatically during database initialization from src/main/saving/db/index.ts.
Add a migration any time you change the SQLite schema in a way that existing installs need to pick up, for example:
- creating a new table
- adding, removing, or renaming columns
- adding indexes or unique constraints
- changing foreign keys or defaults
If you are only changing TypeScript types or application logic and the database shape does not change, you do not need a migration.
Make your schema change in:
src/main/saving/db/schema.ts
Keep the schema as the source of truth. Do not start by editing old SQL migration files.
From the repository root, run:
bunx drizzle-kit generate --config drizzle.config.ts --name add_history_search_indexUse a short, descriptive snake_case name. Drizzle will create the next numbered SQL file in drizzle/ and update the metadata it tracks in drizzle/meta/.
Avoid hand-written SQL migrations unless the generated SQL is demonstrably wrong for the change you need.
If you absolutely must write the SQL yourself, generate an empty migration instead:
bunx drizzle-kit generate --config drizzle.config.ts --name backfill_history_titles --customTreat --custom as an escape hatch, not the default workflow.
- Prefer updating the Drizzle schema and generating SQL from that schema.
- Custom SQL is easier to get wrong and easier for later contributors to misunderstand.
- Any custom migration should get an especially careful review before it is committed.
Check the new migration carefully before committing it.
- Make sure the SQL only does what you intended.
- Pay extra attention to column renames, default changes, and constraint changes.
- SQLite has limited
ALTER TABLEsupport, so some changes may require table recreation. Review the generated SQL instead of assuming it is safe.
Do not:
- edit or rename older migrations
- hand-edit
drizzle/meta/_journal.json - delete previously committed migrations to "clean up" history
If the generated SQL needs a small adjustment, edit the new migration file only.
Start the app in development:
bun devOn first database access, Flow Browser runs Drizzle's migrator against the drizzle/ directory automatically.
- In development, migrations are loaded from the project-root
drizzle/folder. - In packaged builds,
electron-buildercopies that folder into the app'sresources/drizzledirectory.
The local SQLite database file is stored at:
app.getPath("userData")/flow.db
Before opening a PR, verify both the schema and the runtime behavior.
- Confirm the app starts without migration errors.
- Exercise the feature that depends on the new schema.
- If the migration changes existing tables, test against an existing local database as well as a fresh one when practical.
A migration change will usually include:
- the schema update in
src/main/saving/db/schema.ts - the new
drizzle/*.sqlmigration file - any generated
drizzle/meta/*updates
Run the standard checks called out in AGENTS.md:
bun run lint
bun run typecheck
bun run formatFor a new index on history_urls.title, the flow would be:
- Add the index to
src/main/saving/db/schema.ts. - Run
bunx drizzle-kit generate --config drizzle.config.ts --name add_history_title_index. - Review the new SQL in
drizzle/. - Launch the app with
bun devand confirm the migration applies cleanly. - Commit the schema change, the migration SQL, and the generated metadata updates.