vs3

Storage Options

Configuring your storage instance.

bucket

The bucket option is required and specifies the name of the bucket to use for the storage.

const storage = createStorage({
	bucket: "my-bucket",
    // ...
});

adapter

Pass in an adapter to connect vs3 to your storage provider. See Adapters for a full list of supported adapters and their options.

import { aws } from "vs3/adapters";

const storage = createStorage({
    // ...
	adapter: aws({
        region: "us-east-1",
        credentials: {
            accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
            secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
        },
    })
});

maxFileSize

Maximum allowed file size in bytes. Files exceeding this limit will be rejected with a FILE_TOO_LARGE error. Must be a positive number. If not specified, no size limit is enforced.

const storage = createStorage({
	// ...
	maxFileSize: 10 * 1024 * 1024, // 10 MB
});

allowedFileTypes

Allowed file types for uploads. Supports MIME types (e.g. "image/png" or "image/*") and file extensions (e.g. ".png", ".jpg"). When provided, uploads that do not match are rejected with FILE_TYPE_NOT_ALLOWED.

const storage = createStorage({
	// ...
	allowedFileTypes: ["image/png", "image/jpeg", ".pdf"],
});

Note: Extensions "jpeg" and "jpg" are treated as equivalent.

contentValidators

Custom content validators for uploads. Validators are run sequentially after built-in validations (size, file type). If any validator fails, the upload is rejected with a CONTENT_VALIDATION_ERROR.

Validators can be synchronous or asynchronous functions. Each validator receives the file info and parsed metadata, and must return a validation result.

const storage = createStorage({
	// ...
	contentValidators: [
		// Simple function validator
		(ctx) => {
			if (ctx.fileInfo.name.includes("temp")) {
				return { valid: false, reason: "Temporary files not allowed" };
			}
			return { valid: true };
		},
		// Named validator for better error messages
		{
			name: "quota-check",
			validate: async (ctx) => {
				const usage = await getUserUsage(ctx.metadata.userId);
				if (usage + ctx.fileInfo.size > MAX_QUOTA) {
					return { valid: false, reason: "Storage quota exceeded" };
				}
				return { valid: true };
			},
		},
	],
});

contentValidatorTimeoutMs

The Timeout in milliseconds for each content validator. If a validator takes longer than this, the upload is rejected. Default: no timeout.

const storage = createStorage({
	// ...
	contentValidatorTimeoutMs: 5000, // 5 seconds
});

metadataSchema

Optional metadata schema to use for the storage. If provided, uploads will require metadata to be provided. The metadata will be validated against the schema before the upload is allowed. If the validation succeed, the file metadata will be passed on to the S3 Storage and stored in the metadata field of the file.

This can be any StandardSchema compatible schema. See Standard Schema for available schema libraries.

const storage = createStorage({
	// ...
	metadataSchema: z.object({ userId: z.string() }),
});

The above example will require the userId field to be provided in the metadata when uploading a file:

await upload(
    file,
    {
        userId: "user-1",
    },
);

baseUrl

You can specify a custom base URL for the storage API. Defaults to http://localhost:3000.

const storage = createStorage({
	// ...
	baseUrl: "https://example.com",
});

apiPath

Specify where the storage API handler is mounted. Defaults to /api/storage. If you are using a different path, you must also specify the apiPath option on the client.

const storage = createStorage({
	// ...
	apiPath: "/api/files",
});

middlewares

Middlewares to apply to the storage API. Middlewares are applied to every request to the storage API (e.g. api.uploadUrl()). Middlewares are applied in the order they are provided. See Middlewares for more information.

const storage = createStorage({
	// ...
	middlewares: [
		createLoggingMiddleware({ logger: console.log }),
	],
});

generateKey

A function to generate a key for the uploaded file. If not provided, a default function will be used to generate a key based on the file info. The key is used to store the file in the storage and is returned in the response.

const storage = createStorage({
	// ...
	generateKey: (fileInfo, metadata) => `${metadata.userId}/${fileInfo.name}`,
});

This is especially useful if you want to organize your files into a specific structure. You could for example add a type field to the metadata and use it to generate a key like this:

const storage = createStorage({
	// ...
    metadataSchema: z.object({ type: z.literal("profile-picture", "document", "other") }),

    // Files will be stored in the following structure:
    // uploads/
    //   - profile-picture/
    //   - document/
    //   - other/
	generateKey: (fileInfo, metadata) => `uploads/${metadata.type}/${fileInfo.name}`,
});

On this page