Route Function

Route Functions give you full programmatic flexibility to define routes.

// /pages/product/edit/+route.js
 
export { route }
 
import partRegex from 'part-regex'
 
const route = (pageContext) => {
  // Route guard (we can also use a guard() hook instead)
  if (!pageContext.user.isAdmin) {
    return false
  }
 
  // We can use RegExp / any library we want
  if (!partRegex`/product/${/[0-9]+/}/edit`.test(pageContext.urlPathname)) {
    return false
  }
  const id = pageContext.urlPathname.split('/')[2]
 
  return {
    // Make `id` available as pageContext.routeParams.id
    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, which is usually a better approach.

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

Precedence

The precedence number can be used to resolve route conflicts, see Routing > 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 Guides > 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

Async Route Functions are forbidden.

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

The motivation for having an asynchronous Route Function is usually to implement redirection and/or protecting a private page. Instead, use throw render() orthrow redirect() with an async guard(), data() or 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 Route Functions are called. This means that a slow Route Function slows down all pages.

Redirection

See API > throw redirect().

Domain-driven file structure

As with Filesystem Routing a domain-driven file structure is possible, such as:

FILESYSTEM
user/pages/list/+Page.js
user/pages/list/+route.js
user/pages/create/+Page.js
user/pages/create/+route.js
todo/pages/list/+Page.js
todo/pages/list/+route.js
todo/pages/create/+Page.js
todo/pages/create/+route.js

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 this 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.