> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hadoseo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Dynamic Sitemaps with Supabase

> Generate dynamic sitemaps for Lovable apps using Supabase Edge Functions

## Overview

Static sitemaps work for simple sites, but if your app has dynamic content (blog posts, products, user profiles), you need a sitemap that updates automatically.

This guide shows you how to create a dynamic sitemap using Supabase Edge Functions in your Lovable project — no manual coding required. Just paste one of the prompts below into Lovable and customize the placeholders.

## When You Need a Dynamic Sitemap

* Blog or content site with new posts
* E-commerce with product pages
* Directory or listing site
* Any app where pages are created from database records

## Prerequisites

* A Lovable project connected to Supabase

## Step 1: Choose the Right Prompt

Pick the prompt that best matches your site, then customize the placeholders (marked with `[BRACKETS]`) before pasting it into Lovable.

<AccordionGroup>
  <Accordion title="Static-Only Sitemap (no database content)" icon="file-lines" defaultOpen>
    Use this if your site has no database-driven pages — just fixed routes like `/about`, `/pricing`, etc.

    ```text theme={null}
    Create a static sitemap.xml file for my site that has no database-dependent pages. Include:

    1. A sitemap.xml file at the public root directory containing:
       - All public pages with their full canonical URLs using [YOUR_DOMAIN]
       - Appropriate lastmod dates (use today's date or actual last modified)
       - changefreq values (daily for homepage, weekly for main pages, monthly for static content)
       - priority values (1.0 for homepage, 0.8 for main sections, 0.6 for subpages)

    2. These pages:
       - Homepage (/)
       - [List all your static pages, e.g., /about, /pricing, /contact, /features, /blog]

    3. Proper XML structure with:
       - XML declaration
       - urlset with xmlns namespace
       - Properly escaped URLs

    Make sure the sitemap validates against the sitemap protocol specification.
    ```
  </Accordion>

  <Accordion title="Hybrid Sitemap (static pages + some dynamic Supabase content)" icon="arrows-split-up-and-left">
    Use this if your site has static pages **and** some dynamic content from Supabase (under 1,000 items per entity).

    ```text theme={null}
    Create a sitemap system for my site that has both static pages and some dynamic
    content from Supabase, but not enough to require pagination (under 1000 items
    per entity).

    1. Create an edge function at /functions/v1/sitemap that:
       - Fetches all dynamic entities from Supabase in a single query per entity
       - Combines with hardcoded static page URLs
       - Returns complete sitemap XML
       - Caches the response for 1 hour
       - Uses canonical domain: [YOUR_DOMAIN]

    2. Include static pages:
       - [List your static pages, e.g., /, /about, /pricing, /contact]

    3. Include dynamic entities:
       - [List your dynamic routes, e.g., blog posts at /blog/[slug]]

    4. For each URL include:
       - loc (full canonical URL)
       - lastmod (from database updated_at or static date)
       - changefreq (based on content type)
       - priority (based on page importance)

    5. Create a static sitemap.xml in public/ using <sitemapindex> that references the edge function URL
    ```
  </Accordion>

  <Accordion title="Backend Function Sitemap (large datasets)" icon="database">
    Use this if you have **1,000+ records** across your entity types (up to 50,000 total URLs).

    ```text theme={null}
    Create a single Supabase edge function at /functions/v1/sitemap that returns
    a complete sitemap with all URLs (up to 50,000). Requirements:

    1. The edge function should:
       - Query all dynamic entities from Supabase
       - Combine with hardcoded static page URLs
       - Return a single <urlset> XML document with all URLs
       - Include proper lastmod dates from updated_at columns
       - Set appropriate changefreq and priority values
       - Cache the response for 1 hour
       - Return proper XML content-type header
       - Use the canonical domain: [YOUR_DOMAIN]

    2. Include static pages:
       - [List your static pages, e.g., /, /about, /pricing, /contact]

    3. Include these dynamic entity types:
       - [List your entities, e.g., /blog/[slug], /products/[id], /users/[username]]

    4. Ensure the total URL count stays under 50,000 (the sitemap protocol limit)

    5. Create a static sitemap.xml in public/ using <sitemapindex> that references the edge function URL
    ```
  </Accordion>

  <Accordion title="Paginated Sitemap (over 50,000 URLs)" icon="layer-group">
    Use this if your total URL count exceeds **50,000** and you need paginated sub-sitemaps.

    ```text theme={null}
    Create a Supabase edge function at /functions/v1/sitemap that returns a
    <sitemapindex> XML document listing paginated sub-sitemap URLs. Requirements:

    1. The /functions/v1/sitemap edge function should:
       - Query entity counts from Supabase to determine pagination
       - Return a <sitemapindex> listing sub-sitemap URLs like:
         /functions/v1/sitemap-posts?page=1, /functions/v1/sitemap-posts?page=2, etc.
       - Include one entry per entity type per page (1000 URLs per page)
       - Cache the response for 1 hour
       - Return proper XML content-type header

    2. For each entity type, create a separate edge function (e.g., /functions/v1/sitemap-posts) that:
       - Accepts a ?page=N query parameter
       - Queries Supabase for that batch of 1000 records
       - Returns a <urlset> XML document with those URLs
       - Includes proper lastmod dates from updated_at columns
       - Sets appropriate changefreq and priority values
       - Uses the canonical domain: [YOUR_DOMAIN]

    3. Include these entity types:
       - [List your entities, e.g., /blog/[slug], /products/[id], /users/[username]]

    4. Create a static sitemap.xml in public/ using <sitemapindex> that references
       the /functions/v1/sitemap edge function URL
    ```

    <Warning>
      Google only follows **one level of nesting** in sitemap indexes. Since your static `sitemap.xml` is a `<sitemapindex>` pointing to another `<sitemapindex>` (the edge function), Google won't discover the paginated sub-sitemaps. You **must** proxy `/sitemap.xml` to your `/functions/v1/sitemap` edge function using Hado SEO's routing rules (see Step 3 below) so that Google sees the paginated sub-sitemaps directly.
    </Warning>
  </Accordion>
</AccordionGroup>

<Tip>
  Replace all `[BRACKETS]` with your actual values before pasting into Lovable. For example, replace `[YOUR_DOMAIN]` with `https://myapp.com` and list your real pages and entity types.
</Tip>

## Step 2: Verify the Edge Function

After Lovable generates and deploys the code, verify it's working:

1. Open your app's `sitemap.xml` and confirm all static URLs or edge function URLs are listed
2. Visit each edge function URL in the sitemap index — each one should return valid XML with your pages

## Step 3: Proxy the Sitemap Through Your Domain

Search engines prefer sitemaps served from your own domain. Use Hado SEO's **routing rules** to proxy `/sitemap.xml` to your Supabase Edge Function — no code changes needed.

<Steps>
  <Step title="Open Routing Rules">
    In your [Hado SEO Dashboard](https://hadoseo.com/dashboard), select your domain and go to the **Routing Rules** tab.
  </Step>

  <Step title="Add a proxy rule">
    Click **Add Rule** and configure:

    | Field       | Value                                                       |
    | ----------- | ----------------------------------------------------------- |
    | Rule Type   | **Proxy**                                                   |
    | Source Path | `/sitemap.xml`                                              |
    | Target URL  | `https://YOUR_PROJECT_REF.supabase.co/functions/v1/sitemap` |
    | Priority    | `10`                                                        |
  </Step>

  <Step title="Verify">
    Visit `https://yourdomain.com/sitemap.xml` in your browser. You should see the XML output from your Supabase function, served from your own domain.
  </Step>
</Steps>

<Info>
  Routing rules are processed by Hado SEO's proxy before your app is hit. The request is forwarded to your Supabase function and the response is returned under your domain — visitors and search engines see `yourdomain.com/sitemap.xml`. Learn more in the [Routing Rules documentation](/dashboard/routing-rules).
</Info>

## Step 4: Test Your Sitemap

### Browser Test

Visit your sitemap URL. You should see properly formatted XML.

### Google Search Console

1. Go to Google Search Console
2. Navigate to Sitemaps
3. Submit your sitemap URL
4. Check for any errors

## Sitemap Best Practices

<AccordionGroup>
  <Accordion title="Keep sitemaps under 50,000 URLs" icon="list-ol">
    Google limits sitemaps to 50,000 URLs or 50MB. For larger sites, use the **Backend Function Sitemap** prompt above, which generates a sitemap index with paginated sub-sitemaps.
  </Accordion>

  <Accordion title="Update lastmod accurately" icon="calendar">
    Only update `lastmod` when content actually changes. Google may ignore sitemaps that update `lastmod` without real changes.
  </Accordion>

  <Accordion title="Include only indexable pages" icon="filter">
    Don't include:

    * Pages blocked by robots.txt
    * Pages with `noindex` meta tag
    * Redirect URLs
    * Login-required pages
  </Accordion>

  <Accordion title="Use proper URL encoding" icon="code">
    Encode special characters in URLs:

    * `&` becomes `&amp;`
    * `<` becomes `&lt;`
    * `>` becomes `&gt;`
    * `"` becomes `&quot;`
    * `'` becomes `&apos;`
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="SEO Optimization" icon="chart-line" href="/guides/seo-optimization">
    Complete SEO checklist for your app
  </Card>
</CardGroup>
