Open source May 2026 /19 pages
Laracrate

Laracrate

Laracrate

Polymorphic file storage for Laravel: direct uploads to R2/S3, granular access control, sensitive-content streaming, automatic image variants, video and PDF previews, per-variant watermarks, multipart uploads, text extraction, vector embeddings, and hybrid (keyword plus semantic) search.

This is the documentation for Laracrate 2.x. Using 1.x? Its documentation is the README of 1.3.0, and Upgrading from 1.x lists what to change to move to 2.x.

What is Laracrate?

Laracrate is a polymorphic file storage layer for Laravel built for object storage (Cloudflare R2, AWS S3) and local disks. It lets any Eloquent model own collections of files, uploads the binary straight from the browser to your bucket (the file never passes through PHP), then runs an asynchronous pipeline that derives everything else: image variants, video and PDF previews, extracted text, vector embeddings, and a searchable chunk store for retrieval-augmented generation. The backend is fully decoupled from any frontend, and optional upload components for Livewire, React and Svelte ship in the box if you want them.

What you get:

  • Direct upload to R2 and S3. Presigned single-part PUT for normal files, and multipart upload for large files (parallel parts with per-part retries and ETag assembly).
  • Polymorphic ownership. Three independent morphs per file (fileable, creator/owner, tenant) so a file knows what it belongs to, who created it, and which tenant scopes it.
  • Asynchronous processing pipeline. Creating a file dispatches a queued job that runs ordered steps by file type. Your user's upload stays instant.
  • Image variants and per-variant watermarks. Automatic resized derivatives with optional watermarking configured per variant.
  • Typed variants for video and PDF. MP4 copies, teasers built from fragments, frames and strips of frames, and rendered PDF pages, each under the name your app gives it, plus a preview that names one of them.
  • Public or private files. A private file gets a signed link straight to the disk, or is served through PHP with the view policy checked on every request: the caller chooses, per use.
  • Text extraction, embeddings and hybrid search. Opt-in extraction, chunking, embedding generation, and a pluggable ChunkStore (MySQL or Meilisearch) for keyword plus semantic search.
  • Folders and slots. A folder tree for organizing files, and file slots for "fill in this required document" workflows with quotas.
  • Multi-tenant buckets and usage accounting. Optional dedicated bucket per tenant and storage usage reporting for quotas.
  • Optional upload components. Three of them, for Livewire, React and Svelte, styled by a single CSS file with eleven themes. The React and Svelte ones upload to targets the app declares once, with their authorization. None of it is required to use the package.

At a glance:

  Your model (HasFiles)
        |  addFile($upload, $collection, ...)
        v
  CreateFileAction ----- writes binary -----> Storage backend (R2 / S3 / local)
        |                                      (StorageManager: plain disk or tenant bucket)
        v
  File row (laracrate_files)   processing_status = pending
        |  FileObserver::created()  ->  dispatch
        v
  ProcessFileJob (queue)  ->  ProcessFileAction (orchestrator)
        |  resolves steps by file type, collection and model, ordered by priority
        v
  Pipeline steps:
    image  : extract dimensions -> optimize -> generate variants
    video  : extract dimensions -> transcode -> generate variants -> extract preview
    pdf    : extract preview
    text   : extract text -> chunk -> generate embeddings -> persist chunks
        |                                                          |
        v                                                          v
  variants (child File rows)                              ChunkStore.store()
                                                       (MysqlChunkStore | MeilisearchChunkStore)
                                                                   |
        processing_status = completed                              v
                                                          search() (keyword + semantic)

Philosophy

Laracrate follows six principles. Keep them in mind and the rest of the API will feel predictable.

  1. The backend is frontend-agnostic. There is zero coupling to Livewire, Vue, or Alpine in the storage layer. The Livewire uploader is an optional, publishable convenience, not a dependency of the core.
  2. Reuse Storage::disk(). Disk credentials live in your app's config/filesystems.php, not here. Laracrate resolves disks through Laravel's filesystem and never duplicates that configuration.
  3. Everything is a pipeline of Actions. Each operation is an isolated, testable, queueable class (built on edulazaro/laractions). The processing pipeline is just a registry of ordered steps you can extend.
  4. Processing is asynchronous. Variants, video and PDF previews, text extraction, and embeddings all run on the queue. The user's upload is instantaneous, and a file simply stays pending until a worker picks it up.
  5. Who a file is for is decided per collection; how it is served, per use. A collection is public or private. For a private file the code picks a signed link to the disk (url()) or the route through PHP (streamUrl()); only encrypted and sensitive files are always served through PHP.
  6. path is the full object key. A file's path stores the complete key of the object in the disk (directories, filename, extension included). Use the key accessor to read it. Never rebuild a key by concatenating path and name.

Requirements

Laracrate targets current Laravel. The core requirements below are enough to store files and serve them. Media processing, text extraction, and search rely on optional system tools and services that you only install for the features you use.

What Requirement Notes
PHP >= 8.2
Laravel laravel/framework >= 12.0
Actions edulazaro/laractions >= 1.0 Queueable, testable action classes used throughout.
AWS SDK aws/aws-sdk-php ^3.300 Presigned uploads and S3/R2 operations.
Image processing intervention/image ^3.0 Image variants and optimization (needs an imagick or gd PHP extension).
Flysystem adapter league/flysystem-aws-s3-v3 ^3.0 S3/R2 disk driver.

The four packages above are hard Composer dependencies and are installed for you. The following are optional and unlock specific pipeline features:

Optional dependency Unlocks
smalot/pdfparser Native PDF text extraction (PdfTextExtractor).
imagick or gd PHP extension Image variant generation through Intervention Image.
ffmpeg + ffprobe Video dimension extraction, transcoding, and preview frames.
poppler-utils (pdftoppm) or ghostscript Rasterized PDF previews.
meilisearch/meilisearch-php + a Meilisearch server The meilisearch chunk store for server-side hybrid search (see the Text extraction, embeddings and search section).
An OpenAI or Anthropic API key Embeddings, plus OCR and transcription based extraction.

These tools are invoked only inside queued pipeline steps, so they never block an upload. If a tool is missing, the corresponding step is skipped or the file stays unprocessed, but storing and serving the file still works.