x-laravel / spatie-media-library-uuid-path
A UUID-based path generator for spatie/laravel-medialibrary.
Package info
github.com/x-laravel/spatie-media-library-uuid-path
pkg:composer/x-laravel/spatie-media-library-uuid-path
Requires
- php: ^8.2
- spatie/laravel-medialibrary: ^11.0
Requires (Dev)
- mockery/mockery: ^1.0
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^11.0|^12.0
This package is auto-updated.
Last update: 2026-04-22 12:40:55 UTC
README
A UUID-based path generator for spatie/laravel-medialibrary.
The Problem
spatie/laravel-medialibrary's default DefaultPathGenerator stores media files in a flat structure based on the primary key (ID):
1/photo.jpg
2/photo.jpg
3/photo.jpg
...
This works fine for small applications, but causes serious issues as the number of media files grows:
- File system performance degradation: File systems like ext4 and NTFS slow down directory listings when thousands of subdirectories exist under a single parent.
- Predictable URLs: The sequential ID-based structure makes media file URLs trivially easy to enumerate.
- Operational overhead: Bulk-moving, backing up, or migrating files to a CDN becomes harder with a flat layout.
The Solution
This package distributes files evenly by turning the first 8 characters of each media UUID into a four-level directory hierarchy:
55/0e/84/00/550e8400-e29b-41d4-a716-446655440000/photo.jpg
Conversions and responsive images are placed in dedicated subdirectories under the UUID folder:
55/0e/84/00/550e8400-e29b-41d4-a716-446655440000/conversions/
55/0e/84/00/550e8400-e29b-41d4-a716-446655440000/responsive-images/
Benefits:
- Performance: Each directory holds at most 256 subdirectories, spreading the file system load evenly.
- Security: The UUID-based random structure makes file paths unpredictable and resistant to enumeration.
- Uniqueness: Every media file gets its own UUID directory, eliminating any risk of path collisions.
Requirements
- PHP ^8.2
- spatie/laravel-medialibrary ^11.0
Installation
composer require x-laravel/spatie-media-library-uuid-path
Setup
Publish the spatie/laravel-medialibrary config (if you haven't already) and set the path_generator option:
php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="config"
In config/media-library.php:
'path_generator' => \XLaravel\SpatieMediaLibraryUuidPath\UuidPathGenerator::class, 'file_remover_class' => \XLaravel\SpatieMediaLibraryUuidPath\UuidFileRemover::class,
Why
UuidFileRemover? The default file remover deletes the UUID directory but leaves the empty shard parent directories (55/0e/84/00/) behind.UuidFileRemovercascades upward and removes each shard level when it becomes empty.
Migrating from DefaultPathGenerator
If your project already has media files stored with spatie's default ID-based structure (1/photo.jpg, 2/photo.jpg), you can migrate them to the UUID path structure without any downtime:
1. While your config still points to DefaultPathGenerator, run:
php artisan media:migrate-to-uuid
2. Once it completes, switch the config to this package:
'path_generator' => \XLaravel\SpatieMediaLibraryUuidPath\UuidPathGenerator::class, 'file_remover_class' => \XLaravel\SpatieMediaLibraryUuidPath\UuidFileRemover::class,
The command moves all files (including conversions and responsive images), deletes the old ID directories, and is safe to re-run — it skips media whose old directory no longer exists.
Options:
| Option | Description |
|---|---|
disk |
Disk to migrate (defaults to media-library.disk_name config) |
--dry-run |
Preview what would be moved without touching any files |
--force |
Skip the production confirmation prompt |
Cleaning Orphaned Directories
spatie's built-in media-library:clean command identifies orphaned directories using an is_numeric() check, which only works for the default ID-based path structure. This package ships a UUID-aware replacement:
php artisan media:clean-uuid
Options:
| Option | Description |
|---|---|
disk |
Disk to clean (defaults to media-library.disk_name config) |
--dry-run |
List orphaned directories without deleting them |
--force |
Skip the production confirmation prompt |
Running Tests
# Locally vendor/bin/phpunit # Via Docker (specific PHP version) docker compose --profile php82 run --rm php82 docker compose --profile php83 run --rm php83 docker compose --profile php84 run --rm php84 docker compose --profile php85 run --rm php85