ReboFilesDocs
Start3
What is ReboFiles
Getting started
Demos to run
Put it in your app6
React component
Headless: your own UI
Without a framework
Styling and themes
Keyboard and accessibility
Languages
Files9
Uploads
Previews and the viewer
Search
Live changes and large folders
Comments
Starred and fields
Versions, trash and space
Download as .zip
Word documents
The server14
The route
Frameworks and sign-in
Who may do what
Storage: S3, GCS, Azure and disk
Checking uploads
Metadata: SQLite and Postgres
Database schema
Sharing and links
Activity and notifications
Hooks, logs and limits
Retention, holds and export
Desktop and other origins
Sync a folder
Going to production
Together1
AI assistants (MCP)
Reference5
Packages
Components and hooks
Client API
HTTP routes
Status and roadmap
↑↓ to move↵ to openEsc to close38 pages

Start Getting started

Getting started

Three pieces: <FileDrive> in a page, one route of your server that keeps the entries and asks your application who may do what, and a bucket that keeps the bytes. This page puts the first two in a Next.js application; Storage is the third.
npm

Install

@rebofiles/react for the page, @rebofiles/server for the route. React 18 or later, Node 22.12 or later.

React

The page

The whole drive, in the height it is given.

app/files/page.tsx
'use client';
import { FileDrive } from '@rebofiles/react';

export default function Files() {
  return (
    <div style={{ height: '100vh' }}>
      <FileDrive base="/api/files" title="Acme Files" language="en" />
    </div>
  );
}

That is the search, My files, Shared with me, Recent and the trash, the list and the grid, previews and the viewer, versions, activity, uploads by button or by dropping files and folders, and a screen of settings. React component has every prop.

Server

The route

createDriveHandler takes a Request and gives a Response, so it is a Next.js route handler as it is.

app/api/files/[...path]/route.ts
import { byRoles, createDriveHandler, s3OptionsFrom, s3Storage, sqliteMetadata } from '@rebofiles/server';
import { session } from '@/lib/auth'; // your own

const handle = createDriveHandler({
  storage: s3Storage(s3OptionsFrom(process.env)),
  metadata: await sqliteMetadata('drive.sqlite'),
  identify: async (request) => {
    const user = await session(request);
    return user ? { id: user.id } : null;
  },
  authorize: byRoles,
  secret: process.env.REBOFILES_SECRET!,
  base: '/api/files',
});

export { handle as GET, handle as POST, handle as PATCH, handle as PUT, handle as DELETE };

identify says who is asking, from your session; byRoles answers who may do what from the drive itself. The route and Who may do what go through both.

In the page

Without a server

For a demo, a story or a test: the drive kept in the page, the bytes as Blobs.

import { FileDrive, createMemoryClient } from '@rebofiles/react';

// No server: the drive kept in the page, with the same client and the same refusals.
<FileDrive client={createMemoryClient({ user: 'You' })} />
Next

Where to go next

Repository

Run the repository

Every package and every application, from source.

git clone https://github.com/JFranciscoRobles/rebofiles
cd rebofiles && npm install
npm run dev        # the playground: the drive on this computer, at http://localhost:5180
CommandWhat it does
npm run devThe playground: the whole drive against a server in the same process, the bytes in a folder, the entries in SQLite. `?as=bea` is someone else.
npm run demoThe demo of the landing: the drive kept in the page, with Claude’s calls to the MCP tools.
npm run storageThe drive against a real bucket (R2, S3, MinIO), from `apps/storage/.env`.
npm run storage:checkThe whole way a file goes against that bucket, from Node, and everything deleted after.
npm run desktopThe desktop application, with Tauri, against the playground.
npm run siteThis site.
npm testEvery test of the packages, in Node.
npm run test:browserThe drive in Chrome with Playwright, axe on every state.
npm run typecheckTypeScript, strict, on the packages and the applications.
npm run lintBiome.