In large Laravel applications, SEO often requires a well-structured sitemap setup. When your website has thousands of URLs like blog posts, products, or categories, keeping them in a single sitemap is inefficient. That is where a Sitemap Index becomes useful. It helps you generate a Sitemap Index in Laravel and keeps your structure organized for search engines.
What is a Sitemap Index
A sitemap index is a file that lists multiple sitemap files for your website instead of all URLs in one. Each sitemap entry points to a separate XML file like posts.xml, products.xml, or categories.xml. We need a sitemap index because Google and other search engines limit each sitemap to 50,000 URLs or 50 MB uncompressed. Once your site grows beyond that, splitting it improves efficiency.
For smaller Laravel applications, you can simply use a single sitemap instead. Check our detailed post on How to Automatically Generate an XML Sitemap in Laravel for that. But large applications benefit more from using a sitemap index.
Why Use a Sitemap Index
A sitemap index helps divide your large list of URLs into smaller parts. It ensures better crawling performance, faster indexing, and stronger SEO.
Getting Started with Spatie Sitemap
In this article, you will use the Spatie Sitemap package in Laravel 12 to makes it easy to generate sitemaps automatically. It also provides ready to use functionality to generate sitemap index.
Before moving forward, you need to install spatie sitemap library into your Laravel application. Open your terminal and enter below command to install spatie sitemap:
composer require spatie/laravel-sitemap
After installation, Laravel auto-detects the package and you can start configuring sitemap logic.
Creating a Sitemap Index with Multiple Sitemaps In Laravel 12
In this example, we will generate a Sitemap Index in Laravel that includes multiple sitemaps such as custom pages, categories, posts, and products. This approach works well for a large-scale platform.
We will include sitemaps for:
- Custom pages: home, contact us, about us, privacy policy, and terms and conditions
- Dynamic categories by slug
- Dynamic posts by slug
- Dynamic products by slug
You can have different pages or even requirement but here we have tried to implement all the common concepts where sitemap index is required. You can get reference from this example and customize as per your need in your Laravel application.
Route Setup
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\CategoryController;
use App\Http\Controllers\PostController;
use App\Http\Controllers\ProductController;
Route::get('/', function () {
return view('welcome');
});
Route::get('/contact-us', function () {
return view('pages.contact');
});
Route::get('/about-us', function () {
return view('pages.about');
});
Route::get('/privacy-policy', function () {
return view('pages.privacy');
});
Route::get('/terms-and-conditions', function () {
return view('pages.terms');
});
Route::get('/categories/{slug}', [CategoryController::class, 'show']);
Route::get('/posts/{slug}', [PostController::class, 'show']);
Route::get('/products/{slug}', [ProductController::class, 'show']);
These routes cover general static pages and dynamic data like categories, products, and posts.
We will use a custom Artisan command to generate the sitemap index with the Spatie package. For creating your own Artisan command, refer to our full guide How to Generate Custom Artisan Commands in Laravel.
Creating a Sitemap Generation Command
In this example, you will create artisan command for generating sitemap and it’s index file. So further you can automate it using cronjobs in Laravel. Create the command using:
php artisan make:command GenerateSitemap
Now open the new command file and add the logic for generating each sitemap part.
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Spatie\Sitemap\Sitemap;
use Spatie\Sitemap\SitemapIndex;
use App\Models\Post;
use App\Models\Product;
use App\Models\Category;
use Illuminate\Support\Facades\URL;
class GenerateSitemap extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:generate-sitemap';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*/
public function handle()
{
$sitemapIndex = SitemapIndex::create();
$this->generateGeneralPagesSitemap();
$this->generatePostsSitemap();
$this->generateProductsSitemap();
$this->generateCategoriesSitemap();
$sitemapIndex
->add(URL::to('general.xml'))
->add(URL::to('posts.xml'))
->add(URL::to('products.xml'))
->add(URL::to('categories.xml'))
->writeToFile(public_path('sitemap.xml'));
}
protected function generateGeneralPagesSitemap()
{
Sitemap::create()
->add(URL::to('/'))
->add(URL::to('/contact-us'))
->add(URL::to('/about-us'))
->add(URL::to('/privacy-policy'))
->add(URL::to('/terms-and-conditions'))
->writeToFile(public_path('general.xml'));
}
protected function generatePostsSitemap()
{
$sitemap = Sitemap::create();
$posts = Post::where('status', 'published')->get();
foreach ($posts as $post) {
$tag = \Spatie\Sitemap\Tags\Url::create(URL::to('/posts/' . $post->slug))
->setLastModificationDate($post->updated_at);
$sitemap->add($tag);
}
$sitemap->writeToFile(public_path('posts.xml'));
}
protected function generateProductsSitemap()
{
$sitemap = Sitemap::create();
$products = Product::where('status', 'published')->get();
foreach ($products as $product) {
$tag = \Spatie\Sitemap\Tags\Url::create(URL::to('/products/' . $product->slug))
->setLastModificationDate($product->updated_at);
$sitemap->add($tag);
}
$sitemap->writeToFile(public_path('products.xml'));
}
protected function generateCategoriesSitemap()
{
$sitemap = Sitemap::create();
$categories = Category::where('status', 'active')->get();
foreach ($categories as $category) {
$tag = \Spatie\Sitemap\Tags\Url::create(URL::to('/categories/' . $category->slug))
->setLastModificationDate($category->updated_at);
$sitemap->add($tag);
}
$sitemap->writeToFile(public_path('categories.xml'));
}
}
Think of this process as dividing a huge library into smaller shelves. Each sitemap is a shelf, grouping similar URLs. The sitemap index acts as the catalog that connects them. In this above example, we have tried to separate sitemap generation logic for better understanding.
First of all this command will generate sitemap file for individual things like post, categories and general pages. Once sitemap files are generated it will use those file links and generate sitemap index XML file. All files will be stored into public directory and can be accessed publicly by visiting url.
Sample Output
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>http://app.test/general.xml</loc>
<lastmod>2025-10-09T18:36:02+00:00</lastmod>
</sitemap>
<sitemap>
<loc>http://app.test/posts.xml</loc>
<lastmod>2025-10-09T18:36:02+00:00</lastmod>
</sitemap>
<sitemap>
<loc>http://app.test/products.xml</loc>
<lastmod>2025-10-09T18:36:02+00:00</lastmod>
</sitemap>
<sitemap>
<loc>http://app.test/categories.xml</loc>
<lastmod>2025-10-09T18:36:02+00:00</lastmod>
</sitemap>
</sitemapindex>
You can also navigate to each sitemaps by clicking link on browser or by URL and see it’s content.
Scheduling the Sitemap Generation Command
To keep your sitemap index up to date automatically, you can schedule the sitemap:generate command in Laravel 12 Task Scheduling. This ensures new pages, posts, or products are always reflected in your sitemaps without manual effort.
Open the routes/console.php file and add your command inside the schedule method like this:
use Illuminate\Support\Facades\Schedule;
Schedule::command('app:sitemap-generate')
->daily()
->withoutOverlapping()
->runInBackground();
Further, you have to setup to run this into your crontab. How to Set Up Laravel Scheduler with Crontab guide will provide all information about schedule this sitemap index generation command into your local system or server.
Conclusion
Creating a Sitemap Index in Laravel brings structure and scalability to your SEO strategy. When you generate a Sitemap Index in Laravel 12 using the Spatie Sitemap package, you ensure faster indexing, clean organization, and a future-proof setup for large-scale web platforms.