PHPackages                             netipar/laravel-chunky - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [File &amp; Storage](/categories/file-storage)
4. /
5. netipar/laravel-chunky

ActiveLibrary[File &amp; Storage](/categories/file-storage)

netipar/laravel-chunky
======================

Chunk-based file upload package for Laravel with event-driven architecture

v0.2.1(2mo ago)0167↓82%MITPHPPHP ^8.2CI failing

Since Mar 8Pushed 2mo agoCompare

[ Source](https://github.com/NETipar/laravel-chunky)[ Packagist](https://packagist.org/packages/netipar/laravel-chunky)[ RSS](/packages/netipar-laravel-chunky/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (10)Versions (3)Used By (0)

  ![laravel-chunky](art/banner.svg)Chunky for Laravel
==================

[](#chunky-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/f3713b5fcf138a14f3b712841e611d572b06058b1ebd83eae8d3a073405fe896/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e6574697061722f6c61726176656c2d6368756e6b792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/netipar/laravel-chunky)[![Tests](https://camo.githubusercontent.com/d41f574160853c2bc2406288bf89456493936ca360c168dd92914803d684472a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f4e4554697061722f6c61726176656c2d6368756e6b792f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/NETipar/laravel-chunky/actions?query=workflow%3ATests+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/6de5c7920b3dca0138f4d2c87960e0b4b7938270997b70d2da1cd87014d78dad/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6e6574697061722f6c61726176656c2d6368756e6b792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/netipar/laravel-chunky)

Chunk-based file upload package for Laravel with event-driven architecture, resume support, and framework-agnostic frontend clients for **Vue 3**, **React**, **Alpine.js**, and **Livewire**. Upload large files reliably over unstable connections.

Quick Example
-------------

[](#quick-example)

```
// Backend: Listen for completed uploads
// EventServiceProvider
protected $listen = [
    \NETipar\Chunky\Events\UploadCompleted::class => [
        \App\Listeners\ProcessUploadedFile::class,
    ],
];
```

```

import { useChunkUpload } from '@netipar/chunky-vue3';

const { upload, progress, isUploading, pause, resume } = useChunkUpload();

function onFileChange(event) {
    upload(event.target.files[0]);
}

    Pause

```

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 11 or 12

Installation
------------

[](#installation)

### Backend

[](#backend)

```
composer require netipar/laravel-chunky
```

Publish the config file:

```
php artisan vendor:publish --tag=chunky-config
```

Run the migrations (for database tracker):

```
php artisan migrate
```

### Frontend

[](#frontend)

Install the package for your framework:

```
# Vue 3
npm install @netipar/chunky-vue3

# React
npm install @netipar/chunky-react

# Alpine.js (standalone, without Livewire)
npm install @netipar/chunky-alpine

# Core only (framework-agnostic)
npm install @netipar/chunky-core
```

> The `@netipar/chunky-core` package is automatically installed as a dependency of all framework packages.

### Livewire

[](#livewire)

No npm package needed. The Livewire component uses Alpine.js under the hood and is included in the Composer package. Just add the component to your Blade template:

```

```

Frontend Packages
-----------------

[](#frontend-packages)

PackageFrameworkPeer Dependencies`@netipar/chunky-core`None (vanilla JS/TS)-`@netipar/chunky-vue3`Vue 3.4+`vue``@netipar/chunky-react`React 18+ / 19+`react``@netipar/chunky-alpine`Alpine.js 3+-Usage
-----

[](#usage)

### How It Works

[](#how-it-works)

1. **Frontend** initiates an upload with file metadata
2. **Backend** returns an `upload_id`, `chunk_size`, and `total_chunks`
3. **Frontend** slices the file and uploads chunks in parallel with SHA-256 checksums
4. **Backend** stores each chunk, verifies integrity, tracks progress
5. When all chunks arrive, an `AssembleFileJob` merges them on the queue
6. **Events** fire at each step -- hook in your own listeners

### API Endpoints

[](#api-endpoints)

The package registers three routes (configurable prefix/middleware):

MethodEndpointPurpose`POST``/api/chunky/upload`Initiate upload`POST``/api/chunky/upload/{uploadId}/chunks`Upload a chunk`GET``/api/chunky/upload/{uploadId}`Get upload status### Vue 3

[](#vue-3)

```

import { useChunkUpload } from '@netipar/chunky-vue3';

const {
    progress, isUploading, isPaused, isComplete, error,
    uploadId, uploadedChunks, totalChunks, currentFile,
    upload, pause, resume, cancel, retry,
    onProgress, onChunkUploaded, onComplete, onError,
} = useChunkUpload({
    maxConcurrent: 3,
    autoRetry: true,
    maxRetries: 3,
    withCredentials: true,
});

function onFileChange(event: Event) {
    const input = event.target as HTMLInputElement;
    if (input.files?.[0]) {
        upload(input.files[0]);
    }
}

```

### React

[](#react)

```
import { useChunkUpload } from '@netipar/chunky-react';

function FileUpload() {
    const {
        progress, isUploading, isPaused, isComplete, error,
        upload, pause, resume, cancel, retry,
    } = useChunkUpload({ maxConcurrent: 3 });

    const handleChange = (e: React.ChangeEvent) => {
        const file = e.target.files?.[0];
        if (file) upload(file);
    };

    return (

            {isUploading && }
            {isUploading && (

                    {isPaused ? 'Resume' : 'Pause'}

            )}
            {error && {error}}

    );
}
```

### Alpine.js

[](#alpinejs)

```

import { registerChunkUpload } from '@netipar/chunky-alpine';
import Alpine from 'alpinejs';

registerChunkUpload(Alpine);
Alpine.start();

            Cancel

            Retry

```

### Livewire

[](#livewire-1)

```
{{-- Basic usage --}}

{{-- With context for validation --}}

{{-- With custom slot content --}}

```

Listen for the upload completion in your Livewire parent component:

```
#[On('chunky-upload-completed')]
public function handleUpload(array $data): void
{
    // $data['uploadId'], $data['fileName'], $data['finalPath'], $data['disk']
}
```

### Core (Framework-agnostic)

[](#core-framework-agnostic)

```
import { ChunkUploader } from '@netipar/chunky-core';

const uploader = new ChunkUploader({
    maxConcurrent: 3,
    autoRetry: true,
    maxRetries: 3,
    context: 'documents',
});

uploader.on('progress', (event) => {
    console.log(`${event.percentage}%`);
});

uploader.on('complete', (result) => {
    console.log('Done:', result.uploadId);
});

uploader.on('error', (error) => {
    console.error('Failed:', error.message);
});

await uploader.upload(file, { folder: 'reports' });

// Controls
uploader.pause();
uploader.resume();
uploader.cancel();
uploader.retry();

// Cleanup when done
uploader.destroy();
```

Context-based Validation &amp; Save Callbacks
---------------------------------------------

[](#context-based-validation--save-callbacks)

Register per-context validation rules and save handlers in your `AppServiceProvider`:

```
use NETipar\Chunky\Facades\Chunky;

public function boot(): void
{
    Chunky::context(
        'profile_avatar',
        rules: fn () => [
            'file_size' => ['max:5242880'], // 5MB
            'mime_type' => ['in:image/jpeg,image/png,image/webp'],
        ],
        save: function ($metadata) {
            $user = auth()->user();
            $user->addMediaFromDisk($metadata->finalPath, $metadata->disk)
                ->toMediaCollection('avatar');
        },
    );

    Chunky::context(
        'documents',
        rules: fn () => [
            'file_size' => ['max:104857600'], // 100MB
            'mime_type' => ['in:application/pdf,application/zip'],
        ],
    );
}
```

Then pass the context from the frontend:

```
// Vue 3
const { upload } = useChunkUpload({ context: 'profile_avatar' });

// React
const { upload } = useChunkUpload({ context: 'profile_avatar' });

// Alpine.js
//
```

Listening to Events
-------------------

[](#listening-to-events)

Register listeners in your `EventServiceProvider`:

```
use NETipar\Chunky\Events\UploadCompleted;
use NETipar\Chunky\Events\ChunkUploaded;
use NETipar\Chunky\Events\FileAssembled;

protected $listen = [
    UploadCompleted::class => [
        \App\Listeners\ProcessUploadedFile::class,
        \App\Listeners\NotifyUserAboutUpload::class,
    ],
    ChunkUploaded::class => [
        \App\Listeners\TrackUploadProgress::class,
    ],
];
```

Example listener:

```
namespace App\Listeners;

use NETipar\Chunky\Events\UploadCompleted;
use Illuminate\Support\Facades\Storage;

class ProcessUploadedFile
{
    public function handle(UploadCompleted $event): void
    {
        $path = $event->finalPath;
        $disk = $event->disk;

        Storage::disk($disk)->move($path, "documents/{$event->uploadId}.zip");
    }
}
```

### Available Events

[](#available-events)

EventPayloadWhen`UploadInitiated`uploadId, fileName, fileSize, totalChunksUpload initialized`ChunkUploaded`uploadId, chunkIndex, totalChunks, progress%After each successful chunk`ChunkUploadFailed`uploadId, chunkIndex, exceptionOn chunk error`FileAssembled`uploadId, finalPath, disk, fileName, fileSizeAfter file assembly`UploadCompleted`uploadId, finalPath, disk, metadataFull upload completeUsing the Facade
----------------

[](#using-the-facade)

```
use NETipar\Chunky\Facades\Chunky;

// Register a context
Chunky::context('documents', rules: fn () => [...], save: fn ($metadata) => ...);

// Programmatic initiation
$result = Chunky::initiate('large-file.zip', 524288000, 'application/zip');
// Returns: ['upload_id' => '...', 'chunk_size' => 1048576, 'total_chunks' => 500]

// Query upload status (returns UploadMetadata DTO)
$status = Chunky::status($uploadId);
// $status->progress(), $status->fileName, $status->status, etc.
```

Configuration
-------------

[](#configuration)

Key `.env` variables:

```
CHUNKY_TRACKER=database
CHUNKY_DISK=local
CHUNKY_CHUNK_SIZE=1048576

```

Full `config/chunky.php`:

KeyDefaultDescription`tracker``database`Tracking driver: `database` or `filesystem``disk``local`Laravel filesystem disk for storage`chunk_size``1048576` (1MB)Chunk size in bytes`temp_directory``chunky/temp`Temp directory for chunks`final_directory``chunky/uploads`Directory for assembled files`expiration``1440`Upload expiration in minutes (24h)`max_file_size``0`Max file size in bytes (0 = unlimited)`allowed_mimes``[]`Allowed MIME types (empty = all)`routes.prefix``api/chunky`Route prefix`routes.middleware``['api']`Route middleware`verify_integrity``true`SHA-256 checksum verification`auto_cleanup``true`Auto-cleanup expired uploadsTracking Drivers
----------------

[](#tracking-drivers)

### Database (default)

[](#database-default)

Uses the `chunked_uploads` table. Best for production -- queryable, reliable, supports status tracking.

```
CHUNKY_TRACKER=database

```

### Filesystem

[](#filesystem)

Uses JSON metadata files on disk. Zero database dependency -- useful for simple setups.

```
CHUNKY_TRACKER=filesystem

```

Error Handling
--------------

[](#error-handling)

```
use NETipar\Chunky\Exceptions\ChunkyException;
use NETipar\Chunky\Exceptions\ChunkIntegrityException;
use NETipar\Chunky\Exceptions\UploadExpiredException;

try {
    $manager->uploadChunk($uploadId, $chunkIndex, $file);
} catch (ChunkIntegrityException $e) {
    // SHA-256 checksum mismatch
} catch (UploadExpiredException $e) {
    // Upload has expired (past 24h default)
} catch (ChunkyException $e) {
    // Base exception (catches all above)
}
```

Examples
--------

[](#examples)

- [English examples](examples/en/)
- [Magyar peldak](examples/hu/)

Testing
-------

[](#testing)

```
composer test
```

Credits
-------

[](#credits)

- [NETipar](https://netipar.hu)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance88

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity37

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

2

Last Release

61d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/63ebd403a206ac48ef1923c8237326df547be3598c1e46ade9d244315ec25735?d=identicon)[NETipar](/maintainers/NETipar)

---

Top Contributors

[![hegedustibor](https://avatars.githubusercontent.com/u/6483104?v=4)](https://github.com/hegedustibor "hegedustibor (4 commits)")

---

Tags

laravelfileuploadchunk

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/netipar-laravel-chunky/health.svg)

```
[![Health](https://phpackages.com/badges/netipar-laravel-chunky/health.svg)](https://phpackages.com/packages/netipar-laravel-chunky)
```

###  Alternatives

[unisharp/laravel-filemanager

A file upload/editor intended for use with Laravel 5 to 10 and CKEditor / TinyMCE

2.2k3.3M74](/packages/unisharp-laravel-filemanager)[laravel/scout

Laravel Scout provides a driver based solution to searching your Eloquent models.

1.7k49.4M479](/packages/laravel-scout)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[flat3/lodata

OData v4.01 Producer for Laravel

96320.9k](/packages/flat3-lodata)[erlandmuchasaj/laravel-file-uploader

A simple package to help you easily upload files to your laravel project.

128.7k](/packages/erlandmuchasaj-laravel-file-uploader)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
