File Storage
File read, write, list, and delete with local and S3 drivers
File storage. Available via ctx.files.
// Write a file (string or Buffer)
await ctx.files.write('avatars/user-123.jpg', imageBuffer);
// Read a file (returns Buffer or null)
const buffer = await ctx.files.read('avatars/user-123.jpg');
// Delete a file (no error if missing)
await ctx.files.delete('avatars/user-123.jpg');
// List files under a prefix
const fileList = await ctx.files.list('avatars/');
// ['avatars/user-123.jpg', 'avatars/user-456.jpg']
// Check existence
const exists = await ctx.files.exists('avatars/user-123.jpg');File Upload Example
// api/upload.js
export const POST = {
handler: async (ctx) => {
const { files } = ctx;
const { filename, data } = ctx.req.body; // Base64 or buffer
const path = `uploads/${Date.now()}-${filename}`;
await files.write(path, Buffer.from(data, 'base64'));
return { data: { path } };
},
};Namespacing
Create a namespaced file store:
const avatars = ctx.files.withNamespace('avatars');
await avatars.write('user-123.jpg', buffer); // Stored at 'avatars/user-123.jpg'
await avatars.list(''); // Lists only files under 'avatars/'Path Security
Both drivers enforce path traversal protection — paths containing .. or starting with / are rejected.
File Storage Drivers
Local (default) — stores files on the filesystem under .build/storage/:
export default {
files: {
driver: 'local',
local: {
root: '.build/storage', // Default
},
},
};- Automatically creates directories on write
list()recursively walks subdirectories- Paths normalized to forward slashes
S3 — AWS S3 or S3-compatible storage (MinIO, DigitalOcean Spaces, etc.):
export default {
files: {
driver: 's3',
s3: {
bucket: 'my-bucket',
region: 'us-east-1', // Default
endpoint: 'https://...', // Optional: custom S3-compatible endpoint
forcePathStyle: true, // Optional: for MinIO compatibility
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
},
},
};