Files
Upload, URL builders, protected-file tokens, multi-file fields, delete.
vb.files wraps the /api/v1/files/* endpoints. Pairs with the
Files concept page for the server-side rules.
Upload
Section titled “Upload”const file = inputEl.files[0]; // a Blob / File from <input type="file">const meta = await vb.files.upload("posts", post.id, "cover", file);// meta = {// id: "u-…",// filename: "uuid-…ext",// originalName: "photo.jpg",// size: 12345,// mimeType: "image/jpeg",// }The record must exist already, and uploading needs its update_rule. The upload
stores the file; setting the field to the returned filename is what attaches it
to the record:
const post = await vb.collection("posts").create({ title: "Hi" });const meta = await vb.files.upload("posts", post.id, "cover", file);await vb.collection("posts").update(post.id, { cover: meta.filename });The file must have been uploaded to that record and field: setting cover to a
file uploaded elsewhere is refused with a validation error (admins excepted).
A file that no record names is deleted by the hourly cleanup once it’s a day old, and so is the old file after you set the field to a new one.
Multi-file fields accept an array; the response is meta[]:
const metas = await vb.files.upload("posts", post.id, "attachments", [file1, file2]);await vb.collection("posts").update(post.id, { attachments: metas.map((m) => m.filename) });FileMeta and UploadOptions are exported types (SDK 0.7.2). upload with one
File returns one FileMeta, with an array an array.
The server enforces maxSize and mimeTypes from the field options
before any bytes hit storage.
const url = vb.files.url(meta.filename);// → "https://api.example.com/api/v1/files/uuid-…ext"
const thumb = vb.files.url(meta.filename, { thumb: "300x200" });// → "https://api.example.com/api/v1/files/uuid-…ext?thumb=300x200"
const cropped = vb.files.url(meta.filename, { thumb: "400x300", fit: "cover" });// → "…?thumb=400x300_cover"The URL is a plain GET, suitable for <img src> / <a href>.
Protected files
Section titled “Protected files”Fields with protected: true need a ?token= to fetch. A field with only
rule-based protection is also
served to a request with an Authorization header, but a plain <img src>
sends none, so a token is the way to show it there. The SDK mints + caches
one for you:
const tokenized = await vb.files.urlWithToken("posts", post.id, "private_doc", "uuid-…pdf");// → "https://api.example.com/api/v1/files/uuid-…pdf?token=<jwt>"
// Or just the token: { token, expires_at, one_time }const t = await vb.files.token("posts", post.id, "private_doc", "uuid-…pdf");The token is good for ~1h (server-configurable via
auth.file.window_seconds). The SDK caches it in memory per
collection, record, field and filename, and refreshes it ~60s before
expiry. Two exceptions:
- One-time tokens aren’t cached. On a field with
oneTimeToken, each token works for one download, so every call mints a fresh one. The SDK reads the server’sone_timeflag (or the token’suses: 1claim, for older servers). - The cache is dropped when the signed-in user changes (sign-in, sign-out, another account), since a token was granted to the previous identity.
vb.files.clearTokenCache() drops every cached token yourself.
Delete
Section titled “Delete”// One file from a multi-file fieldawait vb.files.delete("posts", post.id, "attachments", filename);
// Every file under (record, field): leave out the filenameawait vb.files.delete("posts", post.id, "attachments");Programmatic Blob upload
Section titled “Programmatic Blob upload”vb.files.upload accepts any Blob / File-shaped object — useful in
Node:
import { readFile } from "node:fs/promises";
const buf = await readFile("photo.jpg");const blob = new File([buf], "photo.jpg", { type: "image/jpeg" });await vb.files.upload("posts", post.id, "cover", blob);Errors
Section titled “Errors”Errors are VaultbaseErrors:
| Status | e.data | Cause |
|---|---|---|
| 400 | kind: "server", status: 400 | No file in the request, or more than one for a single-file field |
| 401 | kind: "auth", reason: "expired" | Not signed in |
| 403 | kind: "auth", reason: "forbidden" | The record’s update_rule refuses the upload, a file rule refuses the download, or an IP-bound token is used from another address |
| 404 | kind: "server", status: 404 | No such record or field |
| 410 | kind: "server", status: 410 | One-time token replayed |
| 413 | kind: "server", status: 413 | Over the server’s upload limit (files.max_upload_size) |
| 415 | kind: "server", status: 415 | MIME type outside the server’s allow-list |
| 422 | kind: "validation" | MIME type outside the field’s mimeTypes, or over its maxSize; e.data.details names the field |