Adding offline support to an existing application always sounded like one of those features that would require rewriting half the codebase.
That was exactly why I kept postponing it.
I imagined I'd have to sprinkle if (online) checks everywhere, duplicate logic in components, keep separate offline states, and generally make the whole application much harder to maintain.
In the end... it turned out to be much simpler than I expected.
The key wasn't a particular library it was keeping the architecture clean.
The goal
I wanted a complete offline mode where users could continue working even without a network connection:
- Browse existing data
- Create, edit and delete content
- Close the application
- Come back later Automatically synchronize everything once they're back online
Most importantly, I didn't want my Vue components to know whether they were online or offline.
The architecture
I decided that components should never care where the data comes from.
Instead, everything goes through the stores.
The component simply calls:
await nodesStore.create(node)
Whether that operation goes to the server immediately or is stored locally for later synchronization is entirely the store's responsibility. The API never changes.
Reading data
For reads, I relied on PWA + Workbox.
Requests are intercepted transparently and served from the cache whenever appropriate. When the application starts, previously synchronized data is loaded into the store's cache.
From the store's perspective, nothing changes: it still fetches data exactly as before. If a piece of data isn't available locally, it simply can't be accessed offline.
The components don't know whether the response came from the network or from Workbox. And with this approach we don't have to manage a full cache, the biggest part is handled by workbox, we just manually store content created or updated offline.
Nothing changed in the UI.
Writing data
CRUD operations are handled a little differently.
When online, the store behaves normally.
When offline, instead of calling the API, it stores the operation inside a small local database (IndexedDB, using localForage library) and immediately updates the local state.
Component
│
▼
Store.create()
│
Online?
├── Yes → API
└── No → Queue operation in IndexedDB
Later, when the connection comes back, the queued operations are replayed automatically in the background in the same order.
From the component's perspective, nothing changed.
The biggest benefit
The offline mode itself is nice.
But the real win is that almost none of my components had to change.
The entire application still interacts with the stores exactly the same way.
The complexity stays in one place instead of leaking into every page and every component.
Lessons learned
A few things surprised me while implementing this:
- It was much simpler than I expected
- I had postponed the feature for months because I thought every component would need special offline logic.
- In reality, combining PWA + Workbox for reads with a small local database and adapting the stores was enough.
- Keeping components completely unaware of the network state makes the application much easier to maintain.
- Good architecture often saves far more time than clever code.
Offline support ended up being one of the features I feared the most, but also one of the cleanest to implement once the architecture was in place.
The complete implementation is part of Alexandrie, an open-source knowledge base built with Nuxt and Go. If you're curious about the full architecture or the implementation details, you can find the project here:

Top comments (0)