Aviary
Recipes

Multiple disks

Register several disks and route collections (or individual uploads) to the right one.

A real app often wants more than one disk — a fast public CDN bucket for images, a private bucket for documents, local disk in dev. media holds any number of named disks and lets you route per collection or per call.

Register them

MediaModule.forRoot({
  default: 's3',
  disks: {
    s3: new S3Driver({ client: s3, bucket: 'public-assets', publicBaseUrl: 'https://cdn…' }),
    private: new S3Driver({ client: s3, bucket: 'private-docs' }),
    local: new LocalDriver({ root: './storage' }),
  },
  store,
});

default is what media.disk() returns with no name, and the disk a collection uses unless it overrides.

Route by collection

Pin a collection to a disk with the disk option:

collections: [
  { name: 'gallery', disk: 's3' },        // public images → CDN bucket
  { name: 'invoices', disk: 'private' },  // private docs → private bucket
]

Now attach to invoices lands in the private bucket automatically; gallery goes to the public one.

Route per upload

Override per call when you need to — the precedence is per-call → collection → module default:

await media.library.attach({
  ownerType: 'Post', ownerId: '1', collection: 'gallery',
  fileName, mimeType, contents,
  disk: 'local', // this one upload goes local regardless of the collection's disk
});

Raw storage across disks

The same naming works without the library:

await media.disk('private').put(`invoices/${id}.pdf`, pdf);
await media.disk().put(`thumbs/${id}.webp`, webp); // the default disk

Conversions are written to the same disk as their original, so a private collection's variants stay private too.

Upload behavior also follows the disk: an S3 disk defaults to the direct/presigned path, a local disk to proxy — each overridable via uploadMode.

On this page