--- status: "published" label: "External Marketing Website" title: "External Marketing Website in the Next.js Supabase Turbo Starter Kit" description: "Configure Makerkit to redirect marketing pages to an external website built with Framer, Webflow, or WordPress." order: 9 --- Redirect Makerkit's marketing pages to an external website by configuring the `proxy.ts` middleware. This lets you use Framer, Webflow, or WordPress for your marketing site while keeping Makerkit for your SaaS application. {% sequence title="External Marketing Website Setup" description="Configure redirects to your external marketing site" %} [Understand the architecture](#when-to-use-an-external-marketing-website) [Configure the middleware](#configuring-the-middleware) [Handle subpaths and assets](#handling-subpaths-and-assets) [Verify the redirects](#verify-the-redirects) {% /sequence %} ## When to Use an External Marketing Website Use an external marketing website when: - **Marketing team independence**: Your marketing team needs to update content without developer involvement - **Design flexibility**: You want visual builders like Framer or Webflow for landing pages - **Content management**: WordPress or a headless CMS better fits your content workflow - **A/B testing**: Your marketing tools integrate better with external platforms Keep marketing pages in Makerkit when: - You want a unified codebase and deployment - Your team is comfortable with React and Tailwind - You need tight integration between marketing and app features ## Configuring the Middleware {% alert type="default" title="Next.js 16+" %} In Next.js 16+, Makerkit uses `proxy.ts` for middleware. Prior versions used `middleware.ts`. {% /alert %} Edit `apps/web/proxy.ts` to redirect marketing pages: ```typescript {% title="apps/web/proxy.ts" %} import type { NextRequest } from 'next/server'; import { NextResponse } from 'next/server'; const EXTERNAL_MARKETING_URL = 'https://your-marketing-site.com'; const MARKETING_PAGES = [ '/', '/pricing', '/faq', '/contact', '/about', '/blog', '/privacy-policy', '/terms-of-service', '/cookie-policy', ]; export function proxy(req: NextRequest) { if (isMarketingPage(req)) { const redirectUrl = new URL( req.nextUrl.pathname, EXTERNAL_MARKETING_URL ); // Preserve query parameters redirectUrl.search = req.nextUrl.search; return NextResponse.redirect(redirectUrl, { status: 301 }); } // Continue with existing middleware logic return NextResponse.next(); } function isMarketingPage(req: NextRequest): boolean { const pathname = req.nextUrl.pathname; return MARKETING_PAGES.some((page) => { if (page === '/') { return pathname === '/'; } return pathname === page || pathname.startsWith(`${page}/`); }); } ``` ### Configuration Options | Option | Description | |--------|-------------| | `EXTERNAL_MARKETING_URL` | Your external marketing site's base URL | | `MARKETING_PAGES` | Array of paths to redirect | | Status code `301` | Permanent redirect (SEO-friendly) | | Status code `302` | Temporary redirect (for testing) | ## Handling Subpaths and Assets ### Blog Posts with Dynamic Paths If your blog uses dynamic paths like `/blog/post-slug`, handle them separately: ```typescript const MARKETING_PAGES = [ // ... other pages ]; const MARKETING_PREFIXES = [ '/blog', '/resources', '/case-studies', ]; function isMarketingPage(req: NextRequest): boolean { const pathname = req.nextUrl.pathname; // Check exact matches if (MARKETING_PAGES.includes(pathname)) { return true; } // Check prefix matches return MARKETING_PREFIXES.some((prefix) => pathname.startsWith(prefix) ); } ``` ### Excluding Application Routes Keep certain routes in Makerkit even if they share a marketing prefix: ```typescript const APP_ROUTES = [ '/blog/admin', // Blog admin panel stays in Makerkit '/pricing/checkout', // Checkout flow stays in Makerkit ]; function isMarketingPage(req: NextRequest): boolean { const pathname = req.nextUrl.pathname; // Never redirect app routes if (APP_ROUTES.some((route) => pathname.startsWith(route))) { return false; } // ... rest of the logic } ``` ## Verify the Redirects After configuring, verify redirects work correctly: ```bash # Start the development server pnpm run dev # Test a redirect (should return 301) curl -I http://localhost:3000/pricing ``` Expected output: ``` HTTP/1.1 301 Moved Permanently Location: https://your-marketing-site.com/pricing ``` ### Common Issues **Redirect loops**: Ensure your external site doesn't redirect back to Makerkit. **Missing query parameters**: The example code preserves query params. Verify UTM parameters pass through correctly. **Asset requests**: Don't redirect asset paths like `/images/` or `/_next/`. The middleware should only match page routes. ## Environment-Based Configuration Use environment variables for different environments: ```typescript {% title="apps/web/proxy.ts" %} const EXTERNAL_MARKETING_URL = process.env.EXTERNAL_MARKETING_URL; export function proxy(req: NextRequest) { // Only redirect if external URL is configured if (!EXTERNAL_MARKETING_URL) { return NextResponse.next(); } // ... redirect logic } ``` ```bash {% title=".env.production" %} EXTERNAL_MARKETING_URL=https://your-marketing-site.com ``` This lets you keep marketing pages in Makerkit during development while redirecting in production. ## Related Resources - [Marketing Pages](/docs/next-supabase-turbo/development/marketing-pages) for customizing built-in marketing pages - [SEO Configuration](/docs/next-supabase-turbo/development/seo) for sitemap and meta tag setup - [Legal Pages](/docs/next-supabase-turbo/development/legal-pages) for privacy policy and terms pages