Smooth Logo
    HomeFeaturesPricingLearnContact
    Start for FREE →
    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.

    Back to Articles

    © 2025 Smooth
    ContactPrivacy PolicyTerms of use