StartupKitstartupkit
SEO

Sitemaps

How to generate sitemaps for search engine discovery

Sitemaps help search engines discover and index your pages. The generateSitemap function creates a Next.js-compatible sitemap.

Basic Usage

app/sitemap.ts
import {  } from "@startupkit/seo"

export default function () {
  return ({
    : "https://myapp.com",
    : [
      { : "/" },
      { : "/about" },
      { : "/pricing" },
      { : "/blog" },
      { : "/contact" }
    ]
  })
}

This generates /sitemap.xml:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://myapp.com/</loc>
    <lastmod>2024-01-15</lastmod>
    <changefreq>daily</changefreq>
    <priority>1</priority>
  </url>
  <url>
    <loc>https://myapp.com/about</loc>
    <lastmod>2024-01-15</lastmod>
    <changefreq>daily</changefreq>
    <priority>1</priority>
  </url>
  ...
</urlset>

Route Configuration

Basic Route

{ path: "/about" }

With Priority

Higher priority pages (0.0 to 1.0):

{ path: "/", priority: 1.0 },      // Homepage - highest
{ path: "/pricing", priority: 0.9 },
{ path: "/about", priority: 0.8 },
{ path: "/contact", priority: 0.5 }

With Change Frequency

How often the page changes:

{ path: "/", changeFrequency: "daily" },
{ path: "/blog", changeFrequency: "weekly" },
{ path: "/about", changeFrequency: "monthly" },
{ path: "/terms", changeFrequency: "yearly" }

Options: always, hourly, daily, weekly, monthly, yearly, never

With Last Modified

{ 
  path: "/blog/my-post", 
  lastModified: new Date("2024-01-15") 
}

Dynamic Sitemaps

Blog Posts

app/sitemap.ts
import {  } from "@startupkit/seo"
import {  } from "@repo/db"

export default async function () {
  const  = await .query.posts.findMany({
    : { : true, : true }
  })

  const  = .map( => ({
    : `/blog/${.slug}`,
    : .updatedAt,
    : "weekly" as ,
    : 0.7
  }))

  return ({
    : "https://myapp.com",
    : [
      { : "/", : 1.0 },
      { : "/blog", : 0.9 },
      ...
    ]
  })
}

Product Pages

app/sitemap.ts
import {  } from "@startupkit/seo"

export default async function () {
  const  = await fetchProducts()

  const  = .map( => ({
    : `/products/${.slug}`,
    : .updatedAt,
    : 0.8
  }))

  return ({
    : "https://myapp.com",
    : [
      { : "/", : 1.0 },
      { : "/products", : 0.9 },
      ...
    ]
  })
}

Multiple Sitemaps (Sitemap Index)

For large sites with more than 50,000 URLs, split into multiple sitemaps using Next.js's built-in sitemap index support:

app/sitemap.ts
import type { MetadataRoute } from "next"
declare function (): <number>
declare function (: { : number; : number }): <{ : string; : Date }[]>

export async function () {
  const  = await ()
  const  = .( / 50000)
  
  return .({ :  }, (, ) => ({ :  }))
}

export default async function ({ 
   
}: { 
  : number 
}): <MetadataRoute.> {
  const  =  * 50000
  const  = await ({ , : 50000 })
  
  return .( => ({
    : `https://myapp.com/products/${.}`,
    : .
  }))
}

This automatically generates:

  • /sitemap.xml — the sitemap index listing all child sitemaps
  • /sitemap/0.xml, /sitemap/1.xml, etc. — individual sitemaps with up to 50,000 URLs each

Category-Based Sitemaps

You can also organize sitemaps by content type:

app/sitemap.ts
import type { MetadataRoute } from "next"
declare function (): <{ : string; : Date }[]>
declare function (): <{ : string; : Date }[]>

const  = ["main", "blog", "products"] as 

export async function () {
  return .( => ({  }))
}

export default async function ({ 
   
}: { 
  : string 
}): <MetadataRoute.> {
  switch () {
    case "main":
      return [
        { : "https://myapp.com", : 1.0 },
        { : "https://myapp.com/about", : 0.8 },
        { : "https://myapp.com/pricing", : 0.9 }
      ]
    case "blog":
      const  = await ()
      return .( => ({
        : `https://myapp.com/blog/${.}`,
        : .
      }))
    case "products":
      const  = await ()
      return .( => ({
        : `https://myapp.com/products/${.}`,
        : .
      }))
    default:
      return []
  }
}

## Parameters

### generateSitemap

```tsx
generateSitemap({
  baseUrl: string,   // Full base URL (e.g., "https://myapp.com")
  routes: SitemapRoute[]
})

SitemapRoute

FieldTypeDefaultDescription
pathstringRequiredURL path (e.g., /about)
lastModifiedDatenew Date()Last modification date
changeFrequencystring"daily"How often page changes
prioritynumber1Importance (0.0 - 1.0)

Best Practices

Priority Guidelines

Page TypePriority
Homepage1.0
Core pages (pricing, features)0.9
Product/category pages0.8
Blog posts0.7
Support/docs0.6
Legal pages0.3

Exclude Pages

Don't include in sitemap:

  • Auth pages (/sign-in, /sign-up)
  • Dashboard/app pages
  • API routes
  • Error pages (/404, /500)
  • Redirects

Keep Updated

Update lastModified when content changes:

const  = await .query.posts.findMany()

const  = .map( => ({
  : `/blog/${.slug}`,
  : .updatedAt  // Actual update date
}))

Submitting to Search Engines

Google Search Console

  1. Go to Search Console
  2. Add your property
  3. Navigate to Sitemaps
  4. Enter sitemap.xml
  5. Click Submit

Bing Webmaster Tools

  1. Go to Bing Webmaster
  2. Add your site
  3. Submit sitemap URL

robots.txt Reference

Include sitemap in robots.txt:

Sitemap: https://myapp.com/sitemap.xml

See Robots.txt for more.

Debugging

Check Sitemap

Visit https://myapp.com/sitemap.xml directly.

Validate Format

Use XML Sitemap Validator.

Check in Search Console

Google Search Console shows sitemap status and any errors.

Next Steps

On this page