Storage
VentureKit provides storage through @venturekit/storage with S3 bucket configuration, CloudFront CDN, and lifecycle policies.
1. Install the Package
Section titled “1. Install the Package”npm install @venturekit/storage@dev2. Declare Storage Intents
Section titled “2. Declare Storage Intents”Add storage definitions on defineVenture() in vk.config.ts:
export default defineVenture({ base, security, storage: [ { id: 'uploads', purpose: 'uploads', versioned: true }, { id: 'assets', purpose: 'assets' }, { id: 'backups', purpose: 'backups' }, ], envs: { dev, prod },});Override per environment (e.g. config/prod.ts):
export const prod: EnvConfigInput = { preset: 'medium', storage: [ { id: 'assets', cdn: true, corsOrigins: ['https://app.example.com'] }, ],};VentureKit auto-prefixes bucket names with {project}-{stage} at deploy time (e.g. myapp-uploads-dev).
Storage Purposes
Section titled “Storage Purposes”| Purpose | Description | Typical Config |
|---|---|---|
uploads | User-uploaded files | Versioned, private access |
assets | Static assets (images, CSS, JS) | CDN-enabled, public read |
backups | Database and application backups | Private, lifecycle rules |
logs | Application and access logs | Private, expiration rules |
Accessing Storage in Handlers
Section titled “Accessing Storage in Handlers”After deployment, storage outputs are available via ctx.intentOutputs:
import { handler } from '@venturekit/runtime';import type { IntentOutputs } from '@venturekit/core';
export const main = handler(async (_body, ctx, logger) => { const outputs = ctx.intentOutputs as IntentOutputs;
const uploadsBucket = outputs.storage['uploads'].bucketName; const assetsCdnUrl = outputs.storage['assets'].cdnUrl;
logger.info('Storage info', { uploadsBucket, assetsCdnUrl });
return { uploadsBucket, assetsCdnUrl };});CDN Configuration
Section titled “CDN Configuration”Enable CloudFront CDN for fast global delivery:
{ id: 'assets', purpose: 'assets', cdn: true, cdnDomain: 'cdn.example.com', // Custom domain (optional) corsOrigins: ['*'],}The CDN URL is available in outputs.storage['assets'].cdnUrl.
Storage Client
Section titled “Storage Client”The @venturekit/storage package includes a full-featured runtime client for interacting with S3 (production) and MinIO (local dev). It auto-detects the environment.
Create a Client
Section titled “Create a Client”import { createStorageClient, createStorageClientFromEnv } from '@venturekit/storage';
// From explicit configconst storage = createStorageClient({ bucket: 'my-uploads' });
// From environment variables (recommended)const storage = createStorageClientFromEnv();Upload Files
Section titled “Upload Files”// Simple uploadawait storage.put('avatars/user-123.jpg', imageBuffer, { contentType: 'image/jpeg', cacheControl: 'max-age=31536000',});
// Multipart upload for large filesawait storage.upload('videos/intro.mp4', videoStream, { contentType: 'video/mp4', onProgress: ({ loaded, total }) => console.log(`${loaded}/${total}`),});Download Files
Section titled “Download Files”// Download to bufferconst { body, contentType } = await storage.get('avatars/user-123.jpg');
// Download as stream (for large files)const { body: stream } = await storage.getStream('videos/intro.mp4');stream.pipe(res); // pipe to HTTP responseSigned URLs
Section titled “Signed URLs”// Signed download URL (client can download directly from S3)const downloadUrl = await storage.getSignedUrl('avatars/user-123.jpg', { expiresIn: 3600, // 1 hour});
// Signed upload URL (client can upload directly to S3)const uploadUrl = await storage.getSignedUploadUrl('avatars/user-456.jpg', { contentType: 'image/jpeg', expiresIn: 600, // 10 minutes});List, Copy, Delete
Section titled “List, Copy, Delete”// List objectsconst { objects, prefixes } = await storage.list({ prefix: 'avatars/', delimiter: '/',});
// List all (auto-paginate)const allFiles = await storage.listAll({ prefix: 'uploads/' });
// Check existenceconst exists = await storage.exists('avatars/user-123.jpg');
// Copyawait storage.copy('avatars/old.jpg', 'avatars/new.jpg');
// Moveawait storage.move('temp/upload.jpg', 'avatars/final.jpg');
// Deleteawait storage.delete('avatars/old.jpg');
// Bulk deleteawait storage.deleteMany(['temp/a.jpg', 'temp/b.jpg']);Multi-Tenant Storage
Section titled “Multi-Tenant Storage”Use the prefix option to isolate storage per tenant:
const tenantStorage = createStorageClient({ bucket: 'my-uploads', prefix: `tenants/${ctx.tenant.id}/`,});
// All operations are scoped to the tenantawait tenantStorage.put('avatar.jpg', buffer);// Actually stored at: tenants/{tenantId}/avatar.jpgLocal Development
Section titled “Local Development”During vk dev, the storage client automatically connects to MinIO (started via shared Docker Compose at ~/.vk/). No configuration changes needed. All projects share the same MinIO instance on standard ports.
The following env vars are set automatically:
| Variable | Example |
|---|---|
VENTURE_LOCAL | true |
VENTURE_MINIO_ENDPOINT | http://localhost:9000 |
VENTURE_STORAGE_BUCKET | myapp-uploads |
Buckets are project-prefixed and auto-created on first use. Open http://localhost:9001 for the MinIO console (credentials: minioadmin / minioadmin).
Related
Section titled “Related”- Infrastructure Intents — declaring storage
- Queues — message queues
- Database — database setup