Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Filepond Laravel Package

sopamo/laravel-filepond

An all-in-one Laravel backend for FilePond. Handles temporary uploads, chunked uploads, and file reverting, with support for any Laravel filesystem disk. Get up and running in minutes with a simple composer install and minimal JS config.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Check version requirements first

    • v2.0.0-beta.5 is a breaking release: PHP 8.2+ and Laravel 12 or 13 only. Laravel 13 requires PHP 8.3+.
    • If you're on PHP 8.0/8.1 or Laravel 10/11, stay on the 1.x line. Don't bump this in composer.json casually — it will fail resolution or, worse, fail at runtime.
    php -v && php artisan --version
    composer require sopamo/laravel-filepond:2.0.0-beta.5
    

    Pin the exact beta tag. Semver pre-releases don't get patch updates automatically; you'll want deliberate bumps while evaluating.

  2. Publish the config

    php artisan vendor:publish --provider="Sopamo\Filepond\FilepondServiceProvider" --tag="filepond-config"
    

    Review disk, path, allowed_mime_types, max_file_size, and the chunk settings. In v2 the chunk pipeline changed, so diff your published config against the upstream default rather than assuming your 1.x values still mean the same thing.

  3. Register the routes

    use Sopamo\Filepond\FilepondController;
    
    Route::post('/filepond-upload', [FilepondController::class, 'upload']);
    Route::post('/filepond-revert', [FilepondController::class, 'revert']);
    Route::get('/filepond-load', [FilepondController::class, 'load']);
    

    FilePond's JS calls revert and load as part of its normal lifecycle (undo, restoring a previously uploaded file). Missing them shows up as silent frontend failures, not backend errors.

  4. Frontend wiring

    <link href="https://unpkg.com/filepond@^4/dist/filepond.css" rel="stylesheet">
    <script src="https://unpkg.com/filepond@^4/dist/filepond.js"></script>
    
    FilePond.setOptions({
      server: {
        process: '/filepond-upload',
        revert: '/filepond-revert',
        load: '/filepond-load',
      },
    });
    
  5. First use case to validate the upgrade Upload a small file, then a chunked file, then revert it. If all three work, the temp-upload path handling and cleanup are behaving. Then repeat with your real disk (S3 or Azure) before touching production config.


Implementation Patterns

Workflow: Handling File Uploads

  1. Basic upload The stock FilepondController handles validation, disk writes, and FilePond's expected response format. For a straightforward "user uploads an avatar" case, route straight to it and only customize the config.

  2. Custom validation Extend the controller rather than duplicating it:

    // app/Http/Controllers/CustomFilepondController.php
    use Sopamo\Filepond\FilepondController;
    
    class CustomFilepondController extends FilepondController
    {
        public function upload(Request $request)
        {
            $this->validate($request, [
                'file' => ['required', 'mimes:jpeg,png,pdf', 'max:10240'],
                'user_id' => 'required|exists:users,id',
            ]);
    
            return parent::upload($request);
        }
    }
    

    Keep the parent call last so package-level response formatting stays intact.

  3. Chunked uploads

    // config/filepond.php
    'chunk_size' => '5MB',
    'chunk_upload_url' => '/filepond-chunk-upload',
    

    v2 rewrote chunk handling. Invalid chunk ranges and oversized integer headers are now rejected before anything is written to storage — which is good, but it means a client sending odd headers now gets an error instead of a silently-created empty chunk. In practice:

    • Return the correct HTTP status for a rejected chunk and log the offending header values, otherwise you'll be debugging "it just stops at 40%" with no signal.
    • Rejected chunks no longer write garbage, but already-uploaded temp chunks from an aborted session still exist. Keep a scheduled cleanup job for your temp directory.
    • If you previously worked around empty-chunk accumulation in application code, that workaround is now redundant — remove it.
  4. Azure OSS storage Azure chunked uploads now stage and commit blocks server-side instead of downloading the assembled file and re-uploading it. This is the single biggest performance change in the release for large files.

    • Breaking for Azure: you must send the original file's Content-Type when initializing a chunked upload. See the README example. Omit it and blocks are staged with a generic type, which typically bites you later on download or when the file is served from a CDN.
    • Pass the real MIME type from the client (FilePond metadata or a hidden form field) rather than inferring it server-side — the browser knows better than a filename extension check.
  5. Post-upload processing

    // app/Providers/AppServiceProvider.php
    use Sopamo\Filepond\Events\FileUploaded;
    
    public function boot(): void
    {
        Event::listen(FileUploaded::class, function ($event) {
            // thumbnails, virus scan dispatch, DB record creation
        });
    }
    

    Remember this fires per completed upload, which for chunked uploads means after the final commit, not per chunk.

Integration Tips

  • Bundle FilePond with Vite instead of the CDN once you're happy with the prototype:
    // resources/js/app.js
    import * as FilePond from 'filepond';
    import 'filepond/dist/filepond.min.css';
    import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
    FilePond.registerPlugin(FilePondPluginImagePreview);
    
  • Form Requests keep validation out of the controller:
    public function rules(): array
    {
        return ['file' => ['required', 'mimes:jpeg,png', 'max:5120']];
    }
    
    Note the package's own config-level validation still applies; keep the two consistent or you'll reject files the config would have allowed (confusing for users, invisible in logs).
  • Cloud disks work via league/flysystem — set 'disk' => 's3' and confirm your IAM policy allows PutObject and DeleteObject, since revert needs to delete.
  • Upgrade choreography: create a branch, bump to 2.0.0-beta.5, run the full test suite, and exercise upload/chunk/revert manually on each disk you use. The release adds regression tests and CI across supported PHP and Laravel versions — mirror their matrix locally so you're not the one discovering an 8.2-only issue.

Gotchas and Tips

Pitfalls

  1. PHP/Laravel version floor The hardest failure mode is a lockfile that resolves but breaks at boot. Check CI runners too — a pipeline on PHP 8.1 will fail on install, not on a test, which can look like a flaky build if you don't read the log.

  2. Laravel 13 needs PHP 8.3+ Laravel 12 + PHP 8.2 is fine; Laravel 13 + PHP 8.2 is not. If you run a mixed matrix, pin per-job versions explicitly.

  3. Azure Content-Type omission The most likely regression for existing Azure users. Symptom: uploads succeed but served files have the wrong MIME type, or downstream processing (image previews, PDF viewers) misbehaves. There's no exception thrown — validate it with a test.

  4. Disk-root temp paths v2 explicitly supports '' and '/' as temp upload paths, along with historical server IDs. If you have legacy temp paths or stored server IDs from 1.x, they should keep working thanks to the added path validation and safe deletion — but verify any custom code that concatenates paths, since '/' plus a filename can produce //name and bypass naive checks.

  5. CORS for cross-origin frontends

    // config/cors.php
    'paths' => ['filepond-*', 'api/*'],
    'allowed_origins' => ['https://your-frontend.com'],
    

    FilePond's load endpoint is a GET — make sure it's not accidentally excluded from your CORS paths.

  6. Filename collisions Defaults use UUIDs. If you override:

    'filename_generator' => fn ($file) => 'custom_' . time() . '.' . $file->getClientOriginalExtension(),
    

    time() alone collides under concurrent uploads. Use Str::uuid().

  7. Timeouts on large files Raise max_execution_time, memory_limit, upload_max_filesize, post_max_size, plus client_max_body_size in Nginx. A 413 from the proxy never reaches Laravel, so nothing appears in your logs.

Debugging Tips

  • Log at the controller boundary, wrapping the parent call so package exceptions aren't swallowed:
    public function upload(Request $request)
    {
        try {
            return parent::upload($request);
        } catch (\Throwable $e) {
            \Log::error('FilePond upload failed', ['message' => $e->getMessage(), 'headers' => $request->headers->all()]);
            return response()->json(['error' => 'Upload failed'], 500);
        }
    }
    
    Logging headers matters specifically for the new chunk-header validation — you want the rejected values.
  • Watch the browser network tab, not just the server. FilePond surfaces server error bodies in the UI; a bare "Upload failed" usually means you returned HTML where JSON was expected.
  • Reproduce with curl/Postman to isolate backend from plugin behavior. For chunked uploads, replicate the chunk headers exactly — that's where the new validation lives.
  • Check temp storage after a failed upload. With v2 fewer junk chunks are written, but aborted sessions still leave committed temp files. If disk usage grows unexpectedly, that's the first place to look.
  • Run the package's own test suite against your Laravel version if you hit something exotic; their CI matrix tells you which combinations are actually exercised.

Extension Points

  1. Custom storage logic

    protected function storeFile($request, $file)
    {
        $path = $this->getFilePath($file);
        Storage::disk($this->config['disk'])->put($path, file_get_contents($file));
        return $path;
    }
    

    Don't override this for Azure chunked uploads — the block staging/commit path is the point of the v2 change, and bypassing it reintroduces the download-and-reupload behavior.

  2. Pre-signed URLs for direct-to-cloud uploads

    $url = Storage::disk('s3')->temporaryUploadUrl(
        'uploads/' . Str::uuid(),
        now()->addMinutes(15),
        ['ContentType' => $request->input('content_type')]
    );
    return response()->json(['url' => $url]);
    

    Prefer Storage::temporaryUploadUrl over instantiating an S3Client yourself — it respects your disk config and credentials.

  3. Post-upload events

    event(new \App\Events\FileProcessed($filePath, $request->user()));
    

    Keep custom events distinct from the package's FileUploaded so listeners don't fire on internal temp operations.

  4. Listener registration Register in EventServiceProvider::$listen (or via Event::listen in boot()), and confirm it's firing with php artisan event:list before assuming your processing logic is broken.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package