# External Marketing Website in the Next.js Supabase Turbo Starter Kit

> Configure Makerkit to redirect marketing pages to an external website built with Framer, Webflow, or WordPress.

*Canonical: https://makerkit.dev/docs/next-supabase-turbo/development/external-marketing-website*

---

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
