tapp/laravel-uppy-s3-multipart-upload
Laravel package that provides backend endpoints for Uppy's AWS S3 multipart uploader, handling create, sign, complete, and abort requests so large files upload directly to S3 via presigned URLs with minimal server overhead.
What the package actually is. tapp/laravel-uppy-s3-multipart-upload is a thin server-side adapter that implements the endpoints Uppy's @uppy/aws-s3 plugin expects for S3 multipart uploads: create a multipart upload, sign individual parts, list parts, complete, and abort. It wraps aws/aws-sdk-php (or the Flysystem S3 adapter) and exposes them as a publishable Laravel route group plus a config file. It is glue code, not a platform — realistically a few hundred lines of controller and config.
Architecture fit.
Integration feasibility. Low effort mechanically: composer require, publish config, register routes, point Uppy at the endpoint prefix, configure IAM and bucket CORS. The real effort is not installation, it is hardening: the package is intentionally unopinionated about auth, key naming, size limits, and content-type allow-listing. Everything a reviewer would ask about — who may upload, to which prefix, how large, of what type — is your code, not the package's.
Technical risk.
aws/aws-sdk-php/Flysystem S3 signatures. The 2025-11-25 release is recent, which is reassuring, but a package this small can go quiet without anyone noticing until a Laravel upgrade.Key questions to resolve in the technical spike.
uploadId to the authenticated user, and what stops a replay of another user's uploadId?filesystems disk config (reusable, testable) or its own raw credential handling?Stack fit. Assumes Laravel 9+ with PHP 8.1+, an S3 (or S3-compatible) bucket, and a JS frontend that can add @uppy/aws-s3. S3-compatible targets (MinIO, Cloudflare R2) generally work but differ on multipart semantics and ETag CORS exposure — validate with a spike before committing. If you are on a signed-URL/Laravel-Flysystem pattern already, this slots in cleanly; if you are on a proxied-upload pattern, this is a genuine architecture change, not an increment.
Alternatives to weigh before adopting.
Migration path.
Compatibility checklist.
aws/aws-sdk-php constraint conflicts with anything already pulling it in (Flysystem, SES, SQS).routes/api.php and any Inertia catch-all route.api-public by default.AllowedHeaders must include the headers Uppy sends (x-amz-*, content-type), and ExposeHeaders must include ETag.s3:PutObject, s3:AbortMultipartUpload, s3:ListMultipartUploadParts, s3:CompleteMultipartUpload on a specific prefix — not s3:*.Sequencing. Infrastructure (bucket policy, CORS, IAM) → package install + config + auth wrapping → server-side validation layer (key scoping, size/type caps, uploadId ownership) → frontend Uppy integration → lifecycle rule for aborted uploads → observability → rollout behind flag.
Maintenance. Low ongoing code maintenance, moderate dependency-watch overhead. Pin the version, enable Dependabot/Renovate, and assign explicit ownership. Because the package is small, keep a fork (or a vendored controller) in your back pocket: the exit cost is measured in hours. Budget a recurring "does this still work with the next Laravel major" check — that is the realistic failure point, not feature stagnation.
Support. No vendor, no SLA, community GitHub issues only. Internal support means one or two engineers who understand the multipart flow. Document the auth wrapping and validation layer as yours, so on-call does not chase a third-party repo at 2am.
Scaling. Excellent on the data plane — bytes go browser→S3, and S3 scales far beyond anything the app tier will see. The app tier only signs URLs and completes uploads, so cost is a small number of short requests per file, roughly one per part. Watch two things: (1) signing endpoint request rate under concurrency — presigning is cheap but it is still a PHP request per part, so a 100GB upload at 10MB parts is ~10,000 signing calls; tune part size upward (25–50MB) to keep requests tractable; (2) per-user concurrency and bandwidth quotas, since nothing throttles the client's direct-to-S3 throughput.
Failure modes to design for.
AbortIncompleteMultipartUpload after 1–7 days) and an alert.Ramp-up. A mid-level Laravel engineer can integrate the package in about a day; hardening (key scoping, uploadId ownership, size/type enforcement, lifecycle rules) is realistically 3–5 days; frontend Uppy configuration and large-file testing another 2–3 days. Include an integration test with a 100MB+ file and a deliberately interrupted upload — that exercise surfaces CORS, ETag, abort, and presign-expiry issues that unit tests will not.
Bottom line for a TPM. Technically adequate and strategically low-commitment: it is a small, MIT-licensed adapter over AWS's own SDK, so the real risk is not lock-in but the security and lifecycle work the package deliberately leaves to you. Approve it as a starting point with the auth/validation layer treated as first-class scope, a feature-flagged rollout, and a documented willingness to fork. Do not adopt it as a "supported dependency" that nobody owns.
How can I help you explore Laravel packages today?