Migrating between stores
Two paths when you outgrow your current store:
- Start fresh — swap env vars and let history rebuild. Works for most teams because the detection model only cares about recent windows.
- Copy history — dump from the old store, load into the new one. Needed if you want to preserve trend analysis or avoid a two-week “warm-up” gap after the switch.
Option 1: Start fresh (recommended)
Section titled “Option 1: Start fresh (recommended)”-
Install the new store package
Terminal window npm i -D @flaky-tests/store-tursoTerminal window pnpm add -D @flaky-tests/store-tursoTerminal window yarn add -D @flaky-tests/store-turso -
Update
FLAKY_TESTS_STOREand credentialsTerminal window FLAKY_TESTS_STORE=tursoFLAKY_TESTS_CONNECTION_STRING=libsql://your-db.turso.ioFLAKY_TESTS_AUTH_TOKEN=eyJhbGci... -
Run your tests
The preload auto-calls
migrate()on the first run, creating tables in the new store. -
(Optional) Remove the old store package
Terminal window bun remove @flaky-tests/store-sqlite
Option 2: Copy history
Section titled “Option 2: Copy history”Every store implements the same IStore interface, so copying data
is a handful of reads against the old store and writes against the
new one. There’s no CLI subcommand for this yet; a one-off script is
the supported path.
import { SqliteStore } from '@flaky-tests/store-sqlite'import { TursoStore } from '@flaky-tests/store-turso'
const source = new SqliteStore({ dbPath: './node_modules/.cache/flaky-tests/failures.db' })const dest = new TursoStore({ url: process.env.FLAKY_TESTS_CONNECTION_STRING!, authToken: process.env.FLAKY_TESTS_AUTH_TOKEN,})
await dest.migrate()
// Pull the full history. `getRecentRuns` with a large limit is enough// for most projects — if you've been capturing for years, raise it.const runs = await source.getRecentRuns({ limit: 100_000 })
for (const run of runs) { await dest.insertRun({ runId: run.runId, startedAt: run.startedAt, ...(run.project !== null && { project: run.project }), ...(run.gitSha !== null && { gitSha: run.gitSha }), ...(run.gitDirty !== null && { gitDirty: run.gitDirty }), }) await dest.updateRun(run.runId, { ...(run.endedAt !== null && { endedAt: run.endedAt }), ...(run.durationMs !== null && { durationMs: run.durationMs }), ...(run.status !== null && { status: run.status }), ...(run.totalTests !== null && { totalTests: run.totalTests }), ...(run.passedTests !== null && { passedTests: run.passedTests }), ...(run.failedTests !== null && { failedTests: run.failedTests }), ...(run.errorsBetweenTests !== null && { errorsBetweenTests: run.errorsBetweenTests, }), })}
await source.close()await dest.close()console.log(`Copied ${runs.length} runs`)Choosing the destination
Section titled “Choosing the destination”See Choosing a store for the full comparison. Summary:
| Scenario | Destination |
|---|---|
| Still solo / local only | Stay on SQLite |
| Team wants shared history | Turso (free tier fits most teams) |
| Already on Supabase | Supabase |
| Already on Neon / managed Postgres | Postgres |
Common pitfalls
Section titled “Common pitfalls”Project name mismatch
Section titled “Project name mismatch”If FLAKY_TESTS_PROJECT differs between the two environments, rows
written in one won’t show up when read in the other. Export and
import with the same project name, or set FLAKY_TESTS_PROJECT="" to
write rows with a NULL project during the copy.
Duplicate run IDs
Section titled “Duplicate run IDs”insertRun on most adapters errors on duplicate run_id. If you run
the migration script twice, wrap each call in a try/catch or add a
pre-check that the run doesn’t already exist in the destination.
Remote-store write rate limits
Section titled “Remote-store write rate limits”Turso / Supabase / Neon free tiers have write-per-minute caps. For
large histories, add a small await new Promise(r => setTimeout(r, 50))
between rows, or batch with insertFailures where appropriate.
What to update after the switch
Section titled “What to update after the switch”- CI env vars — update
FLAKY_TESTS_STOREand credentials on every CI workflow. .env.example— tell teammates what to set locally.- Uninstall the old store package — keeps
node_moduleslean and prevents accidental dual-writes. - Rotate the old credentials if they’re no longer needed.