Product — FluxFiles
Everything a modern file manager needs
Built for developers who need flexibility.
Multi-storage
Local, AWS S3, Cloudflare R2, SFTP via Flysystem v3 — swap with config, no code change.
Embed anywhere
iframe + postMessage SDK. Standalone UI is Alpine.js (zero build). Works with any framework.
JWT auth + scoping
Per-user path prefix, permission claims, disk whitelist, owner-only mode — or start from a viewer/editor/admin role preset.
ACL role presets
Mint tokens from viewer / editor / admin / superadmin presets — one parameter expands to the right permission, disk, and scope claims instead of hand-assembling them.
AI auto-tag
Claude / OpenAI vision — auto alt text, title, tags.
Image crop
Inline crop tool with aspect ratio presets.
Image optimization
Auto WebP variants — thumb, medium, large.
Presigned uploads
Browser uploads directly to S3/R2 — zero bandwidth on your server.
Chunk upload
S3 multipart for files > 10MB.
Full-text search
Indexed search across names, titles, tags — file-based by default, or your own SQL database as an opt-in backend.
DB-backed metadata
Opt-in FLUXFILES_STORAGE_BACKEND=db mode — metadata, search/folder index, and audit log live in your own MySQL/PostgreSQL/SQLite instead of JSON sidecars. File bytes stay storage-resident either way.
Bulk operations
Multi-select move, copy, delete, download.
Cross-disk transfer
Copy/move between Local ↔ S3 ↔ R2.
Trash / soft delete
Recoverable deletes with auto-purge.
SEO metadata
Title, alt, caption, tags — S3 object metadata (cloud) or sidecar JSON (local). Full-text search.
Dark mode
Light / dark / auto in UI and SDK.
16 languages
Default English. Set locale via SDK, URL (?locale=), or FLUXFILES_LOCALE. RTL for Arabic.
Audit log
All write actions logged for compliance.
Rate limiting
Token bucket per user for API protection.
Storage quota
Per-user storage limits via JWT claims.
BYOB buckets
Users bring their own S3/R2 — credentials encrypted in JWT (AES-256-GCM).
Duplicate detection
SHA-256 match skips redundant uploads unless you force overwrite.
SDK token refresh
onTokenRefresh on 401 — coalesced refresh, retry, and updateToken() for proactive rotation.
Bucket Doctor
Diagnose any S3/R2 disk — credentials, read/write/delete, presign, CORS, multipart — with ready-to-paste IAM & CORS fixes. Onboard BYOB buckets in minutes.
SFTP disk
A 3rd driver after S3/R2 — turn any VPS or shared host into a managed file manager.
Code / config editor
Edit text and config files (wp-config.php, .env, nginx.conf) in-browser, cPanel-style.
Zip & Extract
Download a selection as a zip, or extract an archive in place — zip-slip & bomb guarded.
Watermark
Apply a text or logo watermark on the fly for preview protection — the source is never touched.
On-demand WebP + AVIF
Serve any image size as cached AVIF/WebP via one URL (Accept-negotiated), with ready responsive srcset.
SFTP permissions
Change Unix file permissions (chmod) on SFTP disks with a cPanel-style dialog.
SSH terminal
A stateless command-runner terminal on SFTP disks — cPanel-style admin tooling, built in and free (or embed your own ttyd for a full PTY).
One-click Git deploy
Pull and reset a Git repo on your SFTP server straight from the file manager — fixed-shape, no arbitrary shell, hooks off by default.
Usage dashboard
See storage at a glance — quota plus a per-type and per-folder breakdown.
Media preview
Inline image, video, audio & PDF preview; private local media streams securely (Range-capable).
Up and running in 2 minutes
composer require fluxfiles/fluxfiles
cp .env.example .env
# .env
FLUXFILES_SECRET=your-random-32-char-secret
FLUXFILES_ALLOWED_ORIGINS=https://yourapp.com
require_once 'vendor/autoload.php';
$token = fluxfiles_token(
userId: 'user-123',
perms: ['read', 'write', 'delete'],
disks: ['local', 's3', 'r2'],
prefix: 'user-123/',
maxUploadMb: 10,
allowedExt: null,
ttl: 3600
); composer require fluxfiles/laravel
php artisan vendor:publish --tag=fluxfiles-config
# .env — point the adapter at your FluxFiles server
FLUXFILES_ENDPOINT=https://fm.yourdomain.com
FLUXFILES_SECRET=your-secret-min-32-chars
# Optional: match CORS on the FluxFiles host
# FLUXFILES_ALLOWED_ORIGINS=https://yourapp.com
# Config: config/fluxfiles.php npm install @fluxfiles/node
// Express / Next.js route — mint a token from your JS backend (no PHP)
import { createToken } from '@fluxfiles/node';
app.get('/fluxfiles-token', (req, res) => {
const token = createToken({
secret: process.env.FLUXFILES_SECRET, // >= 32 bytes
userId: req.user.id,
perms: ['read', 'write', 'delete'],
prefix: `users/${req.user.id}`,
ttl: 3600,
});
res.json({ token });
}); pip install fluxfiles-token
# FastAPI / Django / Flask route — mint a token from your Python backend (no PHP)
from fluxfiles_token import create_token
@app.get("/fluxfiles-token")
def fluxfiles_token(user=Depends(current_user)):
token = create_token(
secret=os.environ["FLUXFILES_SECRET"], # >= 32 bytes
user_id=user.id,
perms=["read", "write", "delete"],
prefix=f"users/{user.id}",
ttl=3600,
)
return {"token": token} <!-- Demo: unpkg. In production, serve fluxfiles.js from your FluxFiles host -->
<script src="https://unpkg.com/fluxfiles@latest/fluxfiles.js"></script>
<script>
FluxFiles.open({
endpoint: 'https://your-api.com',
token: 'eyJhbGci...',
disk: 'local',
mode: 'picker',
container: '#file-picker',
onSelect: function(file) {
console.log('Selected:', file.url);
},
async onTokenRefresh() {
const r = await fetch('/api/auth/refresh-fluxfiles-token');
const { token } = await r.json();
return token;
}
});
</script> npm install @fluxfiles/react
import { FluxFilesModal } from '@fluxfiles/react';
<FluxFilesModal
open={open}
endpoint="https://your-api.com"
token={token}
onSelect={(file) => console.log(file)}
onClose={() => setOpen(false)}
/> npm install @fluxfiles/vue
<script setup>
import { FluxFilesModal } from '@fluxfiles/vue';
</script>
<FluxFilesModal
v-model:open="open"
endpoint="https://your-api.com"
:token="token"
@select="onSelect"
@close="open = false"
/> git clone https://github.com/thai-pc/fluxfiles.git
docker build -f fluxfiles/docker/Dockerfile.prod -t fluxfiles fluxfiles
docker run -p 8080:80 \\
-e FLUXFILES_SECRET=your-random-32-char-secret \\
fluxfiles
# UI: http://localhost:8080/public/index.html git clone https://github.com/thai-pc/fluxfiles.git
cd fluxfiles
composer install -d packages/core
cp .env.example .env
cd packages/core
php -S localhost:8080 router.php
# UI: http://localhost:8080/public/index.html
# API: http://localhost:8080/api/fm/list?disk=local&path= Works with
Integrations
Drop-in adapters for your stack
Official adapters embed FluxFiles natively in the frameworks and editors you already use.
Embed
Embed it in a few lines
Load fluxfiles.js, pass a server-minted JWT, and drop a full file manager — or a file-picker modal — into any page.
<script src="https://fm.example.com/fluxfiles.js"></script>
FluxFiles.open({
endpoint: 'https://fm.example.com',
token: 'eyJhbGci...', // JWT from your backend
disk: 'local',
mode: 'picker', // select & close
theme: 'auto',
onSelect(file) {
// { url, key, name, size, disk, meta, variants }
document.querySelector("#img").src = file.url;
},
}); <div id="fm" style="height:600px"></div>
FluxFiles.open({
endpoint: 'https://fm.example.com',
token: 'eyJhbGci...',
mode: 'browser', // full manager, stays open
container: '#fm', // omit for a modal overlay
disks: ['local', 's3', 'r2'],
});
FluxFiles.on('FM_EVENT', (e) => console.log(e.event));
FluxFiles.navigate('/photos/2024'); import { FluxFilesModal } from '@fluxfiles/react';
function Picker({ open, setOpen, token }) {
return (
<FluxFilesModal
open={open}
endpoint="https://fm.example.com"
token={token}
onSelect={(file) => console.log(file.url)}
onClose={() => setOpen(false)}
/>
);
} Tokens are minted server-side — never ship your secret to the browser.
Built for what others forgot
| Feature | FluxFiles | elFinder | Laravel-FM | RichFilemanager | Responsive FM |
|---|---|---|---|---|---|
| S3 + R2 + Local + SFTP | ✓ | ⚠ | ⚠ | ⚠ | ✗ |
| Embed any framework | ✓ | ⚠ | ✗ | ⚠ | ✗ |
| JWT auth + scoping | ✓ | ✗ | ✗ | ✗ | ✗ |
| SEO metadata | ✓ | ✗ | ✗ | ✗ | ✗ |
| AI auto-tag | ✓ | ✗ | ✗ | ✗ | ✗ |
| Image crop | ✓ | ✓ | ✗ | ✗ | ✗ |
| Chunk upload | ✓ | ✗ | ✗ | ✗ | ✗ |
| Full-text search | ✓ | ✗ | ✗ | ✗ | ✗ |
| Dark mode | ✓ | ✗ | ⚠ | ✗ | ✗ |
| 16 languages | ✓ | ✓ | ✗ | ✗ | ✗ |
| PHP ≥ 8.1 | ✓ | ✓ | ✗ | ✓ | ✓ |
| Actively maintained | ✓ | ✓ | ⚠ | ✗ | ✗ |
| Modern UI | ✓ | ✗ | ⚠ | ✗ | ✗ |
| Capability | FluxFiles | Filestack | Uploadcare | Cloudinary | Supabase Storage |
|---|---|---|---|---|---|
| Self-hosted (runs in your infra) | ✓ | ✗ | ✗ | ✗ | ⚠ |
| BYOB — each customer’s own bucket | ✓ | ⚠ | ⚠ | ✗ | ✗ |
| Embeddable file-manager UI | ✓ | ✓ | ✓ | ⚠ | ✗ |
| Open source (MIT) | ✓ | ✗ | ✗ | ✗ | ✓ |
| No per-storage / per-upload SaaS fees | ✓ | ✗ | ✗ | ✗ | ⚠ |
| Multi-storage (S3 / R2 / local) | ✓ | ⚠ | ✗ | ✗ | ✗ |
| Per-tenant token scoping built in | ✓ | ⚠ | ⚠ | ⚠ | ⚠ |
Comparison reflects typical default offerings; each product excels in its own space. FluxFiles’ niche is the embeddable, self-hosted, bring-your-own-bucket combination.
Comparison as of September 2026, unaffiliated — see the GitHub repo to flag a correction.
FAQ