Filesystem
Local filesystem - the dev/test adapter. Uses node:fs/promises with a sidecar .meta.json per file. Not for production.
Installation
This adapter has no extra peer dependencies - the runtime (Node or Bun) provides everything it needs.
npm install files-sdkpnpm add files-sdkyarn add files-sdkbun add files-sdkUsage
Local filesystem. The dev/test adapter - point it at a directory and it implements the same Adapter contract as the cloud adapters using node:fs/promises. Each upload writes the body and a sidecar .meta.json file alongside it (Content-Type, ETag, user metadata) so reads round-trip cleanly. Not for production: there’s no replication, no signing, no auth.
import { Files } from "files-sdk";
import { fs } from "files-sdk/fs";
// Writes objects under `./.uploads` with a sidecar `.meta.json`
// per file for Content-Type, ETag, and user metadata. Designed for
// dev and CI - same Adapter contract as the cloud adapters, so swap
// it in via env without changing call sites.
const files = new Files({
adapter: fs({
root: "./.uploads",
// Optional: configure if a dev server exposes the same root over
// HTTP, so url() returns a browser-friendly URL instead of file://.
// urlBaseUrl: "http://localhost:3000/files",
}),
});
Options
rootstring
Absolute or relative directory the adapter manages. Created on first upload if it doesn't exist. All operations are scoped to this root — keys that resolve outside it (e.g. `../etc/passwd`) throw `Provider`.
stringurlBaseUrl?string
Optional URL prefix for `url()`. When set, `url(key)` returns `${urlBaseUrl}/${key}` — useful when a dev server (Next.js `/public` mount, `serve-static`, etc.) is exposing the same root. When unset, `url()` returns a `file://` URL — appropriate for CLIs/tests, not for browsers.
stringdefaultUrlExpiresIn?number
Accepted for backward compatibility but ignored. `url()` returns a `file://` or static-server URL, and `signedUploadUrl()` fails closed because the fs adapter has no built-in upload signer or verifier.
numberStorage layout
Body at `${root}/${key}`; sidecar at `${root}/${key}.meta.json`. Sidecars survive cp -r / git mv / partial-tree deletion. list() hides them. ETag is a SHA-1-derived stable hash computed at upload time. Files written into root by hand without a sidecar are still readable - contentType falls back to application/octet-stream and etag is absent.
Compatibility
| Method | Status | Notes |
|---|---|---|
upload |
✅ | |
download |
✅ | |
delete |
✅ | |
list |
✅ | |
search |
✅ | |
head |
✅ | |
exists |
✅ | |
copy |
✅ | |
url |
⚠️ | Returns a file:// URL by default - fine for CLIs and tests, not browsers. With urlBaseUrl set, returns <urlBaseUrl>/<key> so a dev server (Next.js /public mount, serve-static, etc.) can deliver the body. responseContentDisposition throws because neither file:// nor static-server URLs have a signature mechanism in which to bind the override. |
signedUploadUrl |
❌ | Throws - the fs adapter has no built-in upload server, signer, or verifier, so it cannot bind expiry, content type, or size limits into an upload capability. Upload through files.upload() or an application route that enforces those controls server-side. |