Skip to content

Commit b42991d

Browse files
committed
offline navigations: add docs and examples (11/11)
1 parent 80a9b05 commit b42991d

4 files changed

Lines changed: 382 additions & 1 deletion

File tree

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
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 been loaded or prefetched, Next.js can restore that route from browser-private navigation data 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 already loaded or prefetched. The most reliable way to make an important route available later is to prefetch it before the user needs it offline.
117+
118+
Use `<Link>` prefetching or [`router.prefetch`](/docs/app/api-reference/functions/use-router#userouter) for routes users are likely to need later:
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+
- Offline recovery also needs the JavaScript and CSS assets for the current build to be available in the browser cache. If those assets were not cached, were evicted, or belong to another deployment, the route cannot boot offline.
162+
- Browser storage can be cleared by users, browser settings, storage pressure, or DevTools. If storage is cleared, offline recovery may not start.
163+
- Mutations, Server Actions, Route Handlers, and POST requests still require the network.
164+
165+
Offline navigations do not cache arbitrary `fetch` responses, cookies, local storage, or your app's own data stores. If your app stores data separately, continue to manage that storage yourself.
166+
167+
## Keep offline data fresh
168+
169+
Offline navigations follow normal App Router cache invalidation. Use the same APIs you already use to refresh client and server data:
170+
171+
- [`router.refresh()`](/docs/app/api-reference/functions/use-router#userouter) refreshes dynamic route data and invalidates offline navigation data for the affected route.
172+
- [`refresh()`](/docs/app/api-reference/functions/refresh) refreshes client router data from a Server Action.
173+
- [`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.
174+
- Mutating cookies in a Server Action invalidates the client router cache, including offline navigation data.
175+
176+
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.
177+
178+
## Test offline navigations
179+
180+
Offline navigations do not run in `next dev`. Test with a production build:
181+
182+
```bash
183+
next build
184+
next start
185+
```
186+
187+
Then in a browser:
188+
189+
1. Visit the route online.
190+
2. Prefetch or navigate to any routes you expect to restore offline.
191+
3. Open DevTools and switch the network to **Offline**.
192+
4. Reload the route or open a cached route URL.
193+
194+
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.
195+
196+
> **Good to know**:
197+
>
198+
> - `localhost` is treated as a secure context, so service worker registration works with `next start` locally.
199+
> - Static export integration is not included in this experimental API.
200+
> - 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: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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 previously loaded or prefetched routes 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 loaded and prefetched App Router routes. |
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 app assets 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 JavaScript and CSS assets for the current build are not available in the browser cache, 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+
> - 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.
71+
> - Static export integration is not included in this experimental API.
72+
73+
## Version History
74+
75+
| Version | Changes |
76+
| --------- | ------------------------------------ |
77+
| `v16.3.0` | `offlineNavigations` was introduced. |

0 commit comments

Comments
 (0)