Part 5 of 7 · Persistence

Save your reading list.

Make the list survive a refresh, find out what saving in the browser can and can’t do, then add search and filters.

By Ahmed Gadir6 min read

At the end of Part 4 your app could add, edit and remove books, and forgot them all on refresh. This part fixes that, then completes the features in the brief.

Temporary and saved data

While a page is open, an app keeps its working information in memory. Developers call this state: the current list, whether the form is open, what is typed in the search box. State is fast and temporary. Refreshing the page throws it away and starts again, which is what you saw.

Most state should be temporary. Nobody wants a half-typed search restored next week. The list of books is different, so the app needs to copy it somewhere lasting whenever it changes and read it back when the page opens. That lasting copy is what persistence means.

What happens to the list when the page refreshesYou add a book and the list in memory changes. Without saving, a refresh starts again with an empty list. With localStorage, each change is also written to the browser's storage, and a refresh reads the list back.You add a bookThe list in memorychanges.The app savesIt writes the list tolocalStorage.You refreshMemory is cleared.Storage is kept.The app loadsIt reads the savedlist back.
A refresh clears the page’s memory but not the browser’s storage, so an app that saves each change can read the list back.

As Part 3 explained, this app’s lasting place is localStorage: a storage area the browser provides to each website address. It keeps the list on this device, in this browser, for this address. It does not copy it to your other devices and it is not a backup.

1. Save the list in the browser

Stage C: save the list

Read CLAUDE.md, docs/brief.md, docs/flows.md and docs/epics/03-build.md. Stages A and B are working. Build Stage C only. Before changing anything, explain in two or three sentences how you will save the list and when. Then save the list to localStorage after every change and restore it when the page opens. Keep the saving and loading logic in a small separate file so they can be tested without a browser. If saving fails, tell me on screen; never pretend it worked. If saved data cannot be read, tell me and do not overwrite it. Add a "Try example books" option that loads samples only when I choose it; a new visitor starts with an empty list. Do not add search or filters yet. When you finish, stop, tell me what to try and wait.

Paste this into your project conversation.

This prompt asks the agent to explain its approach before acting. For a change you can’t see directly, a short explanation lets you catch a misunderstanding before it is built. You might read, for example, that it plans to save only when a button is pressed, when you wanted every change saved automatically.

Then check it, using the same URL as before:

  • Add a book, edit its note and change its status. Refresh. Everything should still be there.
  • Remove a book, undo, and refresh. The restored book should remain.
  • Close the browser tab, open the URL again, and look once more.

You can also check the limits you learned about. Open the same URL in a private window, or in a different browser: the list is empty there, because each browser profile has its own storage. That is the expected behaviour of this architecture.

2. When saving goes wrong

The prompt included two requirements that are easy to skip: report a failed save, and never overwrite saved data that can’t be read. They matter because of what the alternative looks like to the person using the app.

Browser storage can fail. It can be full, or blocked by a privacy setting. An app that ignores the failure shows the new book on screen as though all is well, and the book silently vanishes at the next refresh. An app that reports it lets the person do something about it, even if that only means copying their note elsewhere.

Saved data can also become unreadable, for instance if a future version of the app changes the format. A careless app responds by starting a fresh empty list and saving over the old one, destroying data that might have been recoverable. A careful one leaves it alone and says so.

These cases are awkward to trigger by hand, so don’t try to break your own browser’s storage. Ask the agent how it handled each one, and in Part 6 you’ll see automated tests produce both failures safely in a separate test browser. The general habit is worth keeping: when you ask an agent for something that saves, sends or deletes information, also say what should happen when that fails.

3. Find books and finish the details

Stage D: search, filters and details

Read CLAUDE.md, docs/brief.md, docs/flows.md and docs/epics/03-build.md. Stages A to C are working. Build Stage D only. Add search by title or author, and a filter for All books, Want to read, Reading and Finished. They must work together: searching within a chosen status shows only books that match both. Show a clear message when nothing matches. Give Pip a small reaction when clicked or when I finish a book, and respect the reduced-motion setting. Check phone and desktop widths for sideways scrolling and buttons I cannot reach. Run the production build and tell me about any errors. When you finish, stop, tell me what to try and wait.

Paste this into your project conversation.

Load the example books so there is something to search, then check:

  • Search for part of an author’s name in capitals. Matching should ignore capital letters.
  • Choose Finished, then search for a book you know is still marked Reading. You should see the “nothing found” message, because the book fails one of the two conditions.
  • Clear the search and choose All books. Everything returns.
  • Narrow the browser window to roughly phone width. Nothing should need sideways scrolling.
The finished reading list at phone width, with Pip, the search field, status filters and book cards stacked in one column.
Our finished example at phone width.

The combined search and filter is a good example of a rule that seems obvious until you state it. “Filter by status” and “search by title” each sound complete on their own; the question of what happens when both are active only appears when you write it down or try it. The prompt states it, so the agent doesn’t have to guess.

4. Save a checkpoint

Ask the agent to inspect the changes and save a Git commit called Save the list and add search. Every feature in the brief now exists. What you don’t yet have is evidence that they keep working as the project changes, and the next part provides it.

FAQ

Why is my list empty at a different localhost address?

Storage belongs to a website’s origin: the combination of scheme, hostname and port, such as http://127.0.0.1:5173. If the development server restarts on a different port, the browser treats it as a different site with its own empty storage. Your earlier list is still saved under the old address.

How much can localStorage hold?

Browsers typically allow around five megabytes per site, which is room for many thousands of books with notes. It holds text only, which is one reason this app has no cover images.

Next: Test your reading list.