How TypeWords Uses IndexedDB for Local Data Persistence: A Technical Deep Dive
TypeWords uses the idb-keyval library with a custom versioning wrapper to store typed practice data, word lists, and user settings in IndexedDB, with automatic migration from legacy localStorage.
The open-source typing practice application TypeWords (zyronon/TypeWords) needs to reliably save user progress across sessions. Rather than using raw IndexedDB APIs directly, the project implements a clean abstraction layer that handles serialization, versioning, and backward compatibility. This article examines the actual implementation in the source code.
IndexedDB Wrapper Architecture
TypeWords builds its persistence layer on top of idb-keyval, a minimal promise-based wrapper around the browser's IndexedDB API found in the package dependencies. The core utilities live in app/core/utils/cache.ts, which exports reusable functions for reading and writing typed values.
Core Helper Functions
The foundation consists of two low-level helpers:
getLocal<T>– Retrieves and deserializes a value from IndexedDBsetLocal<T>– Serializes and stores a value as JSON (line 49 showsJSON.stringify(payload))
These wrap the underlying idb-keyval get and set methods and are imported across multiple modules including app/composables/practice-sentences/practice-sentence-cache.ts and app/core/stores/setting.ts.
Data Versioning and Metadata
Every cache definition includes a version field to prevent schema conflicts. For example, PRACTICE_WORD_CACHE.version = 2 (lines 8-11 of cache.ts). When reading cached data, the implementation checks this version and discards mismatched entries automatically.
The helper getLocalWithMeta<T> (lines 23-34) returns a structured object:
{
val: T, // The actual cached data
updated_at?: number, // Timestamp of last write
version: number // Schema version at time of write
}
This metadata enables the application to track cache freshness and trigger refreshes when data becomes stale.
Automatic Migration from localStorage
TypeWords handles legacy browser support through a transparent migration path. In app/core/utils/cache.ts (lines 226-239), the cache implementation:
- First attempts to read from IndexedDB
- Falls back to
localStorageif no entry exists - Automatically migrates any found
localStorageentry to IndexedDB - Removes the old
localStoragekey to prevent future fallbacks
This ensures users with older browsers continue working, and their data upgrades seamlessly on first access.
Domain-Specific Cache Implementations
The core wrapper powers several specialized caches for different practice modes:
Word Practice Cache (PRACTICE_WORD_CACHE)
Key: PracticeSaveWord
Stores the current word list, practice session state, and typing statistics.
import { getPracticeWordCacheLocal } from '@/app/core/utils/cache'
const cache = await getPracticeWordCacheLocal()
if (cache) {
// Access word list, practice progress, accuracy stats
}
Article Practice Cache (PRACTICE_ARTICLE_CACHE)
Key: PracticeSaveArticle
Persists reading position within articles and associated performance metrics.
Sentence Practice Cache (PRACTICE_SENTENCE_CACHE)
Key: PracticeSaveSentence
Defined in app/composables/practice-sentences/practice-sentence-cache.ts (lines 6-19), this cache maintains:
await setPracticeSentenceCacheLocal({
dictId: '123',
items: [...], // Array of sentence objects
index: 5, // Current position
wrongIds: [], // Missed sentences for review
completedIds: [], // Successfully typed sentences
mode: 'normal', // Practice mode setting
})
The implementation serializes this payload before storage (lines 44-49).
Additional IndexedDB Usage Patterns
Settings Persistence
User preferences including theme and language settings use the same IndexedDB helpers through app/core/stores/setting.ts.
Test Data Storage
The file app/core/utils/word-test.ts demonstrates simpler idb-keyval usage patterns for temporary test data.
Performance and Reliability Characteristics
The TypeWords IndexedDB implementation provides:
- Asynchronous I/O – All operations return promises, preventing UI blocking
- Automatic JSON serialization – Complex objects serialize transparently
- Schema evolution safety – Version numbers invalidate incompatible cached data
- Graceful degradation –
localStoragefallback for unsupported environments
Summary
- TypeWords uses
idb-keyvalas its IndexedDB foundation rather than native browser APIs app/core/utils/cache.tscontains the versioned wrapper with metadata support andlocalStoragemigration logic- Each practice mode (words, articles, sentences) has a dedicated cache with typed helpers
- Automatic versioning prevents stale data from corrupting application state after updates
- Transparent migration moves legacy
localStoragedata to IndexedDB without user intervention
Frequently Asked Questions
What library does TypeWords use for IndexedDB access?
TypeWords uses idb-keyval, a minimal promise-based wrapper around the IndexedDB API. This dependency appears in package.json and provides get and set methods that the project's custom cache utilities build upon.
How does TypeWords prevent data corruption when the app updates?
The cache system implements version checking. Each cache definition (like PRACTICE_WORD_CACHE) declares a version number. When reading data via getLocalWithMeta, the implementation compares the stored version against the expected version and discards mismatched entries, forcing a fresh fetch.
What happens to data stored in localStorage when IndexedDB becomes available?
TypeWords automatically migrates legacy data. On first access, if IndexedDB returns no entry but localStorage contains data, the value is copied to IndexedDB and the localStorage key is deleted. This happens transparently in lines 226-239 of cache.ts.
Where is sentence practice progress specifically saved?
Sentence practice data persists through app/composables/practice-sentences/practice-sentence-cache.ts, which exports getPracticeSentenceCacheLocal and setPracticeSentenceCacheLocal. This module uses the core IndexedDB helpers while adding domain-specific typing for sentence items, index tracking, and practice mode.
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 →