How Read Frog Database Migration Scripts Handle Schema Evolution and Version Updates
Read Frog’s database migration scripts form an automated, versioned pipeline that transforms persisted user configurations from legacy schemas to the current version, ensuring data survives extension updates without manual intervention.
Read Frog is a browser extension that persists user preferences in the browser's extension storage. As the codebase evolves, configuration schemas change—fields are added, renamed, or restructured. The Read Frog database migration scripts, implemented in src/utils/config/migration.ts, automatically bridge these schema gaps by sequentially applying version-specific transformation functions, preventing data loss while maintaining backward compatibility.
Migration Pipeline Architecture
The migration workflow orchestrates upgrades through a deterministic, step-wise process defined in src/utils/config/migration.ts. When the extension initializes, it retrieves the stored configuration and initiates the migration sequence.
Version Detection and Comparison
The system first extracts the stored schema version from the originalConfigSchemaVersion property. It compares this value against CONFIG_SCHEMA_VERSION (currently set to 58 in src/utils/constants/config.ts).
If the stored version exceeds the current supported version, the pipeline throws a ConfigVersionTooNewError, forcing the user to update the extension rather than risk data corruption.
Sequential Migration Execution
For outdated configurations, the code enters a controlled loop that increments the version number one step at a time:
- Calculates the next target version (
currentVersion + 1) - Retrieves the corresponding function from the static
migrationScriptsmap - Executes
runMigration(nextVersion, config)to apply the transformation - Replaces the configuration object with the migrated result
- Repeats until reaching
CONFIG_SCHEMA_VERSION
This approach ensures each intermediate schema transition occurs explicitly, making debugging straightforward and state changes predictable.
Schema Validation
After completing the migration chain, the final configuration object undergoes validation via configSchema.safeParse. This Zod validation step catches malformed data or failed transformations before the extension attempts to use the configuration.
Migration Script Structure
Individual migration scripts reside in src/utils/config/migration-scripts/ and export pure functions following the signature (oldConfig: any) => any.
Incremental Transformation Functions
Each script handles exactly one version bump. For example, a migration from version 1 to 2 might add default values for new fields:
import { deepmerge } from 'deepmerge-ts'
export function migrate(oldConfig: any): any {
// Adds a default page translation range that did not exist in v001
return deepmerge(oldConfig, {
pageTranslate: { range: 'mainContent' },
})
}
Static Import Map
Because the extension runs as an ES-module Service Worker, migration functions are statically imported and registered in a Record<number, MigrationFunction> map within migration.ts:
export const migrationScripts: Record<number, MigrationFunction> = {
2: migrateV001ToV002,
3: migrateV002ToV003,
// … continues up to version 58
}
Practical Implementation Example
To load and migrate configuration in the extension context:
import { migrateConfig } from '@/utils/config/migration'
import { CONFIG_STORAGE_KEY } from '@/utils/constants/config'
async function loadConfig() {
const raw = await chrome.storage.sync.get(CONFIG_STORAGE_KEY)
const storedConfig = raw[CONFIG_STORAGE_KEY] ?? {}
const storedVersion = storedConfig.schemaVersion ?? 1 // fallback for legacy installs
// Automatically migrates to schema version 58
const config = await migrateConfig(storedConfig, storedVersion)
return config
}
Testing Strategy
Read Frog maintains rigorous test coverage for migrations. The src/utils/config/__tests__/migration.test.ts file verifies that newer-than-current versions trigger the appropriate error, while src/utils/config/__tests__/migration-scripts/all-migrations.test.ts executes every migration script in sequence to ensure deterministic upgrades across the entire version chain.
Summary
- Read Frog database migration scripts reside in
src/utils/config/migration.tsand provide automated schema evolution for browser extension storage. - The system compares stored versions against
CONFIG_SCHEMA_VERSION(currently 58) and rejects incompatible future versions withConfigVersionTooNewError. - Migration functions are chained sequentially in the
migrationScriptsmap, with each handling exactly one version increment. - Final Zod validation via
configSchema.safeParseensures data integrity after transformations complete. - Individual scripts live in
src/utils/config/migration-scripts/and follow a simple(oldConfig: any) => anysignature.
Frequently Asked Questions
What happens if a user has a newer config version than the installed extension supports?
The migration pipeline throws a ConfigVersionTooNewError when originalConfigSchemaVersion exceeds CONFIG_SCHEMA_VERSION. This prevents data corruption by forcing users to update their extension to a version capable of understanding the newer schema.
How are migration scripts organized in the Read Frog codebase?
Individual scripts are stored in src/utils/config/migration-scripts/ as separate TypeScript files. The orchestrator in src/utils/config/migration.ts imports these into a static migrationScripts map keyed by target version numbers, which ensures sequential execution from the stored version up to the current schema version.
Why does Read Frog use Zod validation after running migrations?
The final configSchema.safeParse call serves as a safety net that catches malformed configurations or migration failures. This validation ensures only type-safe, schema-compliant data reaches the extension's runtime, preventing runtime errors caused by incomplete or buggy transformations.
Can migration scripts be tested individually?
Yes. The codebase includes __tests__/migration-scripts/all-migrations.test.ts, which runs every migration function in sequence to verify deterministic upgrades across the entire version history. Additionally, migration.test.ts validates error handling for version mismatches, ensuring the pipeline behaves correctly under edge cases.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →