DEV Community

Muhammad Shoaib
Muhammad Shoaib

Posted on

Offline-first web apps with localStorage: a journal, planner and grocery list that never upload your data

Most "simple" productivity apps want an account before you can write one line. I wanted the opposite: open a page, start typing, close the tab, and find everything still there tomorrow, without a server ever seeing it.

Here's the small pattern I used for a set of free browser apps on Toolverse.

1. Save on every change, debounced

let t;
function save(state){
  clearTimeout(t);
  t = setTimeout(() => localStorage.setItem('journal-v1', JSON.stringify(state)), 400);
}
Enter fullscreen mode Exit fullscreen mode

A 400 ms debounce keeps typing smooth and still feels instant.

2. Version your key

Using journal-v1 instead of journal means you can migrate the shape later without breaking old saves.

3. Load defensively

function load(){
  try { return JSON.parse(localStorage.getItem('journal-v1')) || {entries: []}; }
  catch { return {entries: []}; }
}
Enter fullscreen mode Exit fullscreen mode

Corrupted or hand-edited storage should never crash the app.

4. Give people an export button

localStorage is per-browser. A one-click JSON export (a Blob plus a download link) lets people back up or move their data, which matters more than any sync feature.

5. For secrets, encrypt first

For the password manager I used the Web Crypto API (PBKDF2 to derive a key, AES-GCM to encrypt), so only ciphertext ever touches storage.

Try them

Open one, add something, reload, and it's still there. Feedback on the pattern is welcome.

Top comments (0)