How to Automatically Generate an XML Sitemap in Laravel

Search engines play a vital role in driving organic traffic to your website. To help them understand your website’s structure, it’s important to Generate XML Sitemap in Laravel 12. A sitemap works like a road map that helps search engines know which pages to crawl and when to index them. Automating sitemap generation in Laravel saves time and ensures search engines always include your latest pages and posts without requiring manual updates.

What is a Sitemap?

A sitemap is an XML file that lists all the URLs of your website. It provides important metadata about each URL, such as the last update date, how frequently it changes, and its relationship to other URLs. In simple terms, it’s like a directory that helps search engines easily navigate and understand your website’s structure.

Why Sitemap is Used and Its Benefits

A sitemap is crucial for improving your website’s visibility and indexing speed. Here’s why every Laravel website should have one:

  • Faster Indexing: Search engines quickly discover new and updated pages.
  • Improved SEO Performance: Helps search engines understand your site’s hierarchy.
  • Better Crawl Efficiency: Ensures no page, even deep ones, is left out.
  • Essential for Dynamic Websites: When you frequently publish posts or add products, an automated sitemap keeps everything updated.

By regularly generating or updating XML sitemap in Laravel 12, you help Google, Bing, and other search engines easily crawl and rank your site content.

Getting Started with Spatie Sitemap

The easiest and most reliable way to generate XML sitemap in Laravel is by using the Spatie Sitemap
package. It provides an elegant and efficient way to create, update, and manage sitemaps automatically.

Run the following command to install the package:

composer require spatie/laravel-sitemap

It will take some time to install files of this package but once installed, you can start generating sitemaps directly using the provided classes and methods.

Example: Creating Sitemap for Custom Pages and Dynamic Posts

In this example, we’ll create a sitemap that includes both static pages (like “About Us” or “Privacy Policy”) and dynamic pages (such as blog posts fetched from the database).

Let’s assume, you have some pages into your application like below routes:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::view('/', 'welcome');
Route::view('/contact-us', 'contact');
Route::view('/about-us', 'about');
Route::view('/privacy-policy', 'privacy-policy');
Route::view('/terms-and-conditions', 'terms');

Route::get('/posts/{slug}', [PostController::class, 'show'])->name('posts.show');

As you can see, here you have few static pages like home, contact us, about us, privacy and terms page. However, there is dynamic page for posts too and we will generate sitemap of that.

We’ll use a custom Artisan command to generate the sitemap automatically. If you’re new to custom commands, check out this detailed guide: How to Create Custom Artisan Command in Laravel.

Let’s begin by creating the sitemap command using:

php artisan make:command GenerateSitemap

It will create artisan command. Let’s modify it to generate XML sitemap file.

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\Tags\Url;
use App\Models\Post;
use Illuminate\Support\Carbon;

class GenerateSitemap extends Command
{
    protected $signature = 'app:sitemap-generate';
    protected $description = 'Generate XML Sitemap in Laravel 12 using Spatie';

    public function handle(): int
    {
        $today = Carbon::now()->toDateString();

        $sitemap = Sitemap::create()
            ->add(Url::create('/')->setLastModificationDate($today)->setPriority(1.0))
            ->add(Url::create('/contact-us')->setLastModificationDate($today)->setPriority(1.0))
            ->add(Url::create('/about-us')->setLastModificationDate($today)->setPriority(1.0))
            ->add(Url::create('/privacy-policy')->setLastModificationDate($today)->setPriority(1.0))
            ->add(Url::create('/terms-and-conditions')->setLastModificationDate($today)->setPriority(1.0));

        Post::query()
            ->select('slug', 'created_at')
            ->chunk(100, function ($posts) use ($sitemap) {
                foreach ($posts as $post) {
                    $sitemap->add(
                        Url::create("/posts/{$post->slug}")
                            ->setLastModificationDate($post->created_at)
                            ->setPriority(1.0)
                    );
                }
            });

        $sitemap->writeToFile(public_path('sitemap.xml'));

        $this->components->info('Sitemap generated successfully!');

        return self::SUCCESS;
    }
}

The code uses the Spatie Sitemap package to automatically generate XML sitemap in Laravel 12. It first creates an empty sitemap instance and adds custom pages like Home, About Us, and Privacy Policy. Then, it loops through all blog posts in the database, dynamically adding their URLs to the sitemap. Finally, it writes the sitemap to the public/sitemap.xml file. You can run this command anytime to generate sitemap.

Generated XML Sitemap File

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    <url>
        <loc>https://example.com/</loc>
        <lastmod>2025-10-09</lastmod>
        <priority>1.0</priority>
    </url>
    <url>
        <loc>https://example.com/contact-us</loc>
        <lastmod>2025-10-09</lastmod>
        <priority>1.0</priority>
    </url>
    <url>
        <loc>https://example.com/about-us</loc>
        <lastmod>2025-10-09</lastmod>
        <priority>1.0</priority>
    </url>
    <url>
        <loc>https://example.com/privacy-policy</loc>
        <lastmod>2025-10-09</lastmod>
        <priority>1.0</priority>
    </url>
    <url>
        <loc>https://example.com/terms-and-conditions</loc>
        <lastmod>2025-10-09</lastmod>
        <priority>1.0</priority>
    </url>
    <url>
        <loc>https://example.com/posts/first-post</loc>
        <lastmod>2025-09-20</lastmod>
        <priority>1.0</priority>
    </url>
    <url>
        <loc>https://example.com/posts/laravel-tips</loc>
        <lastmod>2025-09-25</lastmod>
        <priority>1.0</priority>
    </url>
    <url>
        <loc>https://example.com/posts/generate-xml-sitemap-in-laravel</loc>
        <lastmod>2025-10-01</lastmod>
        <priority>1.0</priority>
    </url>
</urlset>

As you can see in above sitemap file, it shows all the URLs and last modified date and priorities.

Scheduling Sitemap Generation in Laravel 12

To keep your sitemap up-to-date automatically, you can schedule the sitemap generation command in Laravel 12. Instead of manually running php artisan app:sitemap-generate every time you add new pages or posts, scheduling ensures your sitemap updates regularly, which is crucial for SEO.

Open the routes/console.php file and add the following code:

use Illuminate\Support\Facades\Schedule;

Schedule::command('app:sitemap-generate')
    ->daily()
    ->withoutOverlapping()
    ->runInBackground();

This helps to add new content into sitemap for search engines and remove outdated or deleted content from it. For more on scheduling command run automatically into Ubuntu crontab check our guide for “How to Set Up Laravel Scheduler with Crontab

Conclusion

Having an updated sitemap is essential for search engine apperences. By automating this process using the Spatie package, you ensure search engines always have access to your latest pages and content. With the above example, you can easily Generate XML Sitemap in Laravel for both static and dynamic pages, improving your SEO performance and keeping your website search-engine friendly without manual updates.

But for larger sites it’s ideal to split sitemap into multiple sitemap files targeting specific things like general sitemap for custom pages, another sitemap for post and so on. You can achieve this with help of sitemap index. For enterprise level application it’s best practice to create an sitemap index with individual sitemaps for topics.