# How to create a sitemap: by CMS, by generator or by hand

> How to create a sitemap for any site: check whether your CMS already makes one, switch it on in WordPress, Shopify, Wix or a framework, generate one by crawling, or write the XML yourself, then publish and submit it.

Updated 2026-09-26 · Technical SEO · HTML version: https://getreport.app/guides/how-to-create-an-xml-sitemap

To create a sitemap, first check whether your platform already makes one; WordPress, Shopify, Wix, Squarespace, Webflow and most frameworks do. If it does, switch it on and tidy what it lists. If not, generate a sitemap.xml by crawling your site, or write the XML yourself, then upload it to the site root, declare it in robots.txt and submit it in Google Search Console. This guide walks through each route, from a five-minute setting to a small script. For what a sitemap is and what belongs in it, see the [XML sitemap guide](https://getreport.app/guides/xml-sitemap).

## Quick answer

- **Check first:** open `yourdomain/robots.txt` and look for a `Sitemap:` line, then try `/sitemap.xml`, `/sitemap_index.xml` and `/wp-sitemap.xml`.
- **WordPress:** core makes `/wp-sitemap.xml`; Yoast SEO or Rank Math replace it with `/sitemap_index.xml`. Use one.
- **Shopify, Wix, Squarespace, Webflow:** the platform builds `/sitemap.xml` for you.
- **Frameworks:** Next.js, Astro, Hugo and Gatsby build the sitemap from your page list at build time.
- **No CMS:** run a [sitemap generator](https://getreport.app/tools/sitemap-generator) that crawls the site, or write the file by hand from the [sitemap examples](https://getreport.app/guides/xml-sitemap-example).
- **Then:** upload to the root, add `Sitemap: https://yourdomain/sitemap.xml` to robots.txt, submit in Search Console, and validate.

## Step 1: check whether you already have a sitemap

Most sites already have a sitemap and do not know it. Before building anything, look in three places:

1. **robots.txt.** Open `https://yourdomain/robots.txt` and look for lines starting with `Sitemap:`. That is where a site states its sitemap address.
2. **The usual paths.** Try `/sitemap.xml`, `/sitemap_index.xml` and `/wp-sitemap.xml` in the browser.
3. **Search Console.** Under Indexing → Sitemaps, the table lists any sitemap already submitted for your property.

If one of them answers with a list of URLs, you have a sitemap and the job is to check it, not to create a second one. Two sitemaps from two sources list different URL forms and send mixed signals. The guide to [finding a website's sitemap](https://getreport.app/guides/how-to-find-sitemap-of-a-website) lists the default address for each platform.

## Step 2: pick the route that fits your site

| Your site | How the sitemap gets made | Effort |
| --- | --- | --- |
| WordPress | Core, or your SEO plugin | A setting |
| Shopify | Automatic, not editable | None |
| Wix, Squarespace, Webflow | Automatic, some settings | None or a toggle |
| Next.js, Astro, Hugo, Gatsby | Built with the site | A file or a plugin |
| Drupal, Joomla, Magento | A module, extension or built-in setting | A module and its settings |
| Hand-written HTML or a legacy CMS | A generator that crawls, or a script | 10 minutes to an hour |

The rule for every route: the sitemap should update itself when pages are added or removed. A file generated once and uploaded by hand goes stale with the first new page.

## Create a sitemap in a CMS

### WordPress

Since version 5.5, WordPress publishes a sitemap index at `/wp-sitemap.xml` with no plugin, with child sitemaps for posts, pages, categories, tags and authors. It is switched off automatically when Settings → Reading → "Discourage search engines from indexing this site" is ticked, which is a common reason a new site has none.

If you use Yoast SEO or Rank Math, the plugin turns the core sitemap off and publishes its own at `/sitemap_index.xml`, with settings to leave out post types and archives you do not want indexed. In Yoast it is under Yoast SEO → Settings → Site features → XML sitemaps. [WordPress sitemaps](https://getreport.app/guides/wordpress-sitemap) compares the core sitemap with the plugin ones and shows what to switch off.

### Shopify

Every Shopify store has an automatic `/sitemap.xml`: an index with child sitemaps for products, collections, pages and blog posts. You cannot edit it, and there is nothing to create; only items published to the Online Store appear in it. [Shopify's sitemap](https://getreport.app/guides/shopify-sitemap) covers what it includes and how to keep a page out of it.

### Wix, Squarespace and Webflow

Wix and Squarespace generate `/sitemap.xml` automatically and update it when you publish. Webflow builds one when "Auto-generate sitemap" is on in the site settings' SEO tab, and lets you exclude individual pages from it in each page's settings. In Wix and Squarespace, a page you hide from search engines in its SEO settings is left out of the sitemap; in Webflow, switch off the page's sitemap setting as well as hiding it from search engines.

### Drupal, Joomla and Magento

Drupal has no sitemap in core; the Simple XML Sitemap module is the usual choice. Joomla needs an extension. Magento and Adobe Commerce generate sitemaps under Marketing → SEO & Search → Site Map, with a generation schedule under Stores → Configuration → Catalog → XML Sitemap so they regenerate automatically. Whichever you use, set it to regenerate on a schedule or on publish.

## Create a sitemap in a framework or static site

Framework sitemaps are built from the same page list as the site, so they stay correct as long as the build runs.

**Next.js (App Router).** Add `app/sitemap.ts`; Next.js serves its output at `/sitemap.xml`:

```ts
// app/sitemap.ts
import type { MetadataRoute } from 'next';
import { getAllPages } from '@/lib/pages';

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const pages = await getAllPages();
  return pages.map((p) => ({
    url: `https://example.com${p.path}`,
    lastModified: p.updatedAt,
  }));
}
```

**Astro.** Add the `@astrojs/sitemap` integration and set `site` in `astro.config.mjs`. The build writes `sitemap-index.xml` and one or more `sitemap-0.xml` files; point robots.txt at the index.

**Hugo** writes `sitemap.xml` on every build with no setup. **Gatsby** uses `gatsby-plugin-sitemap`. For other static site generators, search for a sitemap plugin before writing your own; most have one.

In each case, filter out draft, `noindex` and redirect pages in the code, and use the content's real modification date for `lastModified`, not the build time. The [static sites guide](https://getreport.app/guides/netlify-and-vercel-headers-and-caching) covers the headers and caching for the same stacks.

## Create a sitemap with a generator

A site without a CMS, or with one that has no sitemap, can use a generator that crawls it the way a search engine does.

> **Free tool:** [XML sitemap generator: crawl your site](https://getreport.app/tools/sitemap-generator): Free XML sitemap generator that crawls up to 100 pages and keeps only live, indexable, canonical URLs. It runs while donations cover its server time.

getReport's XML sitemap generator starts at the page you enter, reads robots.txt first, and follows same-site links up to 100 pages and 10 clicks deep. It keeps only pages that answer 200, have no `noindex` and are canonical to themselves, and lists every page it left out with the reason. It uses your server's `Last-Modified` header for `<lastmod>` when there is one, and writes no priority or changefreq. You can copy the XML, download `sitemap.xml` or download a CSV of every URL found.

Two limits to know. It reads the HTML your server sends, so pages reachable only through JavaScript, forms or search are not found. And crawling costs server time, so the generator is a funded unlock: it runs for everyone while donations cover it, and shows an example crawl when they do not.

A generated file is a snapshot. When you add pages, run it again and upload the new file, or move to a CMS or build step that updates the sitemap itself.

## Create a sitemap by hand

For a site of a few dozen pages that rarely changes, writing the file takes ten minutes.

1. Open a plain text editor (not a word processor) and save a new file as `sitemap.xml` with UTF-8 encoding.
2. Paste the skeleton and add one `<url>` per page:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/</loc>
    <lastmod>2026-09-20</lastmod>
  </url>
  <url>
    <loc>https://example.com/services/</loc>
  </url>
</urlset>
```

3. Use the full address of each page exactly as you link to it: `https`, the same host, the same trailing slash.
4. Write `&` in a URL as `&amp;`.
5. Add `<lastmod>` only if you know the date the page last changed.

The [sitemap examples](https://getreport.app/guides/xml-sitemap-example) show image, video, news and hreflang entries and the format rules line by line.

### With a short script

If the page list lives in a database or a spreadsheet, a script can write the file every time the list changes. A minimal Python version that reads `pages.csv` with `path,updated` columns:

```python
# make_sitemap.py: writes sitemap.xml from pages.csv
import csv
from xml.sax.saxutils import escape

rows = list(csv.DictReader(open("pages.csv", encoding="utf-8")))
with open("sitemap.xml", "w", encoding="utf-8") as f:
    f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
    f.write('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n')
    for r in rows:
        f.write("  <url>\n")
        f.write(f"    <loc>{escape('https://example.com' + r['path'])}</loc>\n")
        if r.get("updated"):
            f.write(f"    <lastmod>{r['updated']}</lastmod>\n")
        f.write("  </url>\n")
    f.write("</urlset>\n")
```

`escape` turns `&`, `<` and `>` into entities, so query strings do not break the XML. Above 50,000 rows, write several files and an index, as described in [sitemap index files](https://getreport.app/guides/sitemap-index-files-splitting-large-sitemaps).

## Step 3: publish, declare and submit it

1. **Upload** the file to the site root so it answers at `https://yourdomain/sitemap.xml` with status 200 and an XML content type. A sitemap in a subfolder may only list URLs under that folder unless you submit it in Search Console.
2. **Declare it** in robots.txt with the full address, on its own line: `Sitemap: https://yourdomain/sitemap.xml`. Crawlers that read robots.txt find it without an account.
3. **Submit it** once in Google Search Console under Indexing → Sitemaps, and in Bing Webmaster Tools. [How to submit a sitemap to Google](https://getreport.app/guides/submit-sitemap-to-google) shows each screen and what the statuses mean.

There is no need to resubmit after each update. Google rereads submitted sitemaps on its own schedule, and its old "ping" endpoint was retired at the end of 2023.

## Step 4: validate the result

> **Free tool:** [Sitemap checker: validate your XML sitemap](https://getreport.app/tools/sitemap-validator): Free sitemap checker: find your XML sitemap, validate it against the sitemaps.org protocol, count its URLs and test a sample of the listed pages. No sign-up.

Run the sitemap checker on your site as soon as the file is live. It finds sitemaps through robots.txt and `/sitemap.xml`, validates the XML against the protocol and requests up to 25 listed URLs to confirm they answer 200 without redirecting. It also tells you whether the page you entered is listed.

> **Check: XML sitemap is reachable.** A sitemap lists every page you want indexed and when it changed. Without one, crawlers must find pages by following links, and deep or new pages can wait weeks.
>
> 1. Generate an XML sitemap and publish it at /sitemap.xml (most CMSs and SEO plugins do this automatically).
> 2. Make sure it returns HTTP 200 and lists at least one URL; then declare it in robots.txt and submit it in Google Search Console.

> **Check: Sitemap URL status.** A sitemap should list only pages that answer 200. Redirects, 404s and noindex pages in it waste crawl budget and make Google trust the file less.
>
> 1. Remove deleted pages from the sitemap and list the final URL of redirected pages.
> 2. Most CMS plugins do this automatically; if you generate the file yourself, rebuild it from the live URL list before publishing.

## Common mistakes

- **Creating a second sitemap next to the one the CMS already makes.** Keep one source, and delete an old uploaded `sitemap.xml` that now shadows the plugin's.
- **Listing every URL the server can answer,** including redirects, `noindex` archives, cart pages and URLs with tracking parameters. List only the pages you want in search results.
- **Relative URLs** such as `/about/`. Every `<loc>` needs the protocol and host.
- **Stamping every URL with today's date** on each build. Use the content's real modification date, or no date.
- **A sitemap on a staging host** that lists staging URLs and gets copied to production. Check the host in `<loc>` after every launch.
- **Blocking the sitemap in robots.txt** or putting it behind a login, so crawlers cannot read it.

## Questions people ask

### How do I make a sitemap for my website for free?

Use the one your platform builds: WordPress, Shopify, Wix, Squarespace, Webflow and most frameworks publish a sitemap at no cost. If yours does not, a free generator that crawls your site, such as getReport's XML sitemap generator, writes the file for up to 100 pages, or you can write it by hand in a text editor from an example. Then upload it and submit it in Search Console.

### Can I create a sitemap without a plugin in WordPress?

Yes. WordPress has published a sitemap at `/wp-sitemap.xml` without any plugin since version 5.5. It lists posts, pages, categories, tags and authors. If it answers 404, check Settings → Reading: ticking "Discourage search engines" switches it off. A plugin is only needed for finer control, such as leaving out tag archives.

### How long does it take to create an XML sitemap?

A few minutes on a CMS that builds one: switch it on, check what it lists and submit it. A generator crawl of a small site takes one to three minutes. Writing a file by hand for 20–30 pages takes about ten minutes. What takes longer is cleaning the list, so it holds only live, indexable pages.

### Can a sitemap live in a subfolder instead of the root?

It can, but it then covers only that folder. A sitemap at `https://example.com/blog/sitemap.xml` may list only URLs under `/blog/` unless you submit it in Search Console, while one at the root may list any URL on that host. The root is the simpler choice. Wherever it lives, add its full address to robots.txt with a `Sitemap:` line so every crawler finds it.
