Skip to content
Meeko
Type to search the guides and the API reference. Open it from any page with / or Ctrl K; move with the arrow keys and open a result with Enter.
Get started

Contents

On this page

redirect

Stops page server code or server route middleware and responds with a redirect, which client navigation follows in the same way.

utility Since 1.1.0 No import @meekojs/meeko/framework Source code

Se usa sin import en el nivel superior de <script server>.

ts
import { redirect } from "@meekojs/meeko/framework";

redirect(url, status?) stops the top-level code in a page's <script server> and responds with a redirect. Since 1.6, it also stops server route middleware (app/middleware/*.server.ts). In SSR it is a 302 response (by default) with Location; during client navigation, the browser follows it just like a loader's redirect.

It works by throwing: code after redirect() does not run, and its return type is never, so TypeScript narrows types after the call. Inside <script server>, use it without an import.

Usage#

meeko
<!-- app/pages/account.meeko -->
<script server lang="ts">
const { context, url } = usePage();
const session = context.session.current;
if (!session) redirect(`/login?next=${encodeURIComponent(url.pathname)}`);
export const account = { id: session.id };
</script>

<template><h1>Account {account.id}</h1></template>

After the if, session is no longer undefined.

Type#

ts
function redirect(url: string | URL, status?: 301 | 302 | 303 | 307 | 308): never

Parameters#

Parameter Type Default Description
url string | URL required The destination: a path ("/login") or an absolute URL.
status 301 | 302 | 303 | 307 | 308 302 The HTTP status. 301 and 308 are permanent (browsers and caches remember them); 303 changes the method to GET; 307 and 308 preserve it.

Return value#

It never returns (never): it throws a response with Location and cache-control: no-store, which the server sends as is. It throws other errors in two cases:

  • outside its supported location, Error: MEEK073: redirect() sólo está disponible mientras se ejecuta el código de nivel superior del <script server> de una página o, desde 1.6, un middleware de ruta de servidor;
  • with another status, RangeError: redirect status must be 301, 302, 303, 307 or 308, not 404.

Examples#

An old URL with a permanent redirect#

meeko
<!-- app/pages/blog/[slug].meeko -->
<script server lang="ts">
const renamed: Record<string, string> = { "hola-mundo": "hola-meeko" };
const { params } = usePage();
const target = renamed[params.slug];
if (target) redirect(href("/blog/[slug]", { params: { slug: target } }), 301);
export const post = { slug: params.slug };
</script>

<template><h1>{post.slug}</h1></template>

From server route middleware#

In app/middleware/*.server.ts, import redirect:

ts
// app/middleware/auth.server.ts
import { defineServerRouteMiddleware, redirect } from "@meekojs/meeko/framework";

export default defineServerRouteMiddleware(({ session, url }) => {
  if (!session.current) redirect(`/login?next=${encodeURIComponent(url.pathname)}`);
}, { global: false });

From a loader, returning a Response#

redirect() does not work inside load, which is a route option. Return a Response there:

ts
// app/pages/legacy.route.ts
import { definePage } from "@meekojs/meeko/framework";

export const route = definePage({
  load: ({ url }) => Response.redirect(new URL("/nuevo", url), 301),
});

Common mistakes#

Calling it in the component's <script>#

Incorrectmeeko
<script lang="ts">
const go = () => redirect("/login");
</script>

MEEK073: redirect() sólo funciona en el código de nivel superior del <script server> de una página: el <script> y la plantilla de un componente también se ejecutan en el navegador. In the component, navigate with a link or location.assign.

Correctmeeko
<script server lang="ts">
const { context } = usePage();
if (!context.session.current) redirect("/login");
export const ok = true;
</script>

Calling it inside load or another route option#

Incorrectts
export const route = definePage({ load: ({ params }) => { if (!params.id) redirect("/"); return { id: params.id }; } });

MEEK073: redirect() sólo funciona en el código de nivel superior de <script server>, que se ejecuta en cada petición; llámala fuera de cualquier función y fuera de las opciones de ruta.

Correctts
export const route = definePage({ load: ({ params, url }) => params.id ? { id: params.id } : Response.redirect(new URL("/", url)) });

A nonredirect status#

Incorrectts
redirect("/login", 404);

The project's meeko check reports TS2345: Argument of type '404' is not assignable to parameter of type '301 | 302 | 303 | 307 | 308 | undefined'. At runtime, RangeError: redirect status must be 301, 302, 303, 307 or 308, not 404. For a 404, use notFound().

Correctts
redirect("/login", 303);

Wrapping it in try#

redirect works by throwing: a catch that does not rethrow swallows the redirect, without any error.

Incorrectts
try {
  if (!session) redirect("/login");
  data = await load();
} catch {
  data = null;
}
Correctts
if (!session) redirect("/login");
try {
  data = await load();
} catch {
  data = null;
}

Notes#

  • Security. Do not redirect to a URL received in the request without checking it (?next=https://otro.example): this is an open redirect. Check that it starts with / and not //, or construct the destination with href.
  • Cache. The response carries cache-control: no-store: a session-dependent redirect is never stored in a shared cache.
  • Navigation. In the browser, the page data request receives the redirect and navigation follows it without reloading, just like a loader's redirect.
  • render: "client" and "prerender". These pages have no top-level server code; use isomorphic route middleware, which returns Response.redirect(…).

Was this page helpful?

Add a comment

It is sent when you choose “Yes” or “No”. Only the page, your answer and the comment are stored: no cookies and no personal data.

0 of 2000 characters

Edit on GitHub: docs/en/reference/utils/redirect.md