Options
Complete reference for all createBetterMedia configuration options.
All options are passed to createBetterMedia(config). Only storage, database, and plugins are required.
import { createBetterMedia } from "@better-media/framework";
const media = createBetterMedia({
storage, // required
database, // required
plugins, // required
jobs, // optional
fileHandling, // optional
trustedPolicy, // optional
events, // optional
settings, // optional
});storage — required
A StorageAdapter instance. Controls where file bytes are stored.
storage: StorageAdapterAvailable adapters: S3 · Filesystem · Memory
database — required
A DatabaseAdapter instance (or a raw pg.Pool for the built-in Postgres path).
database: DatabaseAdapter | pg.PoolAvailable adapters: Postgres · MySQL · SQLite · MongoDB
plugins — required
An ordered array of PipelinePlugin instances. Plugins run in the order provided within each phase.
plugins: PipelinePlugin[]Available plugins: Validation · Media Processing · Virus Scan
jobs — optional
A JobAdapter for background execution. When omitted and background plugins are registered, the framework defaults to an in-process memory adapter (jobs run with setImmediate).
jobs?: JobAdapterProvide a BullMQ adapter for production:
import { bullmqJobAdapter } from "@better-media/adapter-jobs-bullmq";
jobs: bullmqJobAdapter({
connection: { host: "localhost", port: 6379 },
queueName: "better-media:background", // default
defaultJobOptions: {
attempts: 3,
backoff: { type: "exponential", delay: 1000 },
},
})See Background Jobs for full setup.
fileHandling — optional
Controls how the framework loads file bytes before passing them to plugins.
fileHandling?: {
maxBufferBytes?: number;
}| Option | Default | Description |
|---|---|---|
maxBufferBytes | undefined (no limit) | Files larger than this are streamed to a temp file instead of loaded into memory. Requires the storage adapter to implement getSize and getStream. |
fileHandling: {
maxBufferBytes: 50 * 1024 * 1024, // 50 MB — stream files larger than this
}trustedPolicy — optional
Controls which plugins are allowed to write to trusted metadata fields. Required only when registering a custom plugin that declares trustLevel: "trusted". See Plugin Architecture for details.
events — optional
Lifecycle event callbacks. See Events & Webhooks for the full reference.
events?: {
onUploadComplete?: (result: MediaResult) => void | Promise<void>;
onProcessingComplete?: (event: ProcessingCompleteEvent) => void | Promise<void>;
onError?: (error: Error, context: ErrorEvent) => void | Promise<void>;
}events: {
onUploadComplete: createWebhookEmitter("https://example.com/hooks", process.env.WEBHOOK_SECRET),
onError: async (err, ctx) => { await errorTracker.capture(err, ctx); },
}settings — optional
Framework-level settings.
settings?: {
logLevel?: "debug" | "info" | "warn" | "error";
}| Option | Default | Description |
|---|---|---|
logLevel | "info" | Controls framework log verbosity. |
Full Example
import { createBetterMedia, createWebhookEmitter } from "@better-media/framework";
import { S3StorageAdapter } from "@better-media/adapter-storage-s3";
import { KyselyDbAdapter } from "@better-media/adapter-db-kysely";
import { bullmqJobAdapter } from "@better-media/adapter-jobs-bullmq";
import { validationPlugin } from "@better-media/plugin-validation";
import { mediaProcessingPlugin } from "@better-media/plugin-media-processing";
import { virusScanPlugin, ClamScanner } from "@better-media/plugin-virus-scan";
import { schema } from "@better-media/core";
import { Kysely, PostgresDialect } from "kysely";
import { Pool } from "pg";
export const media = createBetterMedia({
storage: new S3StorageAdapter({
region: process.env.AWS_REGION!,
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
bucket: process.env.S3_BUCKET!,
}),
database: new KyselyDbAdapter(
new Kysely({ dialect: new PostgresDialect({ pool: new Pool({ connectionString: process.env.DATABASE_URL }) }) }),
{ config: { provider: "pg" }, schema }
),
plugins: [
validationPlugin({
executionMode: "sync",
allowedMimeTypes: ["image/jpeg", "image/png", "image/webp"],
maxBytes: 25 * 1024 * 1024,
preventDuplicates: true,
}),
virusScanPlugin({
scanner: new ClamScanner(),
executionMode: "sync",
onFailure: "abort",
}),
mediaProcessingPlugin({
executionMode: "background",
thumbnailPresets: [
{ name: "sm", width: 320, format: "webp" },
{ name: "lg", width: 1200, format: "webp" },
],
}),
],
jobs: bullmqJobAdapter({
connection: { host: process.env.REDIS_HOST!, port: Number(process.env.REDIS_PORT!) },
defaultJobOptions: { attempts: 3, backoff: { type: "exponential", delay: 1000 } },
}),
fileHandling: {
maxBufferBytes: 50 * 1024 * 1024,
},
events: {
onUploadComplete: createWebhookEmitter(process.env.WEBHOOK_URL!, process.env.WEBHOOK_SECRET),
onError: async (err, ctx) => console.error("[media]", err.message, ctx),
},
settings: {
logLevel: "info",
},
});