Laravel Storage Dedupler, by Khimusov Maxim, uses SHA-1 hashes to avoid storing duplicate files. When users upload the same document for several posts, each post gets its own attachment link to one shared file.
Deduplication applies to files stored through Dedupler. Installing the package does not change existing calls to Laravel's storage methods or remove duplicate files already on disk.
Store Files Without Duplicates
The Dedupler facade accepts uploaded files, local paths, and raw content. This example stores the same content under two filenames:
use Maxkhim\Dedupler\Facades\Dedupler; $content = 'Notes for the November release.'; $first = Dedupler::storeFromContent($content, 'release-notes.txt'); $second = Dedupler::storeFromContent($content, 'notes-copy.txt'); if ($first === null || $second === null) { throw new RuntimeException('Could not store the release notes.'); } $first->id === $second->id; // true
The package hashes the content and looks for an existing UniqueFile record before writing a new file. A matching hash returns that record, even when the incoming filename differs. The SHA-1 hash also serves as the record's primary key.
For uploads, use Dedupler::storeFromUploadedFile($file). For a file already on the server, use Dedupler::storeFromPath($absolutePath). Storage methods can return null for an invalid source or a storage error, so check the result before accessing its properties.
If you use an upload interface such as FilePond in Laravel, pass the Laravel UploadedFile received by your application to Dedupler.
Attach Files to Eloquent Models
Add the Deduplable trait to a model that needs attachments:
namespace App\Models; use Illuminate\Database\Eloquent\Model; use Maxkhim\Dedupler\Traits\Deduplable; class Post extends Model { use Deduplable; }
Use a saved model, so the package has a model ID to associate with the file:
use App\Models\Post; $request->validate([ 'attachment' => ['required', 'file'], ]); $post = Post::findOrFail($postId); $file = $post->storeUploadedFile($request->file('attachment')); if ($file === null) { throw new RuntimeException('Could not store the attachment.'); } $anotherPost = Post::findOrFail($anotherPostId); $anotherPost->attachUniqueFile($file->id);
The second post references the existing file by hash without uploading another copy. The attachment table records the model type and ID so that different model classes can share a file too.
The trait also provides storeLocalFile() and storeContentFile(). When you store a file through the model, Dedupler saves its original filename and status on the attachment record. Attaching by hash sets the status but does not copy the original filename; you can supply it in the second argument to attachUniqueFile().
Detach Shared Attachments
Remove a post's attachment using its file hash:
$post->detachUniqueFile($file->id);
If another model still references the file, Dedupler keeps it. Detaching the final attachment deletes both the stored file and its UniqueFile record by default. If your application must retain documents after users remove their attachments, review this behaviour before using the detach method.
Installation and Legacy Analysis
The package declares support for PHP ^8.2 and Laravel 10, 11, 12, and 13. Install it with Composer, then run its installation command:
composer require maxkhim/laravel-storage-dedupler php artisan dedupler:install
The installation command runs the package migrations, then checks the database tables and storage configuration. The default disk is deduplicated, configured as a private local disk at storage/app/deduplicated. Dedupler writes through Laravel's storage API. For background on remote disk configuration, see our guide to using AWS S3 for Laravel storage.
To inspect an existing local directory, run:
php artisan dedupler:analyse-legacy /absolute/path/to/legacy/storage/directory
This command scans the directory and its subdirectories for matching SHA-1 hashes. It reports duplicate counts and an estimate of potential space savings. It does not migrate or delete the files.
You can find the source and usage documentation in the Laravel Storage Dedupler GitHub repository. The package is released under the MIT licence.