Route Functions provide full programmatic flexibility to define routes.

// /pages/product/edit/+route.js
 
// This file defines the route of /pages/product/edit/+Page.js
 
// We use a RegExp, but we could as well use a routing library.
import partRegex from 'part-regex'
const routeRegex = partRegex`/product/${/([0-9]+)/}/edit`
 
export function route(pageContext) {
  if (!pageContext.user.isAdmin) return false
 
  const match = pageContext.urlPathname.match(routeRegex)
  if (!match) return false
  const [, id] = match
 
  return {
    routeParams: { id }
  }
}

The parameter id is available at pageContext.routeParams.id.

If you merely want to guard your page, then you can use a Route String with a guard() hook instead of a Route Function.

You can use any routing tool you want, such as:

Precedence

The precedence number can be used to resolve route conflicts, see API > Routing Precedence.

// /pages/product/edit/+route.js
 
export { route }
 
const route = (pageContext) => {
  // ...
  return {
    precedence: 10,
  }
}

resolveRoute()

You can use Route Strings inside Route Functions:

// /pages/product/edit/+route.js
 
export { route }
 
import { resolveRoute } from 'vike/routing'
 
const route = (pageContext) => {
  if (!pageContext.user.isAdmin) {
    return false
  }
  return resolveRoute('/product/@id/edit', pageContext.urlPathname)
}
// /pages/product/index/+route.js
 
export { route }
 
import { resolveRoute } from 'vike/routing'
 
const route = (pageContext) => {
  {
    const result = resolveRoute('/product/@id', pageContext.urlPathname)
    if (result.match) {
      result.routeParams.view = 'overview'
      return result
    }
  }
 
  const result = resolveRoute('/product/@id/@view', pageContext.urlPathname)
  if (!['reviews', 'pricing'].includes(result.routeParams.view)) {
    return false
  }
  return result
}

TypeScript

// /pages/product/index/+route.ts
 
export { route }
 
import type { RouteSync } from 'vike/types'
import { resolveRoute } from 'vike/routing'
 
const route: RouteSync = (pageContext): ReturnType<RouteSync> => {
  // ..
}

Lightweight & fast

Route Functions should be lightweight and fast.

Vike executes all Route Functions every time the user navigates to a new page. This means that a slow Route Function slows down all pages.

Vike always has to run all Route Functions because it cannot magically predict the outcome of Route Functions. Consider the following example:

// /pages/login/+route.js
 
export { route }
 
const route = (pageContext) => {
  // Only render the login page to unauthenticated users
  if (pageContext.user !== null) return false
  return {
    // We override all other routes by setting a high `precedence` value of `99`.
    // This means that, if the user isn't authenticated, then *all* URLs render the login page.
    precedence: 99
  }
}

This authentication routing trick is further explained at Integration > Authentication > Login flow.

Vike cannot know whether another Route Function will return a higher precedence number, therefore Vike has to execute all Route Functions.

If you use Client Routing, then all your Route Functions are loaded in the browser. This means that if a Route Function imports a lot of code, then all that code is loaded on the client-side of every page. A heavy Route Function slows down your whole app.

Route Functions should be lightweight and fast.

Async

Asynchronous Route Functions are forbidden.

// +route.js
 
// ❌ This is forbidden
export default async () => { /* ... */ }

The motivation for having an asynchronous Route Function is usually to redirect/protect a private page. You can achieve that by using throw render() / throw redirect() with an async guard(), async data(), or async onBeforeRender() hook.

An asynchronous Route Function would slow down your entire app: as explained in Lightweight & fast, every time the user navigates to a new page all your Route Functions are called. This means that a single slow Route Function slows down all your pages.

Redirection

See API > throw redirect().

Cannot provide pageContext

Using Route Functions to provide pageContext values is forbidden.

// +route.js
 
export default () => {
  return {
    // This is forbidden and Vike will throw an error
    pageContext: {
      some: 'value'
    }
  }
}

In principle, Vike could support providing pageContext values but it deliberately doesn't support it in order to foster lightweight Route Functions.

As explained in Lightweight & fast, you should keep Route Functions simple and you shouldn't implement complex logic in +route.js files.

That said, you can work around it by misusing pageContext.routeParams to provide data.

// +route.js
 
export default () => {
  return {
    routeParams: {
      // Any data can be added here
    }
  }
}

But it isn't recommended: pageContext.routeParams is supposed to hold only a minimal amount of information. Instead, we recommend to implement complex logic in data(), onBeforeRender(), guard(), or in a custom hook.

See also