Environment: Browser, Client Routing.

The navigate('/some/url') function enables you to programmatically switch pages.

navigate() works only with Client Routing. If you use Server Routing, then do window.location.href = '/some/url' instead.

With navigate(), you can implement navigations that aren't triggered by the user clicking on a <a> link: for example, when redirecting a user after a successful form submission.

import { navigate } from 'vike/client/router'

function Form() {
   return (
     <form onSubmit={onSubmit}>
       {/* ... */}

async function onSubmit() {
  const navigationPromise = navigate('/form/success')
  console.log("The URL changed but the new page hasn't rendered yet.")
  await navigationPromise
  console.log('The new page has finished rendering.')

If you want to redirect users before the page finished rendering (e.g. to redirect non-authenticated users to a login page), then use throw redirect() instead.


  • navigate('/some-url', { keepScrollPosition: true }): Don't scroll to the top of the page; keep scroll position where it is instead. (Useful for Nested Layouts.) (You can also use <a href="/some-url" keep-scroll-position />.)
  • navigate('/some-url', { overwriteLastHistoryEntry: true }): Don't create a new entry in the browser's history, instead let the new URL replace the current URL. (This effectively removes the current URL from the browser history).


If you want to change the URL completely independently of Vike then use history.pushState() instead of navigate().

Make sure you implement your navigation handling by listening to the popstate event.

It's paramount you handle the popstate event, otherwise you'll break the browser's back- and forward history button.
window.addEventListener('popstate', (event) => {
  // Vike sets triggeredBy to 'vike' | 'browser' | 'user'
  const { triggeredBy } = window.history.state
  /* Equivalent:
  const { triggeredBy } = event.state

  // Navigation event triggered by Vike or the browser
  if (triggeredBy === 'vike' || triggeredBy === 'browser') {
    // Abort: let Vike handle that navigation event

  // Navigation event triggered by your history.pushState() call
  if (triggeredBy === 'user') {
    // TODO: implement your navigation handling here


Vue example:

React example:

See also