Skip to content

v0.2: Auto-fallback from localStorage to IndexedDB when size exceeds threshold #2

@mayrang

Description

@mayrang

Idea

Currently the user must explicitly choose between localStorageAdapter() (default) and indexedDBAdapter(). For users who don't know upfront how large their form data will be, this is a footgun:

  • Start with localStorage (~5MB limit, ~5MB on iOS Safari)
  • User uploads images / writes long markdown / fills out a rich-text editor
  • JSON.stringify(values).length quietly creeps over the limit
  • Suddenly: QuotaExceededError, persist fails, user loses everything on refresh

Proposed

A new adapter autoAdapter() (or option storage: 'auto') that:

  1. Defaults to localStorageAdapter()
  2. On every write, measures the serialized payload size
  3. If size exceeds threshold (e.g., 1MB by default, configurable), transparently migrates to indexedDBAdapter()
  4. Migrates existing data from localStorage to IndexedDB
  5. Continues using IndexedDB from that point on (no downgrade back to localStorage)

API sketch

```tsx
import { autoAdapter } from 'formdraft';

useFormDraft({
storage: autoAdapter({ thresholdBytes: 1_000_000 }),
// ...
});
```

Considerations

  • Migration race: what if write fires during in-flight migration?
  • Threshold tuning: 1MB safe for all browsers; some apps may want 500KB to be safer
  • iOS Safari quota varies; may need probing-based threshold detection
  • Should also handle the reverse case: if IndexedDB write fails (rare but possible), fall back to in-memory only with a warning?

Acceptance

  • New autoAdapter exported from main entry
  • Tests: write small data → localStorage used; write large data → auto migration → IndexedDB used; subsequent reads correctly come from IndexedDB
  • Documentation note in README explaining the trade-off (auto vs explicit)

Related

Discussed during v0.1.0-rc.1 documentation polish session (2026-05-27).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions