Skip to content

Commit 3867a97

Browse files
committed
offline navigations: add docs and examples (10/10)
1 parent be4811d commit 3867a97

4 files changed

Lines changed: 384 additions & 1 deletion

File tree

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
---
2+
title: Offline navigations
3+
description: Learn how to enable offline hard reloads and navigation recovery with Cache Components.
4+
nav_title: Offline navigations
5+
version: experimental
6+
related:
7+
title: API Reference
8+
description: Learn more about the APIs used in this guide.
9+
links:
10+
- app/api-reference/config/next-config-js/offlineNavigations
11+
- app/api-reference/functions/use-offline
12+
- app/api-reference/config/next-config-js/cacheComponents
13+
---
14+
15+
Offline navigations help an App Router app keep working when a user reloads or opens a same-origin route while their browser is offline.
16+
17+
When a route has browser-private navigation data and the current-build assets it needs, Next.js can restore that route instead of showing the browser's network error page. If the browser does not have everything it needs for the route, the app shows a clear offline miss.
18+
19+
Use offline navigations for read-only route recovery. It does not make every route available offline, sync mutations, or replace a custom Progressive Web App strategy.
20+
21+
## Enable offline navigations
22+
23+
Offline navigations require [Cache Components](/docs/app/api-reference/config/next-config-js/cacheComponents):
24+
25+
```ts filename="next.config.ts" highlight={4,6}
26+
import type { NextConfig } from 'next'
27+
28+
const nextConfig: NextConfig = {
29+
cacheComponents: true,
30+
experimental: {
31+
offlineNavigations: true,
32+
},
33+
}
34+
35+
export default nextConfig
36+
```
37+
38+
```js filename="next.config.js" highlight={3,5}
39+
/** @type {import('next').NextConfig} */
40+
const nextConfig = {
41+
cacheComponents: true,
42+
experimental: {
43+
offlineNavigations: true,
44+
},
45+
}
46+
47+
module.exports = nextConfig
48+
```
49+
50+
You do not need to add your own service worker to enable this behavior. `offlineNavigations` configures the required router features automatically.
51+
52+
## Show offline state
53+
54+
Use [`useOffline`](/docs/app/api-reference/functions/use-offline) from `next/offline` to show whether the app is currently offline:
55+
56+
```tsx filename="app/offline-status.tsx" switcher
57+
'use client'
58+
59+
import { useOffline } from 'next/offline'
60+
61+
export function OfflineStatus() {
62+
const isOffline = useOffline()
63+
return <p>{isOffline ? 'Offline' : 'Online'}</p>
64+
}
65+
```
66+
67+
```jsx filename="app/offline-status.js" switcher
68+
'use client'
69+
70+
import { useOffline } from 'next/offline'
71+
72+
export function OfflineStatus() {
73+
const isOffline = useOffline()
74+
return <p>{isOffline ? 'Offline' : 'Online'}</p>
75+
}
76+
```
77+
78+
Render the indicator from a shared layout so it is visible after a hard reload:
79+
80+
```tsx filename="app/layout.tsx" switcher
81+
import { OfflineStatus } from './offline-status'
82+
83+
export default function RootLayout({
84+
children,
85+
}: {
86+
children: React.ReactNode
87+
}) {
88+
return (
89+
<html lang="en">
90+
<body>
91+
<OfflineStatus />
92+
{children}
93+
</body>
94+
</html>
95+
)
96+
}
97+
```
98+
99+
```jsx filename="app/layout.js" switcher
100+
import { OfflineStatus } from './offline-status'
101+
102+
export default function RootLayout({ children }) {
103+
return (
104+
<html lang="en">
105+
<body>
106+
<OfflineStatus />
107+
{children}
108+
</body>
109+
</html>
110+
)
111+
}
112+
```
113+
114+
## Make routes available offline
115+
116+
Offline navigations work for routes the current browser has enough data and assets to render. The most reliable way to make an important route available later is to load it or let Next.js prefetch it before the user needs it offline.
117+
118+
Visible `<Link>` components prefetch automatically in production. Use [`router.prefetch`](/docs/app/api-reference/functions/use-router#userouter) when you want to explicitly prepare a route, such as a dashboard or report the user is likely to open offline:
119+
120+
```tsx filename="app/prefetch-report-button.tsx" switcher
121+
'use client'
122+
123+
import { useRouter } from 'next/navigation'
124+
125+
export function PrefetchReportButton() {
126+
const router = useRouter()
127+
128+
return (
129+
<button onClick={() => router.prefetch('/reports/weekly')}>
130+
Make weekly report available offline
131+
</button>
132+
)
133+
}
134+
```
135+
136+
```jsx filename="app/prefetch-report-button.js" switcher
137+
'use client'
138+
139+
import { useRouter } from 'next/navigation'
140+
141+
export function PrefetchReportButton() {
142+
const router = useRouter()
143+
144+
return (
145+
<button onClick={() => router.prefetch('/reports/weekly')}>
146+
Make weekly report available offline
147+
</button>
148+
)
149+
}
150+
```
151+
152+
If the route has everything it needs, a hard reload or document navigation can render it while offline. If route data is missing, the app shows an offline miss state instead of guessing or rendering partial UI.
153+
154+
## What to expect
155+
156+
Offline navigations are browser-private and same-origin:
157+
158+
- A route can be restored only in the browser profile where it was loaded or prefetched.
159+
- Dynamic routes can be restored after the browser has learned and cached the matching route.
160+
- A route can miss offline if it was never loaded, was not fully prefetched, or was invalidated.
161+
- Next.js caches the fallback document and its bootstrap assets. Current-build JavaScript and CSS chunks can also be reused offline after the app loads or prefetches them online.
162+
- If the current build's cached assets or navigation data are cleared, evicted, or from another deployment, the route cannot boot offline.
163+
- Browser storage can be cleared by users, browser settings, storage pressure, or DevTools. If storage is cleared, offline recovery may not start.
164+
- Mutations, Server Actions, Route Handlers, and POST requests still require the network.
165+
166+
Offline navigations do not cache arbitrary `fetch` responses, custom static assets, cookies, local storage, or your app's own data stores. If your app stores data separately, continue to manage that storage yourself.
167+
168+
## Keep offline data fresh
169+
170+
Offline navigations follow normal App Router cache invalidation. Use the same APIs you already use to refresh client and server data:
171+
172+
- [`router.refresh()`](/docs/app/api-reference/functions/use-router#userouter) refreshes dynamic route data and invalidates offline navigation data for the affected route.
173+
- [`refresh()`](/docs/app/api-reference/functions/refresh) refreshes client router data from a Server Action.
174+
- [`updateTag()`](/docs/app/api-reference/functions/updateTag) and [`revalidatePath()`](/docs/app/api-reference/functions/revalidatePath) invalidate server data and any offline navigation data that depends on it.
175+
- Mutating cookies in a Server Action invalidates the client router cache, including offline navigation data.
176+
177+
For sign out, account switches, workspace switches, or client-only auth changes, use the same refresh or revalidation API you would use for the online app. Offline navigations mirror those invalidations instead of exposing a separate offline-specific reset API.
178+
179+
## Test offline navigations
180+
181+
Offline navigations do not run in `next dev`. Test with a production build:
182+
183+
```bash
184+
next build
185+
next start
186+
```
187+
188+
Then in a browser:
189+
190+
1. Visit the route online.
191+
2. Prefetch or navigate to any routes you expect to restore offline.
192+
3. Open DevTools and switch the network to **Offline**.
193+
4. Reload the route or open a cached route URL.
194+
195+
If the route has valid offline navigation data, it renders and [`useOffline`](/docs/app/api-reference/functions/use-offline) returns `true`. If required data is missing, the app shows an offline miss state.
196+
197+
> **Good to know**:
198+
>
199+
> - `localhost` is treated as a secure context, so service worker registration works with `next start` locally.
200+
> - Static export integration is not included in this experimental API.
201+
> - For push notifications, background sync, offline mutations, or custom asset caching, use a custom PWA strategy.

docs/01-app/02-guides/progressive-web-apps.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,6 @@ Learn more about defining [Content Security Policies](/docs/app/guides/content-s
665665
666666
1. **Exploring PWA Capabilities**: PWAs can leverage various web APIs to provide advanced functionality. Consider exploring features like background sync, periodic background sync, or the File System Access API to enhance your application. For inspiration and up-to-date information on PWA capabilities, you can refer to resources like [What PWA Can Do Today](https://whatpwacando.today/).
667667
2. **Static Exports:** If your application requires not running a server, and instead using a static export of files, you can update the Next.js configuration to enable this change. Learn more in the [Next.js Static Export documentation](/docs/app/guides/static-exports). However, you will need to move from Server Actions to calling an external API, as well as moving your defined headers to your proxy.
668-
3. **Offline Support**: To provide offline functionality, one option is [Serwist](https://github.com/serwist/serwist) with Next.js. You can find an example of how to integrate Serwist with Next.js in their [documentation](https://github.com/serwist/serwist/tree/main/examples/next-basic). **Note:** this plugin currently requires webpack configuration.
668+
3. **Offline Support**: To restore previously loaded or prefetched App Router routes during a network outage, use [offline navigations](/docs/app/guides/offline-navigations). For broader PWA behavior, such as custom service worker strategies, one option is [Serwist](https://github.com/serwist/serwist) with Next.js. You can find an example of how to integrate Serwist with Next.js in their [documentation](https://github.com/serwist/serwist/tree/main/examples/next-basic). **Note:** this plugin currently requires webpack configuration.
669669
4. **Security Considerations**: Ensure that your service worker is properly secured. This includes using HTTPS, validating the source of push messages, and implementing proper error handling.
670670
5. **User Experience**: Consider implementing progressive enhancement techniques to ensure your app works well even when certain PWA features are not supported by the user's browser.
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
---
2+
title: useOffline
3+
description: API Reference for the useOffline hook.
4+
version: experimental
5+
related:
6+
title: Next Steps
7+
description: Learn more about offline navigations.
8+
links:
9+
- app/guides/offline-navigations
10+
- app/api-reference/config/next-config-js/offlineNavigations
11+
---
12+
13+
`useOffline` returns whether the app is currently offline from a Client Component.
14+
15+
```tsx filename="app/offline-status.tsx" switcher highlight={4,7}
16+
'use client'
17+
18+
import { useOffline } from 'next/offline'
19+
20+
export function OfflineStatus() {
21+
const isOffline = useOffline()
22+
return <p>{isOffline ? 'Offline' : 'Online'}</p>
23+
}
24+
```
25+
26+
```jsx filename="app/offline-status.js" switcher highlight={4,7}
27+
'use client'
28+
29+
import { useOffline } from 'next/offline'
30+
31+
export function OfflineStatus() {
32+
const isOffline = useOffline()
33+
return <p>{isOffline ? 'Offline' : 'Online'}</p>
34+
}
35+
```
36+
37+
## Parameters
38+
39+
```tsx
40+
const isOffline = useOffline()
41+
```
42+
43+
`useOffline` does not take any parameters.
44+
45+
## Returns
46+
47+
`useOffline` returns a boolean:
48+
49+
| Value | Description |
50+
| ------- | ------------------------------------------------------------------ |
51+
| `true` | The browser is offline, or the current route was restored offline. |
52+
| `false` | The browser is online, or the app is rendering on the server. |
53+
54+
## Usage
55+
56+
`useOffline` must be used in a Client Component. It is enabled automatically when [`offlineNavigations`](/docs/app/api-reference/config/next-config-js/offlineNavigations) is enabled.
57+
58+
Use it to show a persistent offline indicator or adjust client-only interactions:
59+
60+
```tsx filename="app/layout.tsx" switcher
61+
import { OfflineStatus } from './offline-status'
62+
63+
export default function RootLayout({
64+
children,
65+
}: {
66+
children: React.ReactNode
67+
}) {
68+
return (
69+
<html lang="en">
70+
<body>
71+
<OfflineStatus />
72+
{children}
73+
</body>
74+
</html>
75+
)
76+
}
77+
```
78+
79+
```jsx filename="app/layout.js" switcher
80+
import { OfflineStatus } from './offline-status'
81+
82+
export default function RootLayout({ children }) {
83+
return (
84+
<html lang="en">
85+
<body>
86+
<OfflineStatus />
87+
{children}
88+
</body>
89+
</html>
90+
)
91+
}
92+
```
93+
94+
> **Good to know**:
95+
>
96+
> - `useOffline` returns `false` during server rendering and hydration.
97+
> - `useOffline` is not a network quality signal. It reports browser offline state and offline navigation recovery state.
98+
> - When `offlineNavigations` restores a route, `useOffline` reports `true` after the client boots.
99+
100+
## Version History
101+
102+
| Version | Changes |
103+
| --------- | ----------------------- |
104+
| `v16.3.0` | `useOffline` was added. |
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
---
2+
title: offlineNavigations
3+
description: Enable offline hard reloads and navigation recovery for Cache Components apps.
4+
version: experimental
5+
related:
6+
title: Next Steps
7+
description: Learn how to build and observe offline navigations.
8+
links:
9+
- app/guides/offline-navigations
10+
- app/api-reference/functions/use-offline
11+
- app/api-reference/config/next-config-js/cacheComponents
12+
---
13+
14+
`offlineNavigations` lets an App Router app recover routes with cached navigation data and current-build assets when a same-origin document navigation fails because the browser is offline.
15+
16+
```ts filename="next.config.ts" highlight={6}
17+
import type { NextConfig } from 'next'
18+
19+
const nextConfig: NextConfig = {
20+
cacheComponents: true,
21+
experimental: {
22+
offlineNavigations: true,
23+
},
24+
}
25+
26+
export default nextConfig
27+
```
28+
29+
```js filename="next.config.js" highlight={5}
30+
/** @type {import('next').NextConfig} */
31+
const nextConfig = {
32+
cacheComponents: true,
33+
experimental: {
34+
offlineNavigations: true,
35+
},
36+
}
37+
38+
module.exports = nextConfig
39+
```
40+
41+
## Reference
42+
43+
| Option | Type | Default | Description |
44+
| -------------------- | --------- | ------- | --------------------------------------------------------------------------- |
45+
| `offlineNavigations` | `boolean` | `false` | Enables offline recovery for App Router routes with cached navigation data. |
46+
47+
## Requirements
48+
49+
`offlineNavigations` requires [`cacheComponents`](/docs/app/api-reference/config/next-config-js/cacheComponents) to be enabled.
50+
51+
When `offlineNavigations` is enabled, Next.js also configures the router features required to restore prefetched routes. You do not need to enable them separately.
52+
53+
Use [`useOffline`](/docs/app/api-reference/functions/use-offline) from `next/offline` to show whether the app is currently offline.
54+
55+
## Behavior
56+
57+
In production, Next.js registers a managed service worker for offline navigation recovery. It is used only for same-origin document navigations.
58+
59+
When a user reloads or opens a route while offline:
60+
61+
- If the browser has valid navigation data and the current-build assets needed for the route, the route renders.
62+
- If the app can boot but the route data is missing or invalidated, the app shows an offline miss.
63+
- If the fallback cannot start, or the current build's managed assets are cleared, evicted, or from another deployment, the route cannot boot offline.
64+
- If the browser is online, normal App Router navigation behavior is unchanged.
65+
66+
> **Good to know**:
67+
>
68+
> - `next dev` does not register the managed service worker. Test offline navigations with `next build` and `next start`.
69+
> - `offlineNavigations` does not cache arbitrary `fetch` responses, Server Actions, POST requests, app-owned storage, or custom static assets.
70+
> - Next.js caches the fallback document and its bootstrap assets. Current-build JavaScript and CSS chunks can also be reused offline after the app loads or prefetches them online.
71+
> - Offline recovery is browser-private and same-origin, similar to persistent browser cache. Use the normal router refresh and cache revalidation APIs when server-visible state changes.
72+
> - Static export integration is not included in this experimental API.
73+
74+
## Version History
75+
76+
| Version | Changes |
77+
| --------- | ------------------------------------ |
78+
| `v16.3.0` | `offlineNavigations` was introduced. |

0 commit comments

Comments
 (0)