This tutorial explains how to set up server-side redirects using Builder's Data model.
Server-side redirects guide visitors from one URL to another before the page loads. Use redirects to phase out old URLs without breaking links or to transition to new naming conventions.
- Redirects run on the server, so the intermediate URL does not display.
- Each redirect maps a source URL to a destination URL and can optionally mark the redirect as permanent with a 301 HTTP status.
- Manage redirects in Builder using a single Data model without code changes until deployment.
- An app in the framework of your choice with the appropriate Builder SDK installed.
- Integrate your app with a Data model. For details, see Integrate with structured Data.
Create a Data Model to define a structured container for your site's URL redirects.
To create a Data model:
- Go to Models.
- Click + Create Model.
- In the Name field, enter
URL Redirects. - In the Description field, enter
server-side redirects. - Click Create.
The video below demonstrates creating a new Data model called URL Redirects:
Add custom fields to the model to store the redirect URLs and other settings for managing redirects in your content entries.
To add custom fields:
- On the Fields tab, click + New Field.
- In the Name field, enter
SourceUrland set the Type to Url. - Repeat the process to create
DestinationUrlwith type Url andRedirectToPermanentwith type Boolean. - Click Save.
The video below demonstrates adding custom fields such as SourceUrl, DestinationUrl, and RedirectToPermanent to the Data model.
To create URL Redirects entries:
- Go to Content and click + New Entry.
- Select URL Redirect as the model type.
- In the Name field, enter
/site/intro → /site/get-startedto make the entry easy to identify. - Assign values to each custom field:
SourceUrl,DestinationUrl, andRedirectToPermanent. - Click Save.
The following video demonstrates creating a content entry using the URL Redirects model and setting values for the custom fields.
Create or update the next.config.js file in the root directory:
// next.config.js
const { builder } = require("@builder.io/sdk");
module.exports = {
async redirects() {
const results = await builder.getAll("url-redirects");
return results.map(({ data }) => ({
source: data.sourceUrl,
destination: data.destinationUrl,
permanent: !!data.redirectToPermanent,
}));
},
};This setup uses builder.getAll() to fetch all entries from the url-redirects model. Each entry is transformed into the format required by Next.js:
source: the original URL fromsourceUrldestination: the redirect target fromdestinationUrlpermanent:truefor permanent HTTP status code301,falsefor temporary HTTP status code302
For example, a redirect created in Builder from /old-page to /new-page with permanent set to true maps to:
{
source: "/old-page",
destination: "/new-page",
permanent: true
}The next.config.js file supports up to 1024 redirect entries. For more context, refer to Vercel's guide, How can I increase the limit of redirects or use dynamic redirects on Vercel? and for more comprehensive information, visit their Redirecting documentation.
With Next.js sites, you need to trigger a rebuild for new redirects. Since Next.js evaluates the next.config.js only once when building an app, newly added redirects don’t take effect immediately. To cause this rebuild, use a webhook.
For this part of the tutorial, you need a webhook URL on the backend. If you're using Vercel, visit their Deploy hooks documentation.
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
Create or update the next.config.js file in the root directory:
// next.config.js
const { fetchEntries } = require("@builder.io/sdk-react");
/** @type {import('next').NextConfig} */
const nextConfig = {
async redirects() {
// Make sure to replace YOUR_API_KEY with your actual Builder API key
const results = await fetchEntries({
model: "url-redirects",
// Make sure you have your Public API Key set in your environment variables
apiKey: process.env.BUILDER_API_KEY,
// Optionally limit the fields returned to only what's needed
fields: 'data.sourceUrl,data.destinationUrl,data.redirectToPermanent',
// You can add additional query parameters as needed
options: {
noTargeting: true,
}
});
// Transform Builder entries into Next.js redirect format
return results.results.map((entry) => ({
source: entry.data.sourceUrl,
destination: entry.data.destinationUrl,
permanent: !!entry.data.redirectToPermanent,
}));
},
};
module.exports = nextConfig;This setup fetches entries from the url-redirects model using fetchEntries(), passing the Builder public API key. Each entry is transformed into the format required by Next.js:
source: the original URL fromsourceUrldestination: the redirect target fromdestinationUrlpermanent: true for permanent HTTP status code 301, false for temporary HTTP status code 302
For example, a redirect created in Builder from /old-page to /new-page with permanent set to true maps to:
{
source: "/old-page",
destination: "/new-page",
permanent: true
}The next.config.js file has a 1024 entry count limit. For more context, refer to Vercel's guide, How can I increase the limit of redirects or use dynamic redirects on Vercel? and for more comprehensive information visit their Redirecting documentation.
With Next.js sites, you need to trigger a rebuild for new redirects. Since Next.js evaluates the next.config.js only once when building an app, newly added redirects don’t take effect immediately. To cause this rebuild, use a webhook.
For this part of the tutorial, you need a webhook URL on the backend. If you're using Vercel, visit their Deploy hooks documentation.
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
Create a new file named middleware.ts in the root directory:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { builder } from '@builder.io/react';
export async function middleware(request: NextRequest) {
const results = await builder.getAll('url-redirects', {
fields: 'data.sourceUrl,data.destinationUrl,data.redirectToPermanent',
options: {
noTargeting: true,
}
});
// Get the current URL path that the user is requesting
const pathname = request.nextUrl.pathname;
// Go through all redirects to find one where the source URL matches current path
const redirect = results.find(entry =>
entry.data.sourceUrl === pathname
);
// If a matching redirect is found
if (redirect) {
// Create a new URL using the destination from Builder
const url = new URL(redirect.data.destinationUrl, request.url);
// Return a redirect response with appropriate status:
// 308 for permanent redirects (equivalent to 301)
// 307 for temporary redirects (equivalent to 302)
return NextResponse.redirect(url, {
status: redirect.data.redirectToPermanent ? 308 : 307
});
}
// If no redirect was found, continue with the original request
return NextResponse.next();
}This middleware fetches entries from the url-redirects model using builder.getAll(). Each redirect entry is checked against the requested path. When a match is found, the middleware issues a redirect:
- HTTP status code 308 for permanent redirects
- HTTP status code 307 for temporary redirects
For example, a redirect created in Builder from /old-page to /new-page with permanent set to true maps to:
{
source: "/old-page",
destination: "/new-page",
permanent: true
}This setup helps handle redirects at the edge, intercepting and rerouting requests dynamically based on Builder-managed rules.
With Next.js sites, you need to trigger a rebuild for new redirects. Since Next.js evaluates the next.config.js only once when building an app, newly added redirects don’t take effect immediately. To cause this rebuild, use a webhook.
For this part of the tutorial, you need a webhook URL on the backend. If you're using Vercel, visit their Deploy hooks documentation.
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
Create a new file named middleware.ts in the root directory:
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { fetchEntries } from '@builder.io/sdk-react';
export async function middleware(request: NextRequest) {
const results = await fetchEntries({
model: "url-redirects",
// Make sure you have your Public API Key set in your environment variables
apiKey: process.env.BUILDER_API_KEY!,
// Optionally limit the fields returned to only what's needed
fields: 'data.sourceUrl,data.destinationUrl,data.redirectToPermanent',
});
// Get the current URL path that the user is requesting
const pathname = request.nextUrl.pathname;
// Go through all redirects to find one where the source URL matches current path
const redirect = results.results.find(entry =>
entry.data.sourceUrl === pathname
);
// If a matching redirect is found
if (redirect) {
// Create a new URL using the destination from Builder
const url = new URL(redirect.data.destinationUrl, request.url);
// Return a redirect response with appropriate status:
// 308 for permanent redirects (equivalent to 301)
// 307 for temporary redirects (equivalent to 302)
return NextResponse.redirect(url, {
status: redirect.data.redirectToPermanent ? 308 : 307
});
}
// If no redirect was found, continue with the original request
return NextResponse.next();
}This middleware fetches entries from the url-redirects model using fetchEntries(). Each redirect entry is checked against the requested path. When a match is found, the middleware issues a redirect:
- HTTP status code 308 for permanent redirects
- HTTP status code 307 for temporary redirects
For example, a redirect created in Builder from /old-page to /new-page with permanent set to true maps to:
{
source: "/old-page",
destination: "/new-page",
permanent: true
}With Next.js sites, you need to trigger a rebuild for new redirects. Since Next.js evaluates the next.config.js only once when building an app, newly added redirects don’t take effect immediately. To cause this rebuild, use a webhook.
For this part of the tutorial, you need a webhook URL on the backend. If you're using Vercel, visit their Deploy hooks documentation.
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
In this React with React Router set up, create a new file named redirects.tsx in the src/components directory, or as the setup indicates:
// src/redirects.tsx
import { builder } from '@builder.io/sdk';
import { Navigate, useLocation } from 'react-router-dom';
import { useState, useEffect } from 'react';
export function RedirectHandler({ children }) {
const [redirects, setRedirects] = useState([]);
const location = useLocation();
useEffect(() => {
async function fetchRedirects() {
const results = await builder.getAll("url-redirects");
setRedirects(results.map(({ data }) => ({
source: data.sourceUrl,
destination: data.destinationUrl,
permanent: !!data.redirectToPermanent
})));
}
fetchRedirects();
}, []);
const currentRedirect = redirects.find(r => r.source === location.pathname);
if (currentRedirect) {
if (currentRedirect.permanent) {
window.location.replace(currentRedirect.destination);
return null;
}
return <Navigate to={currentRedirect.destination} replace />;
}
return children;
}This code creates a React component that handles dynamic URL redirects:
- The
<RedirectHandler>component fetches and stores redirect rules from Builder usinguseEffect()anduseState(). Each rule includes a source URL, destination URL, and permanent status. - The component uses
useLocation()to monitor the current path and check for matching redirect rules. - For matches, the component uses
window.location.replace()for permanent (301) redirects or React Router’snavigate()for temporary (302) redirects. - If no redirect matches, the component renders its child components as usual.
In src/main.tsx, wrap the <Routes> component with RedirectHandler to monitor route changes. For more information, see the Routing of the React Router:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import RedirectHandler from './components/Redirects';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<BrowserRouter>
<RedirectHandler>
<Routes>
<Route path="/site/get-started" element={<GetStarted />} />
</Routes>
</RedirectHandler>
</BrowserRouter>
</React.StrictMode>
);
This setup helps evaluate route changes against the Builder-managed redirect list.
When fetching redirects from Builder, each entry is mapped into an object. For example, a redirect from /old-page to /new-page with permanent set to true becomes:
{
source: "/old-page",
destination: "/new-page",
permanent: true
}In this React with React Router set up, create a new file named redirects.tsx in the src/components directory:
// src/redirects.tsx
import { fetchEntries, type BuilderContent } from "@builder.io/sdk-react";
import { useNavigate, useLocation } from "react-router";
import { useEffect } from "react";
export default function RedirectHandler({ children }: { children: React.ReactNode }) {
const { pathname } = useLocation();
const navigate = useNavigate();
useEffect(() => {
fetchEntries({
model: "url-redirects",
apiKey: /* ADD YOUR PUBLIC API KEY */,
}).then((results) => {
const matchingPath = results.find(
({ data }: BuilderContent) => data?.sourceUrl === pathname
)?.data;
if (matchingPath?.destinationUrl && matchingPath?.redirectToPermanent) {
window.location.replace(matchingPath.destinationUrl);
} else if (matchingPath?.destinationUrl) {
navigate(matchingPath.destinationUrl, { replace: true });
}
});
}, [pathname, navigate]);
return children;
}
This component fetches redirect entries using fetchEntries() to check the current URL with useLocation() and matches against the fetched rules.
Redirects are handled as permanent with window.location.replace() or temporary using navigate().
Wrap the routes with the <RedirectHandler> component inside the <BrowserRouter> to monitor all route changes for matching redirect entries:
// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import RedirectHandler from './components/Redirects';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<BrowserRouter>
<RedirectHandler>
<Routes>
<Route path="/site/get-started" element={<GetStarted />} />
</Routes>
</RedirectHandler>
</BrowserRouter>
</React.StrictMode>
);
This setup helps evaluate route changes against the Builder-managed redirect list.
A redirect entry in Builder with source /old-page, destination /new-page, and permanent set to true maps to:
{
sourceUrl: "/old-page",
destinationUrl: "/new-page",
redirectToPermanent: true
}Run the app locally and verify that visiting /site/intro redirects to /site/get-started.
Create a new file builderRedirects.ts in the /utilsdirectory:
// /utils/builderRedirects.ts
import { fetchEntries } from '@builder.io/sdk-react';
const BUILDER_API_KEY = 'YOUR_PUBLIC_API_KEY';
interface UrlRedirect {
source: string;
destination: string;
permanent: boolean;
}
// Fetch all redirect entries from Builder
export const redirectsFromBuilder = async (): Promise<UrlRedirect[]> => {
const results = await fetchEntries({
model: 'url-redirects',
apiKey: BUILDER_API_KEY,
});
return results.map(({ data = {} }) => ({
source: data.sourceUrl,
destination: data.destinationUrl,
permanent: data.redirectToPermanent,
}));
};
// Find a redirect that matches the current request path
export const findRedirectByRequestUrl = async (
requestUrl: string,
): Promise<UrlRedirect | null> => {
const url = new URL(requestUrl);
const path = url.pathname;
const builderRedirectUrls = await redirectsFromBuilder();
return (
builderRedirectUrls.find((url) => {
let source = url.source;
if (path.endsWith('/') && !source.endsWith('/')) source += '/';
return source === path;
}) || null
);
};
The redirectsFromBuilder() function fetches redirect entries from Builder and maps them into a standard format. The findRedirectByRequestUrl() function checks if the request path matches any source URL.
In Remix, entry.server.tsx is the entry point for all server-side requests. Add the redirect logic at the top of the handleRequest function:
// entry.server.tsx
import { redirect } from '@remix-run/node';
import { RemixServer } from '@remix-run/react';
import { findRedirectByRequestUrl } from './utils/builderRedirects';
import { renderToString } from 'react-dom/server';
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
// Check for a redirect before rendering
const redirectUrl = await findRedirectByRequestUrl(request.url);
if (redirectUrl) {
const status = redirectUrl.permanent ? 301 : 302;
return redirect(redirectUrl.destination, { status });
}
const markup = renderToString(
<RemixServer context={remixContext} url={request.url} />,
);
responseHeaders.set('Content-Type', 'text/html');
return new Response('<!DOCTYPE html>' + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
This setup fetches and checks redirect rules on every request. When a match is found, the app returns an HTTP 301 redirect for permanent redirects or 302 for temporary redirects. When no match is found, the request proceeds with standard server-side rendering.
When using static builds with Remix, you need to trigger a rebuild for new redirects. To cause this rebuild, use a webhook.
For this part of the tutorial, you need a webhook URL on the backend. If you're using Vercel, visit their Deploy hooks documentation.
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
Create a new file named redirects.server.ts in the app/utils directory:
// app/utils/redirects.server.ts
import { builder } from '@builder.io/sdk';
import { redirect } from '@remix-run/node';
builder.init(/* ADD YOUR PUBLIC API KEY HERE */)
export async function checkRedirect(pathname: string) {
// Fetch redirect rules from Builder
const results = await builder.getAll('url-redirects');
// Find matching redirect for current path
const currentRedirect = results.find(
({ data }) => data.sourceUrl === pathname
);
// If match found, throw a Remix redirect response with status code
if (currentRedirect) {
throw redirect(currentRedirect.data.destinationUrl, {
status: currentRedirect.data.redirectToPermanent ? 301 : 302
});
}
}This function fetches redirect rules from Builder, checks if the current path matches a rule, and throws a Remix redirect response. Redirects use HTTP status code 301 for permanent redirects and 302 for temporary redirects.
In app/root.tsx, import and use the checkRedirect() function in the loader:
// app/root.tsx
import { checkRedirect } from '~/utils/redirects.server';
import type { LoaderFunction } from '@remix-run/node';
export const loader: LoaderFunction = async ({ request }) => {
// Get the URL from the incoming request
const url = new URL(request.url);
// Check if current path matches any redirect rules
// If match found, this will throw a redirect response
await checkRedirect(url.pathname);
// No redirect needed, continue with normal page load
return null;
};This loader checks each request for matching redirect rules and performs the redirect when needed.
For static builds, a webhook is needed to trigger rebuilds when redirects change. For server-side rendering, redirects update automatically. Check your codebase to determine if you need a webhook or not. If you do need a webhook, follow the instructions below.
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
Create a new file named builderRedirects.ts in the /utils directory:
// /utils/builderRedirects.ts
import { fetchEntries } from '@builder.io/sdk-react';
const BUILDER_API_KEY = 'YOUR_PUBLIC_API_KEY';
interface UrlRedirect {
source: string;
destination: string;
permanent: boolean;
}
// Fetch all redirect entries from Builder
export const redirectsFromBuilder = async (): Promise<UrlRedirect[]> => {
const results = await fetchEntries({
model: 'url-redirects',
apiKey: BUILDER_API_KEY,
});
return results.map(({ data = {} }) => ({
source: data.sourceUrl,
destination: data.destinationUrl,
permanent: data.redirectToPermanent,
}));
};
// Find a redirect that matches the current request path
export const findRedirectByRequestUrl = async (
requestUrl: string,
): Promise<UrlRedirect | null> => {
const url = new URL(requestUrl);
const path = url.pathname;
const builderRedirectUrls = await redirectsFromBuilder();
return (
builderRedirectUrls.find((url) => {
let source = url.source;
if (path.endsWith('/') && !source.endsWith('/')) source += '/';
return source === path;
}) || null
);
};
The redirectsFromBuilder() function fetches redirect entries from Builder and maps them into a standard format. The findRedirectByRequestUrl() function checks if the request path matches any source URL.
In entry.server.tsx, import findRedirectByRequestUrl() and add the redirect logic at the top of the handleRequest() function:
// entry.server.tsx
import { redirect } from '@remix-run/node';
import { RemixServer } from '@remix-run/react';
import { findRedirectByRequestUrl } from './utils/builderRedirects';
import { renderToString } from 'react-dom/server';
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext,
) {
// Check for a redirect before rendering
const redirectUrl = await findRedirectByRequestUrl(request.url);
if (redirectUrl) {
const status = redirectUrl.permanent ? 301 : 302;
return redirect(redirectUrl.destination, { status });
}
const markup = renderToString(
<RemixServer context={remixContext} url={request.url} />,
);
responseHeaders.set('Content-Type', 'text/html');
return new Response('<!DOCTYPE html>' + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}
This setup fetches and checks redirect rules on every request. When a match is found, the app returns an HTTP 301 redirect for permanent redirects or 302 for temporary redirects. When no match is found, the request proceeds with standard server-side rendering.
For example, a redirect created in Builder from /old to /new with permanent set to true becomes:
{
"source": "/old",
"destination": "/new",
"permanent": true
}
Add a Webhook
When using static builds with Remix, you need to trigger a rebuild for new redirects. To cause this rebuild, use a webhook.
For this part of the tutorial, you need a webhook URL on the backend. If you're using Vercel, visit their Deploy hooks documentation.
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
Create a new file named redirects.server.ts in the app/utils directory.
// app/utils/redirects.server.ts
import { builder } from '@builder.io/sdk';
import { redirect } from '@remix-run/node';
export async function checkRedirect(pathname: string) {
// Fetch redirect rules from Builder
const results = await builder.getAll('url-redirects');
// Find matching redirect for current path
const currentRedirect = results.find(
({ data }) => data.sourceUrl === pathname
);
// If match found, throw a Remix redirect response with status code
if (currentRedirect) {
throw redirect(currentRedirect.data.destinationUrl, {
status: currentRedirect.data.redirectToPermanent ? 301 : 302
});
}
}This function fetches redirect rules from Builder, checks if the current path matches a rule, and throws a Remix redirect response. Redirects use HTTP status code 301 for permanent redirects and 302 for temporary redirects.
In app/root.tsx, import and use the checkRedirect() function in the loader.
// app/root.tsx
import { checkRedirect } from '~/utils/redirects.server';
import type { LoaderFunction } from '@remix-run/node';
export const loader: LoaderFunction = async ({ request }) => {
// Get the URL from the incoming request
const url = new URL(request.url);
// Check if current path matches any redirect rules
// If match found, this will throw a redirect response
await checkRedirect(url.pathname);
// No redirect needed, continue with normal page load
return null;
};This loader checks each request for matching redirect rules and performs the redirect when needed.
For static builds, a webhook is needed to trigger rebuilds when redirects change. For server-side rendering, redirects update automatically. Check your codebase to determine if you need a webhook or not. If you do need a webhook, follow the instructions below.
The following video demonstrates how to set up a Webhook:
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
Create a new file named BuilderRedirects.ts in the /src directory.
//src/BuilderRedirects.ts
import { fetchEntries } from '@builder.io/sdk-vue';
export async function getRedirects() {
const results = await fetchEntries({
model: 'url-redirects',
apiKey: 'YOUR_PUBLIC_API_KEY',
});
return results.map(entry => ({
from: entry.data?.sourceUrl,
to: entry.data?.destinationUrl,
permanent: entry.data?.redirectToPermanent,
}));
}This function fetches redirect entries from the url-redirects model and maps them into a format usable by the Vue router.
In src/router/index.ts, import getRedirects() and add the redirect logic to a beforeEach() navigation guard:
import { createRouter, createWebHistory } from 'vue-router';
import HomeView from '../views/HomeView.vue';
import { getRedirects } from '../builderRedirects'; // Import redirect logic
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/get-started',
name: 'get-started',
component: () => import('../views/GetStarted.vue'),
},
//other routes
],
});
// Add a global navigation guard to handle redirects
router.beforeEach(async (to, from, next) => {
const redirects = await getRedirects();
const match = redirects.find(r => r.from === to.fullPath);
if (match?.to) {
if (match.permanent) {
window.location.replace(match.to);
} else {
next(match.to);
}
} else {
next();
}
});
export default router;
This setup adds a global navigation guard that fetches redirect rules and checks each route change for a match. When a match is found:
- HTTP status code 301 redirects use
window.location.replace(). - HTTP status code 302 redirects use
next()for client-side routing.
For example, a redirect created in Builder from /site/old to /site/new with permanent set to true maps to:
{
"from": "/site/old",
"to": "/site/new",
"permanent": true
}
Run the app locally and verify that visiting /site/intro redirects to /site/get-started.
Create a new file named useRedirects.ts in the composables directory:
// composables/useRedirects.ts
import { fetchEntries } from '@builder.io/sdk-vue';
export async function useRedirects() {
const results = await fetchEntries({
model: 'url-redirects',
apiKey: 'YOUR_PUBLIC_API_KEY',
});
return results.map(entry => ({
from: entry.data?.sourceUrl,
to: entry.data?.destinationUrl,
permanent: entry.data?.redirectToPermanent,
}));
}This composable fetches redirect entries from the url-redirects model and maps them into a format usable by Nuxt middleware.
Create a new file named redirect.global.ts in the middleware directory:
// middleware/redirect.global.ts
export default defineNuxtRouteMiddleware(async (to) => {
const redirects = await useRedirects();
const match = redirects.find(r => r.from === to.fullPath);
if (match?.to) {
if (match.permanent) {
return navigateTo(match.to, { external: true, redirectCode: 301 });
} else {
return navigateTo(match.to, { replace: true });
}
}
});This global middleware runs on every navigation page and checks for a matching redirect rule. When a match is found:
- HTTP status code 301 redirects use
navigateTo()withexternal: trueandredirectCode: 301 - HTTP status code 302 redirects use
navigateTo()withreplace: truefor client-side routing
For example, a redirect created in Builder from /site/old to /site/new with permanent set to true maps to:
{
"from": "/site/old",
"to": "/site/new",
"permanent": true
}
Run the app locally and verify that visiting /site/intro redirects to /site/get-started.
In layout.tsx, add the following code above the onGet() request handler:
import { fetchEntries } from "@builder.io/sdk-qwik";
const BUILDER_API_KEY = YOUR_BUILDER_API_KEY;
interface QwikUrlRedirect {
source: string;
destination: string;
permanent: boolean;
}
const redirectsFromBuilder = async (): Promise<QwikUrlRedirect[]> => {
const results = await fetchEntries({
model: "url-redirect",
apiKey: BUILDER_API_KEY,
});
return results.map(({ data = {} }) => ({
source: data.sourceUrl,
destination: data.destinationUrl,
permanent: data.permanent,
}));
};
let routesLoaded: QwikUrlRedirect[] = [];This code imports fetchEntries() from the Builder SDK, fetches redirect entries from the url-redirect model, and maps them into a usable format. The routesLoaded caches the results.
Update the onGet() request handler to include the following logic:
export const onGet: RequestHandler = async ({
url,
redirect,
cacheControl,
}) => {
// qwik city request caching goes here
// ...
// Fetch data from Builder and assign to `routesLoaded`
async function fetchRules(): Promise<QwikUrlRedirect[]> {
if (routesLoaded.length) return routesLoaded;
routesLoaded = await redirectsFromBuilder();
return routesLoaded;
}
// Find matching redirect rules and redirect as needed
const redirectRules = await fetchRules();
const redirectUrl = redirectRules.find((rule) => {
if (url.pathname.endsWith("/")) {
return rule.source + "/" === url.pathname;
}
return rule.source === url.pathname;
});
if (redirectUrl) {
throw redirect(redirectUrl.permanent ? 308 : 307, redirectUrl.destination);
}
};This code does the following:
- Loads redirect rules from Builder if uncached.
- Checks if the current path matches any source from the redirect rules.
- Redirects using HTTP status code 308 for permanent redirects (equivalent to 301) or 307 for temporary redirects (equivalent to 302).
For example, a redirect created in Builder from /site/old to /site/new with permanent set to true maps to:
{
"source": "/site/old",
"destination": "/site/new",
"permanent": true
}
Run the app and visit /site/intro to confirm that it redirects to /site/get-started.
For Qwik sites using static-site generation, also known as SSG, you will need to trigger a rebuild for new redirects. To cause this rebuild, use a webhook.
For this part of the tutorial, you need a webhook URL on the backend. If you're using Vercel, visit their Deploy hooks documentation.
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
Create or update the gatsby-node.js file in the root directory:
// gatsby-node.js
const { builder } = require('@builder.io/sdk');
builder.init(/* ADD YOUR PUBLIC API KEY HERE */)
exports.createPages = async ({ actions }) => {
const { createRedirect } = actions;
const results = await builder.getAll('url-redirects');
results.forEach(({ data }) => {
createRedirect({
fromPath: data.sourceUrl,
toPath: data.destinationUrl,
isPermanent: !!data.redirectToPermanent,
});
});
};This setup fetches entries from the url-redirects model using builder.getAll() and registers redirects with Gatsby’s createRedirect() API. Each entry maps as follows:
fromPath: the original URL fromsourceUrltoPath: the redirect target fromdestinationUrlisPermanent:truefor HTTP status code 301,falsefor HTTP status code 302
For example, a redirect created in Builder from /old-page to /new-page with permanent set to true becomes:
{
"fromPath": "/old-page",
"toPath": "/new-page",
"isPermanent": true
}For static builds, a webhook is needed to trigger rebuilds when redirects change. For server-side rendering, redirects update automatically. Check your codebase to determine if you need a webhook or not. If you do need a webhook, follow the instructions below.
To add a Webhook to the data model take the following steps:
- Go to Models.
- Open the URL Redirects model you made in Create a Data model.
- On the Advanced tab, go to Webhooks and click Edit.
- Click + Webhook.
- Expand the new Webhook 1 and paste your webhook URL into the URL field.
- Click Done.
The following video demonstrates how to set up a Webhook:
Create or update the gatsby-node.js file in the root directory:
// gatsby-node.js
const { builder } = require('@builder.io/sdk');
exports.createPages = async ({ actions }) => {
const { createRedirect } = actions;
const results = await fetchEntries({
model: 'url-redirects',
apiKey: /* ADD YOUR PUBLIC API KEY */,
})
results.forEach(({ data }) => {
createRedirect({
fromPath: data.sourceUrl,
toPath: data.destinationUrl,
isPermanent: !!data.redirectToPermanent,
});
});
};This setup fetches entries from the url-redirects model using fetchEntries() and registers redirects with Gatsby’s createRedirect() API. Each entry maps as follows:
fromPath: the original URL fromsourceUrltoPath: the redirect target fromdestinationUrlisPermanent:truefor HTTP status code 301,falsefor HTTP status code 302
For example, a redirect created in Builder from /old-page to /new-page with permanent set to true becomes:
{
"fromPath": "/old-page",
"toPath": "/new-page",
"isPermanent": true
}For static builds, a webhook is needed to trigger rebuilds when redirects change. For server-side rendering, redirects update automatically. Check your codebase to determine if you need a webhook or not. If you do need a webhook, follow the instructions below.
- Learn how to integrate CMS data into your site.
- Review the concepts behind Data models to structure other dynamic data.
In entry.server.tsx, import findRedirectByRequestUrl() and add the redirect logic at the top of the handleRequest() function.