fastify-xstorage
fastify-xstorage
S3-compatible file storage for Fastify v5. Register once and get fastify.xStorage — a full-featured decorator covering upload, download, delete, copy, move, list, existence checks, metadata, signed download URLs, and presigned upload URLs. Works with AWS S3, Cloudflare R2, DigitalOcean Spaces, and any S3-compatible provider.
Installation
npm install @xenterprises/fastify-xstorage
For HTTP file uploads, also install:
npm install @fastify/multipart@9
Quick Start
import Fastify from "fastify";
import xStorage from "@xenterprises/fastify-xstorage";
const fastify = Fastify({ logger: true });
await fastify.register(xStorage, {
accessKeyId: process.env.STORAGE_ACCESS_KEY_ID,
secretAccessKey: process.env.STORAGE_SECRET_ACCESS_KEY,
bucket: process.env.STORAGE_BUCKET,
publicUrl: process.env.STORAGE_PUBLIC_URL,
endpoint: process.env.STORAGE_ENDPOINT, // omit for AWS S3
});
// Upload a file
const result = await fastify.xStorage.upload(buffer, "photo.jpg", {
folder: "avatars",
});
// { key: "avatars/photo-a1b2c3d4.jpg", url: "https://cdn.example.com/...", ... }
// Signed download URL (1 hour)
const url = await fastify.xStorage.getSignedUrl(result.key, 3600);
Options
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
accessKeyId | string | — | Yes | Storage access key ID |
secretAccessKey | string | — | Yes | Storage secret access key |
bucket | string | — | Yes | Bucket name |
publicUrl | string | — | Yes | Base public URL for the bucket (trailing slash trimmed automatically) |
endpoint | string | — | No | Custom endpoint URL for R2/DO Spaces/other providers; omit for AWS S3 |
region | string | "us-east-1" | No | AWS region or "auto" for Cloudflare R2 |
forcePathStyle | boolean | true | No | Use path-style S3 URLs (required by most non-AWS providers) |
acl | string | "private" | No | Default ACL applied to uploads |
Methods
Upload
- upload(file, filename, options?) — Upload a single file with auto-naming, folder prefix, and MIME detection.
- uploadMultiple(files, options?) — Upload multiple files concurrently.
Download
- download(key) — Download a file and return it as a
Buffer.
Delete
- delete(key) — Delete a single file.
- deleteMultiple(keys) — Batch-delete multiple files via the S3
DeleteObjectsAPI.
Copy & Move
- copy(sourceKey, destinationKey, options?) — Copy a file within the bucket.
- move(sourceKey, destinationKey, options?) — Move a file (copy then delete source).
Metadata & Existence
- exists(key) — Check whether a file exists without downloading it.
- getMetadata(key) — Get content type, size, last-modified, ETag, and custom metadata.
List
- list(prefix?, maxKeys?) — List files under a prefix (single page, up to
maxKeys). - listAll(prefix?) — List all files under a prefix with automatic pagination.
URLs
- getSignedUrl(key, expiresIn?) — Generate a temporary pre-signed download URL.
- getSignedUploadUrl(key, options?) — Generate a pre-signed upload URL for direct client-to-S3 uploads.
- getPublicUrl(key) — Synchronously construct the public URL for a file.
Error Reference
| Error | Cause |
|---|---|
[xStorage] accessKeyId is required and must be a string | Missing or non-string accessKeyId at registration |
[xStorage] secretAccessKey is required and must be a string | Missing or non-string secretAccessKey |
[xStorage] bucket is required and must be a string | Missing or non-string bucket |
[xStorage] publicUrl is required and must be a string | Missing or non-string publicUrl |
[xStorage] endpoint must be a string when provided | Non-string endpoint |
[xStorage] file is required for upload | upload() called without a file |
[xStorage] filename is required and must be a string | Missing or non-string filename |
[xStorage] files must be a non-empty array | uploadMultiple() given empty or non-array |
[xStorage] keys must be a non-empty array of strings | deleteMultiple() given empty or non-array |
[xStorage] key is required and must be a string | Any method called without a valid key |
[xStorage] expiresIn must be a positive number (seconds) | Non-positive expiresIn |
[xStorage] Failed to upload file "<key>": <reason> | S3 API error during upload |
[xStorage] Failed to download file "<key>": <reason> | S3 API error during download |
[xStorage] Failed to delete file "<key>": <reason> | S3 API error on single delete |
[xStorage] Failed to delete multiple files: <reason> | S3 API error on batch delete |
[xStorage] Failed to copy "<src>" to "<dst>": <reason> | S3 API error on copy |
[xStorage] Failed to list files with prefix "<prefix>": <reason> | S3 API error on list |
[xStorage] Failed to get metadata for "<key>": <reason> | HeadObject error |
[xStorage] Failed to generate signed URL for "<key>": <reason> | Pre-signer error on download URL |
[xStorage] Failed to generate signed upload URL for "<key>": <reason> | Pre-signer error on upload URL |
Environment Variables
| Variable | Required | Description |
|---|---|---|
STORAGE_ACCESS_KEY_ID | Yes | Storage access key ID |
STORAGE_SECRET_ACCESS_KEY | Yes | Storage secret access key |
STORAGE_BUCKET | Yes | Bucket name |
STORAGE_PUBLIC_URL | Yes | Base public URL for the bucket |
STORAGE_ENDPOINT | No | Custom endpoint for R2/DO Spaces/other providers |
STORAGE_REGION | No | AWS region (default "us-east-1") |
How It Works
On registration the plugin validates all required options, creates an S3Client with the provided credentials and optional custom endpoint, then decorates fastify.xStorage with all storage methods. The publicUrl trailing slash is normalised once at startup. Uploaded files get a random 8-byte hex suffix by default to avoid collisions (useRandomName: false disables this). MIME types are auto-detected from the filename extension via mime-types. list() returns a single page up to maxKeys; listAll() follows ContinuationToken until all results are fetched. move() is copy-then-delete. exists() uses HeadObject and returns false on 404 without throwing. getSignedUploadUrl() generates a PutObject presigned URL so clients can upload directly to storage without routing file payloads through your Fastify server.
AI Context
package: "@xenterprises/fastify-xstorage"
type: fastify-plugin
use-when: File storage with AWS S3, Cloudflare R2, or DigitalOcean Spaces — upload, download, delete, copy/move, list, signed URLs
decorator: fastify.xStorage
env: STORAGE_ACCESS_KEY_ID, STORAGE_SECRET_ACCESS_KEY, STORAGE_BUCKET, STORAGE_PUBLIC_URL, STORAGE_ENDPOINT (optional), STORAGE_REGION (optional)
requires: accessKeyId, secretAccessKey, bucket, publicUrl at registration
