Open-source project
zenhosta/9drive avatar
zenhosta/9drive

9Drive: pooling several Google Drive and S3 accounts into one dashboard that routes uploads by free space

9Drive is a storage gateway web app for connecting multiple Google Drive accounts into one virtual storage dashboard. Users can connect Google Drive accounts, track quota, upload files, organize files with virtual folders, preview files, and let the backend route uploads to the Drive account with enough free space.

2,006 stars399 forksTypeScriptApache-2.0

At a glance

What is it?
9Drive is an Apache-2.0 storage gateway that unifies multiple Google Drive and S3-compatible accounts. Its backend streams uploads straight to whichever account has room, so files never land on the server.
Who is it for?
Adopt 9Drive if you want a shared, self-hosted dashboard that pools multiple Google Drive and S3-compatible accounts, routes uploads to whichever has free space, and exposes a key-authenticated upload API, all while streaming files straight to the provider instead of the server.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 24 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 17, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

One dashboard over many storage accounts

9Drive is a storage gateway web app that connects multiple Google Drive accounts, and S3-compatible providers, into one virtual dashboard. The README describes the core loop: users register with email and password or Google, connect their first Drive account automatically during Google sign-in, track quota, upload files into a dedicated `9drive` Drive folder, organize them with virtual folders, and let the backend route uploads to the Drive account with enough free space.

The user is someone who has spread storage across several free Drive accounts, or across Drive plus an S3 provider, and wants to treat them as a single pool instead of logging into each. The S3 side supports custom endpoints for MinIO, Cloudflare R2, Wasabi, Backblaze B2 and AWS S3, so it is not Google-only.

What makes the design more than a file manager is the routing. The README lists upload routing policies with most-available, round-robin and priority-order modes, so the gateway decides which backing account receives a file. That turns a set of separate accounts into something that behaves like one larger store, which is the whole point of a gateway.

Uploads stream through, they do not land on the server

The architectural decision worth calling out is that 9Drive does not store your files. The README states uploads are a direct stream to Google Drive, with files not stored on the server, and the same for S3-compatible storage, streamed through the backend without exposing storage credentials to the frontend.

That matters for two reasons. It keeps the server stateless with respect to file data, so 9Drive itself does not need large disk, and it keeps provider credentials on the backend rather than in the browser. The README reinforces the credential point elsewhere: the global Google OAuth config is stored encrypted in the database, and S3 credentials are never exposed to the frontend. For a gateway that holds access to several storage accounts, keeping those secrets server-side and encrypted is the right posture.

The stack behind this is an Express and TypeScript backend with a React and Vite frontend, backed by MySQL through Prisma migrations. The README notes a manual sync from the Google Drive `9drive` folder back into MySQL, which acknowledges an inherent gateway problem: the source of truth is the provider, and the local database is an index that can drift, so a sync step exists to reconcile them.

Getting it running with the setup script

The README's recommended path is an automated setup script that generates environment files with secure keys, installs dependencies and generates the Prisma client. On Linux or macOS:

bash
bash ./setup.sh

You enter your MySQL connection URL when prompted, and Google client credentials can be skipped and configured later. The prerequisites the README lists are Node.js 20 or newer, npm, a running MySQL, a Google Cloud project and a Google OAuth client ID and secret. After setup you apply migrations and start the two apps in separate terminals:

bash
cd backend
npm run prisma:migrate
npm run dev

and for the frontend:

bash
cd frontend
npm run dev

The README also documents a manual path, creating the database with `mysql -u root -e "CREATE DATABASE IF NOT EXISTS 9drive;"` and writing `backend/.env` with keys such as `DATABASE_URL`, `JWT_ACCESS_SECRET`, `TOKEN_ENCRYPTION_KEY` and `MAX_UPLOAD_BYTES`, plus a Docker Compose path that bundles MySQL. The default database it assumes is `9drive` on `localhost:3306` as root with an empty password, which is a development default you should change before exposing anything.

An external upload API with real key management

9Drive is more than a UI. The README documents an external upload API at `POST /api/v1/uploads` authenticated with API keys, which turns the gateway into a programmable upload target for other applications. The key management around it is more careful than many projects bother with: one-time secret display, hashed key storage, last-used tracking and revocation.

That combination, showing a secret once, storing only its hash, tracking use and allowing revocation, is the standard for handling API keys well, and its presence signals the project thought about the case where a key leaks. A gateway with write access to several storage accounts is a meaningful thing to hand an API key to, so hashed storage and revocation are not optional niceties here.

The README rounds this out with in-app API documentation carrying cURL and JavaScript upload examples, and bearer-token authentication for the app itself. Together with the routing policies, that makes 9Drive usable as a backing upload service, an application can `POST` a file and let 9Drive place it on whichever account has space, without the application knowing anything about the underlying Drive or S3 accounts.

Where a Drive-pooling gateway gets fragile

The honest limitations sit in what a gateway over consumer storage can promise. The manual MySQL sync from the `9drive` folder is a tell: because the providers own the files, the local index can fall out of step if files change outside 9Drive, and reconciling that is a manual action rather than something guaranteed to be always current. Anyone treating 9Drive as authoritative should understand the database is a cache of the provider state.

There is also the dependency on Google's OAuth and API terms. Pooling multiple Google Drive accounts and routing uploads across them relies on continued API access under Google's policies, which is outside the project's control. And the README's documented default of a root MySQL user with an empty password, plus placeholder secrets in the sample `.env`, are development conveniences that would be a serious problem if carried into a deployment unchanged.

Finally, the security of the whole system concentrates in the encryption key. Storage tokens and the global OAuth config are encrypted at rest with `TOKEN_ENCRYPTION_KEY`, so that key protects access to every connected account. Handling it carelessly undermines the credential isolation the rest of the design works to maintain.

Against a mount-based tool like rclone

The closest alternative in spirit is a tool like rclone, which can also present multiple cloud storage backends and even union them into one view. rclone is mature, command-line first, and supports far more providers.

The difference in approach is what 9Drive adds on top: a multi-user web application with accounts, a quota dashboard, virtual folders, file preview and an authenticated external upload API with managed keys and space-aware routing policies. rclone is a powerful engine for a single operator moving data; 9Drive is a hosted service several users log into, with the upload-routing and key-management features that a shared gateway needs. The cost of that is running a stack, MySQL, an Express backend, a React frontend and OAuth setup, where rclone is a single binary. Choose rclone when one person needs flexible, scriptable access to many backends. Choose 9Drive when you want a shared dashboard and a programmable upload endpoint that pools accounts and routes by free space, and you are willing to operate the web app to get it.

Apache-2.0, in-app updates, and what to harden first

9Drive is Apache-2.0, which permits commercial use and derivatives with attribution and includes the patent grant, a permissive choice for a project others may want to self-host and modify. The README even documents automated system updates via an `update.sh` script triggered from the Settings UI under a PM2 setup, so the running instance can update itself, which is convenient for a self-hoster but is also a privileged action to expose in a web UI.

Upgrade cost is the usual Node and Prisma story: MySQL migrations run with `npm run prisma:migrate`, and the pinned stack of Express, Prisma, React and Vite moves at its own pace. The Docker Compose path, which bundles MySQL, is the most reproducible way to keep an instance consistent across upgrades.

The concrete first step before any real use is to replace the development defaults the README ships with: set a strong `JWT_ACCESS_SECRET` and a proper `TOKEN_ENCRYPTION_KEY`, move MySQL off the empty-password root default, and provide real Google OAuth credentials. Those defaults exist to make first-run frictionless, and every one of them is a liability the moment the app is reachable by anyone but you.

Editorial conclusion

Adopt 9Drive if you want a shared, self-hosted dashboard that pools multiple Google Drive and S3-compatible accounts, routes uploads to whichever has free space, and exposes a key-authenticated upload API, all while streaming files straight to the provider instead of the server. It is the wrong choice if you need an authoritative store rather than an index that requires a manual sync from the 9drive folder, or if you are unwilling to run a MySQL, Express and React stack with proper OAuth setup. Before exposing it, replace every development default the README ships: the empty-password root MySQL, the placeholder JWT_ACCESS_SECRET and TOKEN_ENCRYPTION_KEY, since that key protects access to every connected account.

Frequently asked questions

Does 9Drive store my uploaded files on its own server?

No. The README states uploads are streamed directly to Google Drive or S3-compatible storage and are not stored on the server, with storage credentials kept on the backend and never exposed to the frontend.

How does 9Drive decide which account an upload goes to?

Through upload routing policies. The README lists most-available, round-robin and priority-order modes, so the backend can route a file to the Google Drive or S3 account with enough free space.

What do I need to run 9Drive?

The README lists Node.js 20 or newer, npm, a running MySQL, a Google Cloud project, and a Google OAuth client ID and secret. The automated setup.sh script generates environment files and the Prisma client, or a Docker Compose path bundles MySQL.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. Project website
  4. README
  5. zenhosta/9drive on GitHub
Community notes

Community notes