Skip to content

Usage

Here are the general steps you’ll need

  1. Create your Cartographer instance
  2. Add your pages
  3. Generate your toolbelt
  4. Create a sitemap index page
  5. Create your sitemap entry page

Create your Cartographer instance

import { Cartographer } from "@modules/cartographer"
const sitemap = new Cartographer({
domain: "https://your-domain.com"
})

Parameters

  • domain (required): The domain for your site, it will be prepended to all your slugs.
  • urlsPerPage (optional): The maximum number of sitemap entries you want per page. The maxiumum recommended by Google is 50,000, the package default is 10,000.
  • priorityFn (optional): A method for generating the entry priority property. Default to a method returning 0.7.
  • defaultChangeFrequency (optional): The default changefreq property. Defaults to weekly.
  • defaultLastMod (optional): The default lastmod property. Defaults to new Date(). If a string is provided, it will be used as is.
  • logger (optional): A object with a error key used for logging errors. By default it’ll use console.error.

Add your pages

sitemap returns a instance of a class with 3 methods. To add pages you can use the static or dynamic methods. The class implements the builder pattern, meaning you can chain these calls together or easily add a page based on some conditional (think multi-sites where certain categories of pages are not available).

As the names suggests, static is for static “hardcoded” URLs, while dynamic allows you to fetch the data from somewhere.

import { Cartographer } from "@modules/cartographer"
const sitemap = new Cartographer({
domain: "https://your-domain.com"
})
sitemap.static('common', ['/', '/events'])
sitemap.dynamic('events', {
fetcher: async (page, count, urlsPerPage) => {},
counter: async () => {}
})

static

The first key is the name used for the sitemap page, in the case above a /api/v1/sitemap/common.xml route will become available.

The second key are the routes you want to add to the sitemap. This can either be a string or a SitemapEntry if you want some more control over some of the values, if you didn’t want the defaults to apply.

dynamic

The first key is the name used for the sitemap page, in the case above a /api/v1/sitemap/events/0.xml route will become available.

The second parameter is a object with 2 keys.

  1. fetcher - takes in the current page, total count (from the counter) and maximum number of pages that can be on the page. You can use the count and urlsPerPage to figure out API offset values. The function should return a list of SitemapEntry records.
  2. counter - this function should return the total number of records for this category. This will use the urlsPerPage to determine how many individual pages this category needs. Imagine a SELECT count(*) FROM events; type query.

Generate your toolbelt

Once you’re happy with your setup, you can create the toolbelt by running the finalise method on the Cartographer instance.

const sitemap = new Cartographer({...}).static().dynamic()
export const cartographer = sitemap.finalise()

This create a CartographerToolbelt instance and is what you’ll use moving forward, so I recommend exporting it from your file.

Steps 4 & 5

There are 2 methods on this toolbelt;

  1. $survey - generates a Response for the sitemap index
  2. $draw - generates a Response for the individual pages

Depending on the framework used, how you implement these may vary. Here are some general rules using Next.js App Directory as an example.

  1. Create a sitemap.xml/route.ts file. It should export a GET method and return the response directly.
  2. Create a dynamic route at /api/v1/sitemap/[key]/[[...page]]/route.ts. It should export a GET method and return the response directly.
  • Directoryapp
    • Directorysitemap.xml
      • route.ts
    • Directoryapi/v1/sitemap/[key]/[[…page]]
      • route.ts
sitemap.xml/route.ts
import { cartographer } from "@/modules/domain/sitemap"
export function GET() {
return cartographer.$survey()
}

Since Next.js App Directory supports returning a Response object, we can simply return it directly. The only part you want to keep in mind is that the $draw command takes in a unknown first parameter. This is a placeholder for a Request value that might become useful in the future. The second requires a object that has params with this following shape.

export type Segment = {
params: Promise<{
key: string
page?: string[]
}>
}

It mimics the new Next v15 promise based parameters. Regardless of your framework you should be able to replicate this structure, if your params don’t come in as a Promise you can always wrap it in a Promise.resolve.

Weird API urls?

The individual sitemap pages do have weird API urls that needs to be taken care of to make them a bit more “readable”. Your framework may be able to handle this by tweaking where you place the file. With Next, you can use the rewrites property in the next.config file.

next.config.mjs
const nextConfig = {
rewrites: () => [
{
source: "/sitemap/:path*",
destination: "/api/v1/sitemap/:path*",
}
],
}

Framework Guides