dreamfactory/df-file
DreamFactory file service module for adding file and directory management to REST APIs. Provides upload, download, listing, metadata, and storage operations, helping Laravel/PHP applications expose secure file handling through DreamFactory.
Understand what this is first. dreamfactory/df-file is not a standalone file library like Flysystem or Laravel's Storage. It is a service component for the DreamFactory platform — the piece that registers the file service type (local filesystem connector) into a DreamFactory 4.x instance. A "0 stars, 0 dependents" signal here just means the package is a monorepo split consumed by DreamFactory itself; treat the platform, not this repo, as the install target.
Minimal path:
composer require dreamfactory/df-file
Laravel package discovery registers the service provider; run the platform's post-update steps (php artisan migrate, config rebuild/refresh as your version requires) so the file service type appears in the admin.files).curl -H "X-DreamFactory-Api-Key: $KEY" \
"https://your-df/api/v2/files/?include_files=true&include_folders=true"
First real use case: you have a Laravel app (or a mobile/LLM client) that needs governed read/write access to a directory without giving it an SSH user or raw filesystem mount. Point the service at a scoped directory, put a role/API key in front of it, and you have a REST file API with auth, rate limiting, and audit logging already handled by DreamFactory.
Where to look first in the code: the service provider (registers the service type), the service handler class (implements list/get/create/update/delete/copy/move), and the config schema (defines the admin form fields). Those three files tell you the entire contract.
REST surface. A configured file service exposes /api/v2/{service_name}/ for the root and /api/v2/{service_name}/{path} for subpaths. The verbs you'll use daily:
GET .../?include_files=true&include_folders=true — browse/list a folder.GET .../path/to/file.txt — download (add ?content=true or similar depending on version to inline the content rather than metadata).POST .../path/to/new.txt with a body — create file; POST on a folder path — create folder.PUT — replace/overwrite.DELETE — remove file or directory.POST with X-File-* headers (copy/move source/destination) — the copy/move pattern DreamFactory uses across file-ish services.Fronting a private directory per tenant. The recurring production pattern: one file service per tenant bucket/root, or one service plus a per-role path restriction. You scope access with DreamFactory roles (allow GET only on /reports/*, etc.) rather than coding path checks yourself. This is the main reason to use df-file over Storage::disk('local') — the governance layer.
Server-side scripting for shaping. DreamFactory lets you attach pre/post-process scripts to service events (file.<verb>.pre_process / post_process depending on version). Use post_process to rewrite returned metadata (strip absolute paths, normalize timestamps, add checksums) and pre_process to validate uploads or force a tenant prefix onto the incoming path. This is where custom business logic belongs — not in a fork.
Calling it from Laravel. Treat it as an external API:
Http::withHeaders(['X-DreamFactory-Api-Key' => config('services.df.key')])
->get(config('services.df.url').'/api/v2/files/reports/q1.pdf')
->throw()
->body();
Cache the API key in config, not in code. For user-scoped access, issue a JWT via DreamFactory's /api/v2/user/session and pass it as X-DreamFactory-Session-Token; roles then apply per user.
LLM / RAG pipelines. This is the headline DreamFactory story — the file service becomes the ingestion source for local LLMs. Typical flow: an external indexer periodically lists GET /api/v2/files/docs/?include_files=true, pulls changed files, chunks and embeds them. Because DreamFactory handles auth and path scoping, your ingestion worker never needs direct disk access. Keep an eye on listing pagination (limit/offset) if you point it at a large tree.
Extension point — custom service types. If you need S3-with-custom-endpoint, WebDAV, or a virtual filesystem, don't modify df-file; create a sibling component that reuses its handler patterns. The platform loads service types by provider registration, so a new composer required package plus a service-provider registration is the sanctioned add-on route.
File::put() API. If you composer require it in a vanilla Laravel app you'll get a provider that expects DreamFactory's container bindings and config scaffolding. Verify against a real instance before promising anything to a team.www-data/nginx (or the container user) needs read/write on the root. A service that lists fine but 500s on POST is almost always this, not a bug in the package.POST to an existing path often returns a conflict rather than overwriting; use PUT for replace. Clients that blindly POST and assume upsert will surprise you.#. Multi-segment paths go straight into the route; a filename with a space that isn't encoded truncates the path server-side.root, container, storage_path, allow-upload flags) is defined by this package, so an upgrade can rename fields and orphan your saved config. Re-check service config after composer update on a major/minor bump.storage/logs/laravel.log; DreamFactory service exceptions are logged with the service name, which makes grepping trivial.df-* packages diverge fast because DreamFactory's core contracts move with the monorepo.dreamfactory/df-file to a version compatible with your core dreamfactory/df version, and upgrade them together; a mismatched component/core pair is a common source of "service type registered but broken on create."How can I help you explore Laravel packages today?