V1 Design Migration

Despite being a simple change, the V1 design introduces new foundational capabilities. If you're curious: Why the V1 design?

The overall architecture stays the same: the V1 design is mostly about replacing .page.js files with so-called plus files: +Page.js, +route.js, +onBeforeRender.js, ...

The migration is straightforward and usually quick to implement. We encourage you to migrate sooner rather than later.

Don't hesitate to reach out if you run into any issue.

The old design is still supported but we recommend to migrate as the docs now showcase the V1 design.

Main migration

Make sure to update Vike to its latest version.

You need to either fully use the V1 design, or fully use the old design. You cannot mix both.

Most of the migration boils down to the following two steps.

1. Migrate /renderer/*.page.*

Move your renderer/ hooks to + files:

// /renderer/_default.page.client.js
// /renderer/+onRenderClient.js
export { render } 
export { render as onRenderClient } 
// /renderer/_default.page.server.js
// /renderer/+onRenderHtml.js
export { render } 
export { render as onRenderHtml } 

If you've defined a global onBeforeRender() hook and/or passToClient:

// /renderer/_default.page.server.js
// /renderer/+onBeforeRender.js
export { onBeforeRender }
export const passToClient = ['pageProps'] 
// /renderer/+config.js
export default {
  passToClient: ['pageProps']

See API > Config for more information about what + and .h.js means.

The suffixes such as .page.server.js and .page.client.js don't exist anymore. After the feature request #744 is implemented, you'll be able to use .server.js and .client.js suffixes again but note that they'll serve another purpose.

Move /renderer/ configurations to /renderer/+config.ts:

// /renderer/_default.page.client.ts
export { clientRouting }
export { hydrationCanBeAborted }
// /renderer/+config.ts
import type { Config } from 'vike/types'
export default {
  clientRouting: true,
  hydrationCanBeAborted: true
} satisfies Config

Move your error page (if you defined one):

export { Page }

2. Migrate /pages/**/*.page.*

// /pages/some-page/index.page.js
// /pages/some-page/+Page.js
export { Page }
// /pages/some-page/index.page.server.js
// /pages/some-page/+onBeforeRender.js
export { onBeforeRender }
// /pages/some-page/index.page.route.js
// /pages/some-page/+route.js
export default route

Each page now lives in its own directory.

# ✅ V1 design
$ ls pages/**/*
# ❌ This isn't possible anymore: each page now needs to create a new directory
$ ls pages/**/*

Apply following additional steps if you've defined:

If you have many /pages/**/*.page.js files then see Migration scripts.


All official examples have been migrated, see examples/*.

Notable migrations:

Migration scripts

PR welcome to add your migration script.

Renamed hooks

Old nameNew name
render() in .page.client.jsonRenderClient()
render() in .page.server.jsonRenderHtml()

The hooks are equivalent: they just have a new name.

Also note that doNotPrerender has been renamed:

Old nameNew name
doNotPrerender: trueprerender: false
// /pages/news.page.server.js
export const doNotPrerender = true
// /pages/news/+config.js
export default {
  prerender: false

Custom hooks/exports

If you use custom hooks/exports, then replace them with custom hooks/settings.

You can create your own hooks and settings by using meta:

// /renderer/+config.ts
import type { Config } from 'vike/types'
export default {
  meta: {
    // We create a new setting called `title`
    title: {
      // The value of `title` should be loaded only on the server
      env: { server: true }
} satisfies Config
// /renderer/+onRenderHtml.js
export { onRenderHtml }
async function onRenderHtml(pageContext) {
  // Config values are available at pageContext.config
  const { title } = pageContext.config
  return escapeInject`<html>
    <!-- ... -->
// /pages/about/+config.js
export default {
  title: 'Demo showcasing the V1 design'


onBeforeRender in .page.js

If you've defined onBeforeRender() hooks in .page.js (instead of .page.server.js):

// /renderer/+config.ts
import type { Config } from 'vike/types'
export default {
  meta: {
    onBeforeRender: {
      // We tell Vike to load and execute onBeforeRender()
      // not only on the server-side but also on the client-side.
      env: { server: true, client: true }
} satisfies Config

For convenience, you can use meta in order to create a new config dataIsomorph: boolean for a page-per-page toggle.

Client init code

The new config client allows you to define client-side initialization code.

You can also keep using onHydrationEnd().

// +config.js
export default {
  client: './some-client-code.js'
// some-client-code.js
console.log("I'm run when the client-side JavaScript is loaded.")

See also