Skip to content

Storage

@veloxts/storage provides unified file storage with local filesystem and S3-compatible drivers (AWS S3, Cloudflare R2, MinIO).

Terminal window
pnpm add @veloxts/storage
# For S3/R2 (production)
pnpm add @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner
import { storagePlugin } from '@veloxts/storage';
app.register(storagePlugin({
driver: 'local',
config: {
root: './storage',
baseUrl: 'http://localhost:3030/files',
},
}));
// Upload
await ctx.storage.put('avatars/user-123.jpg', buffer, {
contentType: 'image/jpeg',
visibility: 'public',
});
// Download
const content = await ctx.storage.get('avatars/user-123.jpg');
// Stream large files
const stream = await ctx.storage.stream('large-file.zip');
// Get URL
const url = await ctx.storage.url('avatars/user-123.jpg');
// Check existence
const exists = await ctx.storage.exists('avatars/user-123.jpg');
// Delete
await ctx.storage.delete('old-file.pdf');

Temporary access to private files:

const signedUrl = await ctx.storage.signedUrl('private/document.pdf', {
expiresIn: 3600, // 1 hour
});
// Copy
await ctx.storage.copy('old/path.jpg', 'new/path.jpg');
// Move
await ctx.storage.move('temp/upload.jpg', 'permanent/file.jpg');
// Metadata
const meta = await ctx.storage.metadata('file.jpg');
// { path, size, lastModified, contentType }
// List files
const { files, hasMore, cursor } = await ctx.storage.list('uploads/', {
limit: 100,
});

Local

Filesystem storage for development.

S3

AWS S3, Cloudflare R2, MinIO, DigitalOcean Spaces.

FeatureLocalS3/R2
Shared across instancesNoYes
Persists across deploysMaybeYes
CDN integrationManualBuilt-in
ScalabilityLimitedUnlimited
Signed URLsNoYes
ProviderBest For
Cloudflare R2Zero egress fees, global edge
AWS S3Mature ecosystem
DigitalOcean SpacesSimple pricing
MinIOSelf-hosted
.env (AWS S3)
S3_BUCKET=my-bucket
S3_REGION=us-east-1
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=...
.env (Cloudflare R2)
R2_BUCKET=my-bucket
R2_ACCOUNT_ID=your-account-id
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
src/index.ts
app.register(storagePlugin({
driver: 's3',
config: {
bucket: process.env.S3_BUCKET,
region: process.env.S3_REGION,
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
// Optional
endpoint: process.env.S3_ENDPOINT, // For R2, MinIO
forcePathStyle: false, // true for MinIO
defaultVisibility: 'private',
publicUrl: 'https://cdn.example.com', // CDN URL
},
}));
  1. S3-compatible storage - Local doesn’t scale
  2. Bucket policies - Least privilege access
  3. CORS configuration - For browser uploads
  4. Signed URLs - Time-limited private access
  5. CDN - For public files