# laravel-chunk-upload: resumable uploads behind one Laravel controller

> A PHP package that lets a browser upload a large file in pieces, with server side logic that works for resumable.js, flow.js, DropZone, jQuery-File-Upload, Plupload, simple uploader and ng-file-upload without changing the controller. It sits on Laravel's own file upload system and keeps memory use low.

**pionl/laravel-chunk-upload** — The basic implementation for chunk upload with multiple providers support like jQuery-file-upload, pupload, DropZone and resumable.js

- Repository: https://github.com/pionl/laravel-chunk-upload
- Stars: 724 · Forks: 199
- Language: PHP
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/pionl-laravel-chunk-upload

## The problem is a file that will not fit in one request

Laravel Chunk Upload simplifies chunked uploads with support for multiple JavaScript libraries atop Laravel's file upload system, designed with a minimal memory footprint. Features include cross-domain request support, automatic cleaning, and intuitive usage.

That is the whole problem statement. A large file uploaded in one request hits limits you do not control: the web server's body size cap, the PHP request size limit, the proxy timeout, and the browser's patience. Chunking splits the file into pieces the client sends one at a time, and the server reassembles them.

The design goal that shapes everything else is that the server side should be the same regardless of which JavaScript library does the chunking. The readme is explicit about this: select your preferred frontend provider, and multiple providers are supported in a single controller. That means your team picks the frontend library on its own merits, and the PHP side does not change when you change your mind.

The audience is Laravel developers building anything that accepts user files: an attachment feature, a media ingest, a document submission. The package is MIT licensed and is published on Packagist as pion/laravel-chunk-upload.

A separate repository, laravel-chunk-upload-example, holds a working application with integration tests, and the readme points new contributors at it as the place to see the whole thing running.

## The support table is the real feature list, and it is not uniform

Seven JavaScript libraries are listed with their own wiki page, their capabilities and their authors. Reading the table rather than the headline is worthwhile, because the columns are not all the same.

For single and chunk upload, every library except simple uploader has a check mark. So simple uploader is the odd one out on that axis, and it is the one entry with no wiki link of its own in the table.

For simultaneous uploads, the picture splits. resumable.js, flow.js and DropZone are marked as supporting it, while jQuery-File-Upload, Plupload, simple uploader and ng-file-upload are marked as not supporting it. The Included in Example Project column matches that split, with the same three libraries marked as included, and additionally Plupload, simple uploader and ng-file-upload are marked as not included in the example project.

The authors column records who contributed the integration: @pionl for resumable.js, DropZone, jQuery-File-Upload and Plupload, @kcaj-burr for flow.js, @dyktek for simple uploader and @L3o-pold for ng-file-upload.

And the footnote under the table is the part that will cost you an afternoon if you miss it. The library must send the last chunk as the final one to ensure correct merging. That is a client side requirement, and getting it wrong produces a file that is one chunk short, which is the kind of bug that passes a happy path test and fails in production.

## Installing it and wiring the three pieces

Installation is a Composer require:

```bash
composer require pion/laravel-chunk-upload
```

Then the configuration is published, which the readme marks as recommended:

```bash
php artisan vendor:publish --provider="Pion\Laravel\ChunkUpload\Providers\ChunkUploadServiceProvider"
```

The reason publishing is recommended is not a matter of taste. The vendor:publish command will force the recommended default values, and the readme notes that due to a cross-compatibility reason the config can contain different values than the business logic uses. In other words, the shipped configuration is a compatibility surface across the supported frontend libraries, and if you change it, you change behaviour for all of them.

Usage then takes three steps. Integrate your controller to handle file uploads, with the instructions in the controller page of the wiki. Define a route for the controller, covered on the routing page. And select your preferred frontend provider, where multiple providers are supported in a single controller.

The order is worth noting. You write the controller first, against a provider you have chosen, and the route is a separate small step. The wiki page per library then shows the JavaScript side for that provider.

The repository layout matches a Laravel package convention. There is a src directory, a config directory, a fixtures directory, tests and a phpunit.xml.dist, plus .php-cs-fixer.php for code style and .phplint.yml for linting. The package follows the same structure the framework itself uses, so a Laravel developer will recognise it immediately.

## Cross-domain requests and automatic cleaning

Two of the three headline features deserve a closer look because they are the ones with operational consequences.

Cross-domain request support means the uploader can live on a different origin from your Laravel application. That is the normal case for a modern front end separated from the API, and it is also the case where a naive chunk upload implementation falls over, because the browser sends preflight requests and the server has to answer them correctly for every chunk endpoint. Handling it once, inside the package, is the value.

Automatic cleaning is the other one. Chunked uploads leave a trail of temporary files: the individual chunks, and a partially assembled file if the upload is abandoned. If nobody cleans up, a server that has served a few thousand large uploads is holding a few thousand gigabytes of orphaned data. A package that cleans as it goes removes that class of problem from your application entirely.

The minimal memory footprint claim sits alongside these two, and it follows from the same design. Because the chunks are handled through Laravel's file upload system rather than being buffered in memory, the server never holds the whole file, or even a large part of it, at once. The chunks are written to disk and merged from disk.

The one place the readme explicitly asks for help is custom disks. It says that currently it is recommended to use the basic storage setup, not linking the public folder, and that if you have time to verify its functionality, please PR the changes. So the interaction between this package and Laravel's non default storage configuration is an acknowledged rough edge rather than a settled feature.

## Version support is tracked per Laravel release, and it is explicit

The compatibility table is the most concrete thing in the readme, and it distinguishes two things that are easy to confuse. The table shows which PHP and Laravel version is tested, or was tested. If you see a version in the Supported column, it means a package version with the last support of that Laravel version.

Laravel 13 is supported and tested on PHP 8.3, 8.4 and 8.5. Laravel 12 is supported and tested on PHP 8.2 through 8.5. Laravel 11 is supported and tested on PHP 8.2, 8.3 and 8.4. Laravel 10 and Laravel 9 are supported and tested on PHP 8.2.

The bottom two rows are the interesting ones. Laravel 8 and Laravel 7 are marked as supported at version v1.5.6, and the Tested column for both is a red cross rather than a check. In other words, those two lines of Laravel are still installable at a specific pinned package version, but they are no longer exercised by the test matrix. Reading that correctly matters: v1.5.6 is the ceiling for Laravel 7 and 8, so a project on Laravel 8 is pinned to a package version from a much earlier point in the project's life.

The release history shows the package is actively shipping. The three most recent releases are v1.6.3 on 2026-08-28, v1.6.2 on 2026-08-20 and v1.6.1 on 2026-07-29. The last push was on 2026-08-28, the same day as v1.6.3.

## What happens when a new Laravel version lands before a release

The readme has a section for the gap between a new framework version and a package release, and the mechanism it proposes is worth understanding rather than skipping.

If there is a new Laravel version and there is no official release in the package, you can create a PR. Then anyone can use the PR until the official release is made. You check the PR and update composer.json with the repository entry:

```json
"repositories": [
    {
      "type": "vcs",
      "url": "https://github.com/{!ENTER_USER_NAME!}/laravel-chunk-upload"
    }
  ]
```

The url placeholder is literally written that way in the readme, with an exclamation mark wrapped around the field name, which tells you it is a template the reader fills in with their own fork or the fork of whoever opened the PR.

So the workflow is: somebody opens a pull request against the main branch adapting the package to the new framework version, and consumers who need the new Laravel version before an official release point composer at that fork via a vcs repository entry. The readme links an explanation article on requiring a forked repository for the mechanics.

This is a pragmatic answer to a real problem, and it is also a cost. A consumer who goes down this path is running code from a fork whose maintainer is not the package author, pinned by a commit reference, and they will need to move to the official release later. For a team that cannot wait for the release, it is a reasonable trade. For everyone else, the compatibility table tells you whether they need it.

## Where this package is the wrong choice

There are cases where chunked uploading is over engineering, and one where this package is specifically not ready.

The first is file size. If your uploads are documents and images below a few megabytes, a single request works and the chunking machinery is complexity you do not need. The package exists to solve a problem you may not have.

The second is when you already have an upload service. Object storage with multipart upload, a dedicated upload service, or a platform SDK that handles resumable uploads already does this, and does it with the storage layer's own retry and integrity guarantees. The difference in approach is that this package assembles files on your web server's local disk and hands you a path, while those approaches never put the bytes on your application server at all. For large media that is a materially different architecture.

The third is the custom disk caveat. The readme recommends the basic storage setup and explicitly asks for pull requests verifying other configurations. If your application stores files on S3 through Laravel's filesystem layer, you are in the area the project has flagged as unverified, and you should test merging and cleaning on that disk before you rely on it.

The fourth is simultaneous uploads. Four of the seven supported libraries do not support them, and the requirement that the last chunk be sent last is a client side obligation. If your users need to upload several files at once, check the table and choose a library from the three that support it.

And the fifth is a package that stores uploads on the application server, with the disk and the memory implications that follow. For a small team with modest files, that is fine. It is a deliberate architecture, and it should be a deliberate choice.

## Against a per-provider implementation, and against managed upload services

Two comparisons make the trade legible.

The first is against writing the merge logic yourself for one JavaScript library. Each of these libraries has its own chunk protocol, its own way of naming chunks, its own completion semantics, and its own way of telling the server which chunk is the last one. Implementing that once per library is a week of work per library, and it is the kind of work that is invisible until a client retries a chunk or a user abandons an upload halfway. This package does that work once and exposes it through a Laravel controller, so the marginal cost of adding a second frontend library is a different JavaScript call, not a new server implementation.

The second is against a managed upload service. The difference in approach is where the bytes go and who is responsible for them. A managed service takes the upload directly from the browser, so the file never passes through your PHP process, and it handles retries, resumption and integrity on infrastructure designed for it. This package keeps the bytes on your application server and lets you keep full control of the file handling, of the storage layout, and of what happens to the file once it lands.

That control is what people choose this for. If your uploads become part of a processing pipeline, if the file needs to end up somewhere specific with a specific name, if you need to hook into the moment the file is complete, then owning the merge is worth the work. If none of that applies and the goal is simply to accept a file, a managed service will be less code and fewer moving parts.

## Conclusion

Adopt laravel-chunk-upload if your Laravel application needs to accept large files that a single request will not carry, and you want the frontend library to be your choice rather than the package's. Skip it if your file sizes fit comfortably inside a request, since the chunking machinery buys you nothing there. Verify first which of the seven listed JavaScript libraries you will actually use, because the support table is not uniform, and check the simultaneous upload requirement, since the library must send the last chunk as the final one for correct merging.

## FAQ

### How do I install laravel-chunk-upload?

Run composer require pion/laravel-chunk-upload, then publish the configuration with php artisan vendor:publish using the Pion\Laravel\ChunkUpload\Providers\ChunkUploadServiceProvider provider. Publishing is recommended because it forces the recommended default values, and the config can contain different values than the business logic uses.

### Which JavaScript upload libraries does laravel-chunk-upload support?

Seven are listed: resumable.js, flow.js, DropZone, jQuery-File-Upload, Plupload, simple uploader and ng-file-upload. All except simple uploader support single and chunk upload, and only resumable.js, flow.js and DropZone are marked as supporting simultaneous uploads.

### What must the client do to merge chunks correctly with laravel-chunk-upload?

The library must send the last chunk as the final one to ensure correct merging. The readme states this requirement explicitly, and getting it wrong leaves the assembled file one chunk short.

### Which Laravel and PHP versions does laravel-chunk-upload support?

Laravel 13 on PHP 8.3 to 8.5, Laravel 12 on PHP 8.2 to 8.5, Laravel 11 on PHP 8.2 to 8.4, and Laravel 10 and 9 on PHP 8.2 are all supported and tested. Laravel 8 and 7 remain supported only at package version v1.5.6 and are no longer in the tested matrix.

### Can I use laravel-chunk-upload with a custom Laravel storage disk?

The readme says it is currently recommended to use the basic storage setup, not linking the public folder, and asks that if you have time to verify its functionality you submit a pull request with the changes. Other storage configurations are therefore an area the project has flagged as unverified.

### How do I use a new Laravel version before laravel-chunk-upload publishes a release?

The readme says you can create a pull request, and anyone can use that PR until the official release is made. You add a vcs repository entry to composer.json pointing at the fork, using the repositories block shown in the documentation.

## Sources

- [Issues](https://github.com/pionl/laravel-chunk-upload/issues)
- [License: MIT](https://github.com/pionl/laravel-chunk-upload/blob/master/LICENSE)
- [pionl/laravel-chunk-upload on GitHub](https://github.com/pionl/laravel-chunk-upload)
- [README](https://github.com/pionl/laravel-chunk-upload/blob/master/README.md)
- [Releases](https://github.com/pionl/laravel-chunk-upload/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pionl-laravel-chunk-upload
