When the user navigates to a new page, a completely new pageContext object is created and the previous pageContext becomes obsolete — that's why it's called pageContext, not appContext. See Lifecycle for more information.
The pageContext object also contains many internals (they are prefixed with _, e.g. pageContext._httpRequestId). You should use them only if strictly needed and, if you do, then let us know so that we can add official support for your use case (otherwise you'll expose yourself to breaking changes upon any version update).
pageContext.Page
The export { Page } or export default of the +Page.js file.
{ // Without Base URL, and decodes escaped characters. pathname: '/hello/sébastien', // With Base URL, and doesn't decode escaped characters. pathnameOriginal: '/some-base-url/hello/s%C3%A9bastien', search: { fruit: 'orânge' }, searchAll: { fruit: ['âpple', 'orânge'] }, searchOriginal: '?fruit=%C3%A2pple&fruit=orânge', hash: 'âge', hashOriginal: '#%C3%A2ge' // Without Base URL, and doesn't decode escaped characters. href: 'https://example.com/hello/s%C3%A9bastien?fruit=%C3%A2pple&fruit=orânge#%C3%A2ge', origin: 'https://example.com', protocol: 'https://', hostname: 'example.com', // 'localhost' if http://localhost:3000 port: null // 3000 if http://localhost:3000}
pageContext.headers
The headers of the HTTP Request. As a string object (Record<string, string>) normalized by Vike, see HTTP Headers.
pageContext.headersOriginal
The headers of the HTTP Request. The original object provided by the server, see HTTP Headers.
pageContext.config
All runtime information about the page's configuration (the page's route, hooks, settings, ...).
pageContext.isHydration
Whether the page is rendered to HTML.
When using Client Routing, the value is true for the first page the user navigates to, and false for any subsequent navigation. When using Server Routing, the value is always true.
If the page doesn't throw an error then it's equivalent to pageContext.isHydration === !pageContext.isClientSideNavigation. If there is an error, the error page is rendered and both pageContext.isHydrationpageContext.isClientSideNavigation are false.
pageContext.isClientSide
Whether the page is being rendered on the client-side, or server-side / pre-rendered.
Also useful for narrowing down the PageContext type to either PageContextClient or PageContextServer, see Narrowing down.
It's equivalent to pageContext.isClientSide === !import.meta.env.SSR.
// This import is also removed when building for the server-sideimport someClientImport from '../../client'// This import is also removed when building for the client-sideimport someServerImport from '.././server'if (pageContext.isClientSide) { // This code block is removed when building for the server-side someClientImport() // ... client code ...} else { // This code block is removed when building for the client-side someServerImport() // ... server code ...}
pageContext.isPrerendering
Whether the page is being pre-rendered. The value is always false in development.
pageContext.isBackwardNavigation
Whether the user is navigating back in history.
The value is true when the user clicks on his browser's backward navigation button, or when invoking history.back().
The isBackwardNavigation property is only defined when using Client Routing.
pageContext.previousPageContext
Upon client-side page navigation, you can use pageContext.previousPageContext to access the pageContext of the previous page. See Lifecycle.
pageContext.is404
If an error occurs, whether the error is a 404 Page Not Found or a 500 Internal Error, see API > Error Page.
pageContext.isClientSideNavigation
Whether the page was navigated by the client-side router.
In other words, when using Client Routing, the value is false for the first page the user visits, and true for any subsequent navigation. (When using Server Routing, the value is always false.)
// Your Vike server middleware integrationapp.get('*', async (req) => { const pageContextInit = { // *************************************** // *** Built-in pageContext properties *** // *************************************** urlOriginal: req.url, headersOriginal: req.headers, // *************************************** // **** Custom pageContext properties **** // *************************************** // Common use case: make information about logged-in user available at pageContext.user user: req.user, // Or any other value: // pageContext.myCustomProp myCustomProp: someValue } const pageContext = await renderPage(pageContextInit) // ...})
Setting pageContext.user is a common use case for integrating authentication tools, see Integration > Authentication.
FAQ
Can I mutate pageContext?
Yes, it's a common practice to change/add pageContext properties. See Custom.
pageContext.someProp = someValue
Can I use pageContext as a UI store?
Instead of using pageContext, we generally recommend using a proper UI state management tool such as React's useState(), Redux, Vue's ref(), Pinia, etc.
That said, there are use cases for using pageContext to store client-side state. For example to pass information from the previous page to the next during navigation.
See Lifecycle to understand whether using pageContext can make sense for your use case.
// +onAfterRenderHtml.jsexport function onAfterRenderHtml(pageContext) { const isSSR = !!pageContext.Page if (isSSR) { // ... }}
TypeScript
Basics
import type { // For code loaded in client and server PageContext, // For code loaded in client only PageContextClient, // For code loaded in server only PageContextServer} from 'vike/types'
import type { PageContext, GlobalContext } from 'vike/types'function someFunction(someObject: PageContext | GlobalContext) { if (someObject.isPageContext) { // someObject is PageContext } else { // someObject is GlobalContext }}
import type { PageContext } from 'vike/types'function someFunction(pageContext: PageContext) { if (pageContext.isClientSide) { // pageContext is PageContextClient } else { // pageContext is PageContextServer }}
Extend
To extend and/or refine PageContext/PageContextServer/PageContextClient, use the global interface Vike.PageContext:
declare global { namespace Vike { interface PageContext { // Type of pageContext.user user?: { name: string id: string isAdmin: boolean } // Refine type of pageContext.Page Page: () => React.JSX.Element } }}// If you define Vike.PageContext in a .d.ts file then// make sure there is at least one export/import statement.// Tell TypeScript this file isn't an ambient module:export {}
To define properties only for the server-/client-side, use the interfaces Vike.PageContextServer and Vike.PageContextClient instead.
import type { // For code loaded in client and server PageContextWithServerRouting as PageContext, // For code loaded in client only PageContextClientWithServerRouting as PageContextClient, // For code loaded in server only PageContextServer} from 'vike/types'
Lifecycle
The pageContext object is tied to the rendering process of a single page: whenever a new page is rendered, a new pageContext object is created. (If the current page is re-rendered, a new pageContext object is created as well.)
On the server-side, a new pageContext object is created whenever a page is rendered to HTML. The pageContext object is discarded after the HTML is sent to the client. (But pageContext properties sent to the client via passToClient are preserved on the client-side.)
Client
On the client side, a new pageContext object is created whenever a page is rendered. In other words:
dist/client/${urlOfThePage}/index.html (see <script id="vike_pageContext">)
If you inspect dist/client/, you'll find a index.pageContext.json file for each pre-rendered page.
Since a pre-rendered page is built ahead of time, its server-side pageContext may be outdated by the time a user visits the page.
Problem: pageContext is outdated upon hydration
Upon hydration, some pageContext properties may appear incorrect or "outdated".
For example, if a user visits /products?filter=computer then pageContext.urlParsed.search is empty and ?filter=computer is missing.
That's because Vike uses the server-side pageContext.urlOriginal that was used to pre-render the URL /products which didn't have ?filter=computer.
In theory, Vike could update pageContext.urlParsed on the client-side to include ?filter=computer, but this would cause a hydration mismatch. That's why, upon hydration, Vike intentionally keeps the client- and server-side pageContext aligned.
// pages/products/+onHydrationEnd.jsimport { reload } from 'vike/client/router'export async function onHydrationEnd() { if (window.location.href.includes('?filter')) await reload()}
Or, if the number of ?filter= values isn't too large, you can use onBeforePrerenderStart() to pre-render all filter values: /products?filter=computer, /products?filter=car, ...