oxagenDocs
Configuration

Storage driver

STORAGE_DRIVER and the filesystem driver: Oxagen's blob storage without a Vercel Blob token.

Overview

Binary assets (avatars, generated images, video, and documents, and uploaded workspace files) go through @oxagen/storage, one adapter interface with two drivers. One environment variable picks the driver:

bash
STORAGE_DRIVER=vercel-blob   # default — requires BLOB_READ_WRITE_TOKEN
STORAGE_DRIVER=fs            # local filesystem — no token required

The row that references the stored object (URL and metadata) stays in Postgres. Only the bytes move between drivers.

vercel-blob (default)

The production driver, backed by Vercel Blob. It requires BLOB_READ_WRITE_TOKEN. When this driver is selected and the token is missing, storage calls throw an error at startup that names it.

fs: the filesystem driver

The filesystem driver stores bytes on local disk instead of Vercel Blob, with no credential. Use it for local development, or in a CI or e2e container that has no Blob token.

bash
STORAGE_DRIVER=fs
STORAGE_FS_ROOT=/tmp/oxagen-storage   # optional — see default below
VariableRequiredDefault
STORAGE_DRIVERNovercel-blob
STORAGE_FS_ROOTNoAn absolute path under the OS temp directory (<tmpdir>/oxagen-storage)

Why the default root is an absolute temp path, not a path relative to cwd: the app (next start, cwd = apps/app) and the API (tsx, cwd = repo root) run as separate processes with different working directories. Both must resolve to the SAME directory, or an object one process writes is invisible to the other. An absolute path makes them match, and the temp directory is writable inside the CI e2e container. A relative STORAGE_FS_ROOT works, but it resolves against process.cwd(), so use it only for a single-process script.

Path safety. The driver confines every object key to the storage root. It rejects an absolute key, a key with .. traversal, and a key with a null byte before any file operation runs. A key cannot read or write outside STORAGE_FS_ROOT.

Adding a driver

To add a third storage driver, implement the StorageAdapter interface, add the driver name to the STORAGE_DRIVER enum in packages/config/src/env.ts, and add a case in packages/storage/src/client.ts that reads that driver's own environment variables. Each driver's credentials stay separate, so adding one never touches another's configuration.

On this page