Sitemap automation workflow with interconnected nodes

Sitemap automation — make new articles appear automatically

sitemapseoautomation

This page explains three approachable ways to ensure your site sitemap updates when Smooth publishes new articles. Pick the option that matches your hosting and comfort level. Each example includes a short code snippet you can copy.

Option A — Dynamic sitemap route (server-side)

Many sites (including ours) use a server-side route that queries the database on each request and returns an up-to-date sitemap.xml. This requires no extra jobs — the sitemap is fresh on every request.

If you use a CDN, configure cache headers so the CDN refreshes periodically or purge it programmatically after publishing.

Next.js example: set caching headers

// app/server-sitemap.xml/route.ts
export async function GET() {
  // generate fields by querying your articles table
  const xml = await buildSitemapXml()
  return new Response(xml, {
    headers: {
      'Content-Type': 'application/xml',
      // cache at CDN for 10 minutes, browsers 0
      'Cache-Control': 'public, s-maxage=600, stale-while-revalidate=60'
    }
  })
}

Option B — Static regeneration (script + cron / GitHub Actions)

If you prefer a static file (easy to cache/CDN), run a small script hourly/daily that queries the DB and writes a static public/server-sitemap.xml.

Node script (generate sitemap)

// scripts/generate-sitemap.js
const fs = require('fs')
const { createClient } = require('@supabase/supabase-js')

async function run(){
  const sup = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_ROLE_KEY)
  const { data } = await sup.from('frontend_learn_cms').select('slug,published_at')
  const urls = data.map(a => '<url><loc>https://your-site.org/learn/' + a.slug + '</loc><lastmod>' + a.published_at + '</lastmod></url>').join('
')
  const xml = '<?xml version="1.0" encoding="UTF-8"?><urlset>' + urls + '</urlset>'
  fs.writeFileSync('public/server-sitemap.xml', xml)
}
run().catch(err=>{console.error(err); process.exit(1)})

GitHub Actions example (run hourly)

# .github/workflows/generate-sitemap.yml
name: Generate sitemap
on:
  schedule:
    - cron: '0 * * * *' # hourly
  workflow_dispatch:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run generator
        env:
          SUPABASE_URL: {{ secrets.SUPABASE_URL }}
          SUPABASE_SERVICE_ROLE_KEY: {{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
        run: node scripts/generate-sitemap.js
      - name: Commit sitemap
        run: |
          git config user.name github-actions
          git config user.email actions@github.com
          git add public/server-sitemap.xml
          git commit -m "Update sitemap"
          git push

Option C — Purge CDN after publish (recommended for instant updates)

When your webhook upserts the article, you can also call your CDN's purge API to clear the cached sitemap URL so new articles appear immediately.

Simple webhook-side purge (example)

// in your webhook handler, after upsert
await supabase.from('frontend_learn_cms').upsert(article)
// then call CDN provider to purge /server-sitemap.xml
await fetch('https://api.cdn-provider.example/purge', { method: 'POST', headers: { Authorization: 'Bearer ...' }, body: JSON.stringify({ url: 'https://your-site.org/server-sitemap.xml' }) })

Which option to choose?

  • Dynamic route (A): easiest, always up-to-date, but can be heavier on DB if not cached.
  • Static generation (B): great if you want a fast, cacheable file and only need periodic updates.
  • CDN purge (C): best for immediate updates after each publish — slightly more setup.