Code editor
Highlighting for 13 language families, find and replace, go to line, smart indent, Ctrl+S to save. The old copy goes into the version history before every save.
Open source · MIT · v0.2
One component gives your React app a file manager that feels as fast and keyboard-friendly as the one on your desktop.
There is no server behind it: the @thefinder/core engine itself runs on this page, with a driver that keeps files in memory. Reload and
everything starts over.
theFinder is a React component, a CSS file and a single API endpoint. The interface depends on no UI library. The server side is built on the web-standard Request → Response, so the same code runs on Next.js, Bun, Node, Express, Fastify, Koa and Hono. Files live on local disk, in S3, or both. Runtime dependencies of the core: zero.
Virtual list
Version history
Trash
Deleted items wait 30 days in the .tf-trash folder inside the volume. On local disk and on S3 alike.
S3, R2, MinIO
s3Driver({
bucket: "my-bucket",
region: "auto",
endpoint: "https://…r2.cloudflarestorage.com",
})
SigV4 signing with Web Crypto. Runs on edge runtimes too.
Keyboard
Accessibility
Next.js
output: "standalone".Lasso selection, Quick Look, cut and paste, the image editor, the virtual list and how it compares to elFinder, in one silent short.
The engine is one function: finder.handler(request) takes a Request and returns a Response. Bun, Hono and
Next.js use it as is; Express, Fastify and Koa get thin adapters.
Uploads arrive in chunks and the server keeps no state between them. No body-size limits to hit, and it works on serverless too.
app/api/files/route.ts
import {
createTheFinder, createNextRoutes, localDriver, uploadsDir,
} from "@thefinder/next";
const finder = createTheFinder({
volumes: [{
id: "uploads",
driver: localDriver({ root: uploadsDir() }),
url: "/uploads",
}],
});
export const runtime = "nodejs";
export const { GET, POST } = createNextRoutes(finder);
server.ts
const driver = localDriver({ root: "./uploads" });
const finder = createTheFinder({
volumes: [{ id: "files", driver, url: "/uploads" }],
});
Bun.serve({
routes: {
"/api/files": finder.handler,
"/uploads/*": createFileServer({ driver, prefix: "/uploads" }),
},
});
server.mjs
import { toExpress } from "@thefinder/core/node";
app.all("/api/files", toExpress(finder.handler));
app.get("/uploads/*", toExpress(
createFileServer({ driver, prefix: "/uploads" }),
));
// Fine even if express.json() ran first:
// the adapter rebuilds the consumed body.
server.ts
import { toFastify } from "@thefinder/core/node";
fastify.register(toFastify(finder.handler), { prefix: "/api/files" });
// The plugin turns off body parsing in its own scope.
server.ts
import { toKoa } from "@thefinder/core/node";
router.all("/api/files", toKoa(finder.handler));
index.ts
// No adapter needed: Hono already uses the web-standard Request.
app.all("/api/files", (c) => finder.handler(c.req.raw));
Each storage is a volume. They sit side by side in the sidebar, and you can copy and move between them.
StorageDriver interface is enough.
.tf-* folders inside the volume.No Monaco, no CodeMirror, nothing loaded from a CDN. The editors ship in the package itself.
Highlighting for 13 language families, find and replace, go to line, smart indent, Ctrl+S to save. The old copy goes into the version history before every save.
Editing with a side-by-side preview. Raw HTML is not rendered and links are limited to safe schemes, so opening an untrusted file is harmless.
Crop, rotate, flip, resize; pick the format and quality. Convert selected images to WebP or AVIF in one go.
Space previews images, video, audio, PDF, code and Markdown. Video seeking works through Range requests.
useFilePicker returns a Promise: adding a “Choose file” button to your form takes three lines. Outside React,
openFilePicker.
A CKEditor 5 plugin and a CKEditor 4 connector. They do CKFinder's job: a toolbar button and uploads for pasted images.
A file manager means write access to your server. theFinder has taken that seriously from day one.
.. are rejected, never resolved. Symlinks pointing outside the root are hidden.x-thefinder header.authorize runs before every command. 401, 403 or a per-request read-only mode.readOnly per volume, permission per path, extension lists and a size limit.elFinder is the first name that comes to mind for web file managers, and it has been in the field for more than fifteen years. theFinder rethinks the same job with today's stack. Both are good tools; which one suits you depends on how your project is built.
@layer, container queries)
jQuery and jQuery UI plugin
Request → Response. Node, Bun, Deno, edge.
Official connector in PHP. Community connectors for other languages.
react (peer) in the UI.
jQuery and jQuery UI on the client
@thefinder/core/client)
One endpoint, elFinder protocol (cmd=open…)
StorageDriver
Built-in drivers
messages
More than 30 languages
useFilePicker, openFilePicker (Promise)
getFileCallback
elFinder details are based on the documentation of the 2.1 series. If you spot a wrong or outdated row, open an issue.
npm i @thefinder/core @thefinder/react @thefinder/next
@thefinder/core