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 Rustfs Laravel Package

siberfx/laravel-rustfs

Connect Laravel to RustFS, the S3-compatible object storage written in Rust. The package provides a filesystem driver so you can register a RustFS disk and use Laravel's familiar Storage facade to upload, read, delete, and manage files through the same API you already use for S3.

View on GitHub
Deep Wiki
Context7

Getting Started

1.0.1 is a documentation-and-test release only — no code changes since 1.0.0, so any existing install upgrades safely with a composer update and nothing else. If this is your first time with the package, the release is effectively your onboarding: the new README is now the single source of truth and replaces guesswork with copy-pasteable recipes.

Minimal path:

  1. Require the package and let Laravel's package discovery wire the service provider.
  2. Add a RustFS disk to config/filesystems.php (endpoint, key/secret, bucket, region, path-style endpoint, use SSL). The disk behaves like any other Laravel disk, so Storage::disk('rustfs') is the first thing to try.
  3. Point .env at your RustFS instance — locally that's usually the Docker image the package's own CI runs (rustfs/rustfs:1.0.3), which is the version the new security notes were verified against.
  4. Smoke-test with a single put/get round trip before touching any advanced feature.

First real use case: public-read assets plus private downloads. Read the README's "private downloads" recipe first, because presigned URLs are where most Laravel developers' S3 intuition needs correcting (see Gotchas). Then move to whichever recipe matches your actual workload — form uploads, direct browser uploads, or versioning.

Where to look first, in order: the README table of contents → the presigned PUT vs POST section (read before writing any upload code) → the "application testing" section (so you can fake the disk in feature tests from day one) → the error-handling section.

Implementation Patterns

Treat the disk as the default, presigning as the exception. The package registers a Laravel filesystem disk; use the normal Storage facade for internal read/write, and reach for presigned URLs only when the browser or an external service must talk to RustFS directly.

Browser uploads: default to presigned POST, not PUT. This is the most important workflow decision in 1.0.1. The tested behavior against RustFS 1.0.x is:

  • presigned PUT does not enforce the signed Content-Type and does not enforce any size limit;
  • presigned POST policies are enforced — oversized bodies fail with EntityTooLarge, wrong key prefixes fail with InvalidPolicyDocument.

So the pattern is: server issues a presigned POST with a content-length-range condition and an exact key prefix, ships the policy fields plus the JavaScript from the README to the browser, and the browser posts a multipart form directly. Reserve presigned PUT for cases where the client is trusted (your own backend job, a controlled CLI, an internal service) and validation already happened server-side.

Direct browser upload flow (canonical):

  1. Route handler authorizes the user and the target key prefix.
  2. Generate the presigned POST with size and prefix conditions.
  3. Return the URL plus all form fields to the frontend.
  4. Frontend posts multipart/form-data with the policy fields before the file part — order matters in S3-style POST policies.
  5. On success, the frontend notifies your app; your app records the object, then verifies with a head before marking it ready.

Private downloads: store keys, never public URLs. Generate a short-lived presigned GET at render time (or redirect to it from a controller after your own Gate/policy check). Keep TTLs short and aligned with your auth session.

Versioning and restore: enable versioning per bucket, then restore by copying the older version's bytes onto the same key — this is exactly what the new live test covers, so it's a supported, tested path rather than an improvised one. Encapsulate it in a service method (restoreVersion($key, $versionId)) instead of scattering copy calls.

Multipart/resumable uploads: use these for large files and for anything over your reverse proxy's body limit. Pair them with presigned POST policy limits so a broken client can't stream unbounded bytes into the bucket.

Object lock (WORM), lifecycle/tiering, KMS, replication: configure as infrastructure-level bucket policy via the package's admin recipes, not per-request in application code. Application code should only read those behaviors (e.g. expecting a delete to fail on a locked object).

Events: the README includes a receiving route for notifications. Use it to decouple post-upload work (thumbnailing, virus scan, indexing) from the request cycle — but make the handler idempotent, since notification delivery can repeat.

Bulk operations and S3 Select: reach for S3 Select when you'd otherwise download a CSV/JSON object just to filter it; keep the query narrow and the result small.

Testing pattern: use the README's application-testing recipe to fake the disk in feature tests so unit tests stay fast, and keep a small tagged suite that hits a real RustFS container (mirroring the package's own 14-test live suite against rustfs/rustfs:1.0.3) for presigning and policy enforcement, which cannot be meaningfully faked.

Gotchas and Tips

  • The headline trap: presigned PUT gives you no size or content-type enforcement. Signing a Content-Type on a PUT is advisory — the client can send anything. If your app assumes "I signed image/png and a 5 MB limit, so that's what arrives," you have an unbounded upload and a content-type spoof. Switch those flows to presigned POST. Verify Content-Type and size with a head after upload if you must use PUT.
  • Presigned POST failures are opaque on the client. EntityTooLarge and InvalidPolicyDocument come back as XML from the storage layer, not as Laravel validation errors. Map them to friendly messages in your frontend and log the raw body — a wrong field order or an expired policy looks identical to a size violation from the browser's perspective.
  • Policy conditions are strings. Prefix conditions must match the key format you actually submit; a trailing slash or a date-partitioned key (uploads/2025/…) will trip InvalidPolicyDocument if the condition doesn't cover it.
  • Pin your RustFS version in dev and CI. The upload-security clarifications were established against RustFS 1.0.x / 1.0.3. If policy enforcement is load-bearing for you, treat storage-server upgrades as a change that needs the live suite re-run.
  • Keep the live suite small but real. The package's own live suite is 14 tests. Mirror that shape: a handful of live tests for presigning, policy rejection, and version restore; everything else faked.
  • Config quirks to check first when requests fail with signature errors: path-style vs virtual-hosted addressing, region string, and clock skew on the host (presigned URLs are time-sensitive; a container with drifting time produces RequestTimeTooSkewed).
  • Extension points: the filesystem driver config, the notification-receiving route, and the tenant/service-account/group provisioning layer are where you should extend rather than fork. Tracing and cluster-status calls are cheap to add to health checks — wire cluster status into a /health endpoint so a storage outage surfaces as a failed check rather than a wave of 500s.
  • Error handling: wrap storage calls in a single adapter so storage exceptions don't leak S3 XML into your API responses; the README's error-handling recipe is the reference for which exceptions are retryable.
  • Upgrade note: 1.0.0 → 1.0.1 is docs and tests only. There is nothing to migrate, but re-read the upload-security section even if you're already on 1.0.0 — the clarification is behavioral documentation of something that was already true, so existing PUT-based uploads may have been under-enforced all along.
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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo