# Customize Marketing Pages in the Tanstack Start Supabase Turbo Starter Kit

> Build and customize landing pages, pricing pages, FAQ, and other marketing content using Tanstack Start App Router and Tailwind CSS.

*Canonical: https://makerkit.dev/docs/tanstack-supabase/development/marketing-pages*

---

Marketing pages in Makerkit live at `apps/web/src/routes/_marketing/` and include landing pages, pricing, FAQ, blog, changelog, and contact forms. These pages use TanStack Router file-based routing for fast initial loads and SEO optimization.

{% sequence title="Marketing Pages Development" description="Customize and extend your marketing pages" %}

[Understand the structure](#marketing-pages-structure)

[Customize existing pages](#customizing-existing-pages)

[Create new marketing pages](#creating-new-marketing-pages)

[Configure navigation and footer](#navigation-and-footer)

{% /sequence %}

## Marketing Pages Structure

The marketing pages follow TanStack Router file-based conventions. The `_marketing` prefix is a pathless layout route — it wraps its children with a shared header/footer layout without adding a URL segment:

```
apps/web/src/routes/_marketing/
├── route.tsx               # Shared layout with header/footer
├── index.tsx               # Home page (/)
├── cookie-policy.tsx       # Legal pages
├── privacy-policy.tsx
├── terms-of-service.tsx
├── contact.tsx             # Contact form
├── faq.tsx                 # FAQ page
├── pricing.tsx             # Pricing page
├── blog/                   # Blog listing and posts
│   ├── index.tsx
│   └── $slug.tsx
└── changelog/              # Product changelog
    ├── index.tsx
    └── $slug.tsx
```

Shared marketing components (header, footer, navigation) live in `apps/web/src/components/marketing/`.

### Pathless Layout Routes Explained

The `_marketing` folder is a pathless layout route: the leading underscore means it shares `route.tsx`'s layout without contributing a URL segment. Pages inside render at the root level:

| File Path | URL |
|-----------|-----|
| `_marketing/index.tsx` | `/` |
| `_marketing/pricing.tsx` | `/pricing` |
| `_marketing/blog/index.tsx` | `/blog` |

## Customizing Existing Pages

### Home Page

The home page at `apps/web/src/routes/_marketing/index.tsx` typically includes:

```tsx {% title="apps/web/src/routes/_marketing/index.tsx" %}
import { createFileRoute } from '@tanstack/react-router';

import { Hero } from '#/components/marketing/hero.tsx';
import { Features } from '#/components/marketing/features.tsx';
import { Testimonials } from '#/components/marketing/testimonials.tsx';
import { Pricing } from '#/components/marketing/pricing-section.tsx';
import { CallToAction } from '#/components/marketing/call-to-action.tsx';

export const Route = createFileRoute('/_marketing/')({
  component: Home,
});

function Home() {
  return (
    <>
      <Hero />
      <Features />
      <Testimonials />
      <Pricing />
      <CallToAction />
    </>
  );
}
```

Each section is a separate component in `components/marketing/` for easy customization.

### Pricing Page

The pricing page displays your billing plans. It reads configuration from `apps/web/src/config/billing.config.ts`:

```tsx {% title="apps/web/src/routes/_marketing/pricing.tsx" %}
import { createFileRoute } from '@tanstack/react-router';

import { PricingTable } from '@kit/billing-gateway/marketing';

import billingConfig from '#/config/billing.config.ts';
import pathsConfig from '#/config/paths.config.ts';

const paths = {
  signUp: pathsConfig.auth.signUp,
  return: pathsConfig.app.home,
};

export const Route = createFileRoute('/_marketing/pricing')({
  component: PricingPage,
});

function PricingPage() {
  return (
    <div className="container mx-auto py-16">
      <h1 className="text-4xl font-bold text-center mb-4">
        Simple, Transparent Pricing
      </h1>
      <p className="text-muted-foreground text-center mb-12">
        Choose the plan that fits your needs
      </p>

      <PricingTable config={billingConfig} paths={paths} />
    </div>
  );
}
```

See [Billing Configuration](/docs/tanstack-supabase/billing/overview) for customizing plans and pricing.

### FAQ Page

The FAQ page uses an accordion component with content from a configuration file or CMS:

```tsx {% title="apps/web/src/routes/_marketing/faq.tsx" %}
import { createFileRoute } from '@tanstack/react-router';

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from '@kit/ui/accordion';

const faqs = [
  {
    question: 'How do I get started?',
    answer: 'Sign up for a free account and follow our getting started guide.',
  },
  {
    question: 'Can I cancel anytime?',
    answer: 'Yes, you can cancel your subscription at any time with no penalties.',
  },
  // ... more FAQs
];

export const Route = createFileRoute('/_marketing/faq')({
  component: FAQPage,
});

function FAQPage() {
  return (
    <div className="container mx-auto max-w-3xl py-16">
      <h1 className="text-4xl font-bold text-center mb-12">
        Frequently Asked Questions
      </h1>

      <Accordion type="single" collapsible>
        {faqs.map((faq, index) => (
          <AccordionItem key={index} value={`item-${index}`}>
            <AccordionTrigger>{faq.question}</AccordionTrigger>
            <AccordionContent>{faq.answer}</AccordionContent>
          </AccordionItem>
        ))}
      </Accordion>
    </div>
  );
}
```

### Contact Page

The contact page includes a form that sends emails via your configured mailer:

```tsx {% title="apps/web/src/routes/_marketing/contact.tsx" %}
import { createFileRoute } from '@tanstack/react-router';

import { ContactForm } from '#/components/marketing/contact-form.tsx';

export const Route = createFileRoute('/_marketing/contact')({
  component: ContactPage,
});

function ContactPage() {
  return (
    <div className="container mx-auto max-w-xl py-16">
      <h1 className="text-4xl font-bold text-center mb-4">
        Contact Us
      </h1>
      <p className="text-muted-foreground text-center mb-8">
        Have a question? We'd love to hear from you.
      </p>

      <ContactForm />
    </div>
  );
}
```

#### Contact Form Configuration

Configure the recipient email address in your environment:

```bash {% title=".env.local" %}
CONTACT_EMAIL=support@yourdomain.com
```

The form submission uses your [email configuration](/docs/tanstack-supabase/emails/email-configuration). Ensure your mailer is configured before the contact form will work.

## Creating New Marketing Pages

### Basic Page Structure

Create a route file. Add a new `.tsx` file under `apps/web/src/routes/_marketing/` and set metadata with the route `head` option:

```tsx {% title="apps/web/src/routes/_marketing/about.tsx" %}
import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/_marketing/about')({
  head: () => ({
    meta: [
      { title: 'About Us | Your SaaS Name' },
      {
        name: 'description',
        content:
          'Learn about our mission, team, and the story behind our product.',
      },
    ],
  }),
  component: AboutPage,
});

function AboutPage() {
  return (
    <div className="container mx-auto py-16">
      <h1 className="text-4xl font-bold mb-8">About Us</h1>

      <div className="prose prose-gray max-w-none">
        <p>Your company story goes here...</p>
      </div>
    </div>
  );
}
```

After adding a route file, regenerate the route tree:

```bash
pnpm --filter web generate-routes
```

### Content-Heavy Pages

For long-form content that non-developers should be able to edit, source the content from the CMS instead of hardcoding it (see the "Dynamic Pages with Data" example below and the [CMS documentation](/docs/tanstack-supabase/content/cms)).

### Dynamic Pages with Data

For pages that need dynamic data, fetch it in the route `loader` and render it in the component:

```tsx {% title="apps/web/src/routes/_marketing/customers.tsx" %}
import { createFileRoute } from '@tanstack/react-router';

import { createCmsClient } from '@kit/cms';

export const Route = createFileRoute('/_marketing/customers')({
  loader: async () => {
    const cms = await createCmsClient();

    const caseStudies = await cms.getContentItems({
      collection: 'case-studies',
      limit: 10,
    });

    return { caseStudies };
  },
  component: CustomersPage,
});

function CustomersPage() {
  const { caseStudies } = Route.useLoaderData();

  return (
    <div className="container mx-auto py-16">
      <h1 className="text-4xl font-bold mb-12">Customer Stories</h1>

      <div className="grid md:grid-cols-2 gap-8">
        {caseStudies.items.map((study) => (
          <CaseStudyCard key={study.slug} {...study} />
        ))}
      </div>
    </div>
  );
}
```

## Navigation and Footer

### Header Navigation

Configure navigation links in the header component:

```tsx {% title="apps/web/src/components/marketing/site-navigation.tsx" %}
const navigationItems = [
  { label: 'Features', href: '/#features' },
  { label: 'Pricing', href: '/pricing' },
  { label: 'Blog', href: '/blog' },
  { label: 'Docs', href: '/docs' },
  { label: 'Contact', href: '/contact' },
];
```

### Footer Links

The footer typically includes multiple link sections:

```tsx {% title="apps/web/src/components/marketing/site-footer.tsx" %}
const footerSections = [
  {
    title: 'Product',
    links: [
      { label: 'Features', href: '/#features' },
      { label: 'Pricing', href: '/pricing' },
      { label: 'Changelog', href: '/changelog' },
    ],
  },
  {
    title: 'Resources',
    links: [
      { label: 'Documentation', href: '/docs' },
      { label: 'Blog', href: '/blog' },
      { label: 'FAQ', href: '/faq' },
    ],
  },
  {
    title: 'Legal',
    links: [
      { label: 'Privacy Policy', href: '/privacy-policy' },
      { label: 'Terms of Service', href: '/terms-of-service' },
      { label: 'Cookie Policy', href: '/cookie-policy' },
    ],
  },
];
```

### Customizing the Layout

All marketing pages inherit from the pathless layout route at `apps/web/src/routes/_marketing/route.tsx`. This layout includes:

- Header with navigation
- Footer with links
- Shared structure via `<Outlet />`

Edit this file to change the shared structure across all marketing pages.

## SEO for Marketing Pages

### Route head option

Set SEO metadata with the route `head` option:

```tsx {% title="apps/web/src/routes/_marketing/pricing.tsx" %}
export const Route = createFileRoute('/_marketing/pricing')({
  head: () => ({
    meta: [
      { title: 'Pricing | Your SaaS Name' },
      {
        name: 'description',
        content:
          'Choose from flexible pricing plans. Start free, upgrade when ready.',
      },
      { property: 'og:title', content: 'Pricing | Your SaaS Name' },
      {
        property: 'og:description',
        content: 'Choose from flexible pricing plans.',
      },
      { property: 'og:image', content: '/images/og/pricing.png' },
    ],
  }),
  component: PricingPage,
});
```

### Structured Data

Add JSON-LD structured data for rich search results by rendering a `<script type="application/ld+json">` tag inside the route component:

```tsx
function PricingPage() {
  return (
    <>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{
          __html: JSON.stringify({
            '@context': 'https://schema.org',
            '@type': 'Product',
            name: 'Your SaaS Name',
            offers: {
              '@type': 'AggregateOffer',
              lowPrice: '0',
              highPrice: '99',
              priceCurrency: 'USD',
            },
          }),
        }}
      />
      {/* Page content */}
    </>
  );
}
```

### Sitemap

Add new marketing pages to your sitemap by extending the `STATIC_PATHS` array in `apps/web/src/routes/sitemap[.]xml.ts`:

```typescript
const STATIC_PATHS = [
  '/',
  '/pricing',
  '/faq',
  '/blog',
  '/docs',
  '/contact',
  '/about', // Add new pages here
];
```

## Related Resources

- [SEO Configuration](/docs/tanstack-supabase/development/seo) for detailed SEO setup
- [Legal Pages](/docs/tanstack-supabase/development/legal-pages) for privacy policy and terms
- [CMS Setup](/docs/tanstack-supabase/content/cms) for blog configuration
- [Email Configuration](/docs/tanstack-supabase/emails/email-configuration) for contact form setup
