You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I checked the existing issues for duplicate feature requests
What parts of Modrinth is your feature request related too?
Modrinth.com website
Is your suggested feature related to a problem? Please describe.
Imagine you're browsing modrinth.com, your connection drops, you hit reload — and the page is gone. Not a cached copy, not a friendly message, just the browser's error page. Everything you were looking at five minutes ago might as well have never loaded.
That's the current reality — the site has no offline story at all:
No offline state. A dropped connection means a dead stop, even for pages the user just visited. No cached shell, no images, nothing.
No feedback. The user is never told they're offline; every interaction simply fails.
Expensive repeat visits. On slow, metered, or flaky mobile connections, every reload re-fetches the shell and each project icon from scratch — a long blank screen for assets the browser downloaded minutes ago and may have already evicted from its HTTP cache.
The root cause: modrinth.com ships no Service Worker, so the only caching in play is the standard HTTP/CDN cache which does not survive connectivity loss and offers no control over what the offline experience looks like.
Describe the solution you'd like
Add a Workbox-based Service Worker to the website frontend (apps/frontend, Nuxt 3), making modrinth.com offline-first: fully browsable read-only from cache for anything previously visited, with a clear offline indicator and graceful handling of anything that needs a connection.
How a request flows through the Service Worker:
flowchart TD
req["SW intercepts request"] --> auth{"Authenticated or<br/>a mutation?"}
auth -- "Yes" --> netonly["Network only;<br/>friendly offline error when offline"]
auth -- "No" --> type{"Resource type"}
type -- "Immutable shell" --> precache["Cache First<br/>(precache manifest)"]
type -- "HTML navigations &<br/>CDN images" --> swr["Stale While Revalidate"]
type -- "Search & public API GETs" --> online{"User online?"}
online -- "Yes" --> nf["Network First,<br/>cache as fallback"]
online -- "No" --> stale["Serve cached entry,<br/>regardless of age"]
Truly immutable — invalidated automatically whenever the Service Worker version changes
Pages
HTML navigations (homepage, project pages)
Stale While Revalidate
Instant loads from cache, quietly freshened in the background so content never goes stale
Images
cdn.modrinth.com icons & galleries
Stale While Revalidate + entry cap
Instant display, self-correcting if an author replaces a project icon, and bounded storage
Data
Search queries & public, unauthenticated API GETs
Network First + offline-aware expiry
Fresh whenever online; served from cache whenever offline
2. Offline-aware expiry
Search and API responses are stored with a timestamp, and expiry behaves differently depending on connectivity:
While online — an expired entry means "go to the network first, keep the cache as fallback", and the cached copy is refreshed on success.
While offline — an expired entry is served anyway. Being offline should never make cached data less available.
Note
Nothing is ever deleted purely because of age. Entries are evicted only by LRU / quota pressure, so an offline user keeps everything they've already seen.
3. A non-blocking offline banner
When the connection drops or requests simply start failing, since navigator.onLine famously lies,a slim bar appears above the page content: "You're offline — showing cached content."
It never blocks or overlays the page; the site stays fully interactive.
It dismisses itself the moment the connection returns.
4. Read-only, not locked-down
Offline, the user keeps browsing everything cached. Mutations (settings changes, uploads, follows, …) are network-only and fail with a friendly inline "you're offline , this needs a connection" message rather than greying out half the UI to achieve the same thing.
Caution
Authenticated pages (dashboard, settings, notifications) are never served from cache. Offline, they show the /offline page — never a stale authenticated view. Nothing carrying an Authorization header or Set-Cookie is ever stored.
5. Update lifecycle
Warning
An old cached shell references hashed chunks that no longer exist after a deploy — the user gets a white screen. This plan is built to avoid exactly that.
The precache manifest is tied to the build, so a new deploy means a new manifest.
Old caches are deleted on activation.
A newly installed Service Worker waits and shows an "update available — refresh" prompt instead of auto-activating mid-session.
Describe alternatives you've considered
Rely on existing HTTP/CDN caching only
Helps repeat-visit latency, but provides nothing during connectivity loss and offers no offline UX
Cached search & API results, regardless of their age
Search for new queries
Browsing, reading, navigating
Uploads and all other mutations
Important
Safety rules, in one place:
Only GET requests returning 200 are ever cached.
Nothing carrying an Authorization header or Set-Cookie is stored — authenticated API traffic is strictly network-only.
Runtime caches are entry-capped and evicted by LRU / quota pressure, never by time alone.
Large file downloads stay on normal browser/CDN caching — they never enter Service Worker storage.
Explicit non-goals (click to expand)
Indiscriminate caching of authenticated or user-specific responses.
Caching mutation requests.
Storing large downloads in Service Worker storage.
Replacing existing browser/CDN caching.
Tip
The exact routes, Workbox config, and cache sizes can be settled during implementation against the real apps/frontend architecture — the table above is the contract, not the final config.
Enable Navigation preload,as latest content are going to fetch from network.
Please confirm the following.
What parts of Modrinth is your feature request related too?
Modrinth.com website
Is your suggested feature related to a problem? Please describe.
Imagine you're browsing modrinth.com, your connection drops, you hit reload — and the page is gone. Not a cached copy, not a friendly message, just the browser's error page. Everything you were looking at five minutes ago might as well have never loaded.
That's the current reality — the site has no offline story at all:
The root cause: modrinth.com ships no Service Worker, so the only caching in play is the standard HTTP/CDN cache which does not survive connectivity loss and offers no control over what the offline experience looks like.
Describe the solution you'd like
Add a Workbox-based Service Worker to the website frontend (
apps/frontend, Nuxt 3), making modrinth.com offline-first: fully browsable read-only from cache for anything previously visited, with a clear offline indicator and graceful handling of anything that needs a connection.How a request flows through the Service Worker:
flowchart TD req["SW intercepts request"] --> auth{"Authenticated or<br/>a mutation?"} auth -- "Yes" --> netonly["Network only;<br/>friendly offline error when offline"] auth -- "No" --> type{"Resource type"} type -- "Immutable shell" --> precache["Cache First<br/>(precache manifest)"] type -- "HTML navigations &<br/>CDN images" --> swr["Stale While Revalidate"] type -- "Search & public API GETs" --> online{"User online?"} online -- "Yes" --> nf["Network First,<br/>cache as fallback"] online -- "No" --> stale["Serve cached entry,<br/>regardless of age"]1. Caching tiers
/offlineroutecdn.modrinth.comicons & galleriesGETs2. Offline-aware expiry
Search and API responses are stored with a timestamp, and expiry behaves differently depending on connectivity:
Note
Nothing is ever deleted purely because of age. Entries are evicted only by LRU / quota pressure, so an offline user keeps everything they've already seen.
3. A non-blocking offline banner
When the connection drops or requests simply start failing, since
navigator.onLinefamously lies,a slim bar appears above the page content: "You're offline — showing cached content."4. Read-only, not locked-down
Offline, the user keeps browsing everything cached. Mutations (settings changes, uploads, follows, …) are network-only and fail with a friendly inline "you're offline , this needs a connection" message rather than greying out half the UI to achieve the same thing.
Caution
Authenticated pages (dashboard, settings, notifications) are never served from cache. Offline, they show the
/offlinepage — never a stale authenticated view. Nothing carrying anAuthorizationheader orSet-Cookieis ever stored.5. Update lifecycle
Warning
An old cached shell references hashed chunks that no longer exist after a deploy — the user gets a white screen. This plan is built to avoid exactly that.
Describe alternatives you've considered
Additional context
What works offline, and what doesn't:
Important
Safety rules, in one place:
GETrequests returning200are ever cached.Authorizationheader orSet-Cookieis stored — authenticated API traffic is strictly network-only.Explicit non-goals (click to expand)
Tip
apps/frontendarchitecture — the table above is the contract, not the final config.