Aviary
Recipes

Gallery with thumbnails

A multi-file collection with lazy + eager image conversions, ordering, and a clean render shape.

A post gallery is a multi-file collection where each image needs a couple of variants: a thumb for the grid (lazy — only the ones actually viewed get made) and an og card (eager — ready the moment a crawler hits the page).

Configure

collections: [
  {
    name: 'gallery',
    disk: 's3',                 // optional: pin this collection to a specific disk
    conversions: [
      { name: 'thumb', width: 200 },                          // lazy
      { name: 'og', width: 1200, height: 630, eager: true },  // generated on upload
    ],
  },
]

Attach (multiple, ordered)

Each attach appends with an incrementing order, so the gallery keeps insertion order:

gallery.controller.ts
@Post()
@UseInterceptors(FilesInterceptor('files'))
async add(@Param('id') postId: string, @UploadedFiles() files: Express.Multer.File[]) {
  return Promise.all(
    files.map((file) =>
      this.media.library.attach({
        ownerType: 'Post',
        ownerId: postId,
        collection: 'gallery',
        fileName: file.originalname,
        mimeType: file.mimetype,
        contents: file.buffer,
      }),
    ),
  );
}

Render

Build exactly the shape your front-end wants. list returns records ordered by order:

gallery.service.ts
async render(postId: string) {
  const media = await this.media.library.list('Post', postId, 'gallery');
  return Promise.all(
    media.map(async (m) => ({
      id: m.id,
      full: await this.media.library.url(m.id),
      thumb: await this.media.library.url(m.id, 'thumb'), // made + cached on first call
      width: m.customProperties.width,                     // whatever you stored at attach time
    })),
  );
}

The og variant exists immediately after upload; thumb is produced on the first request for each image and cached thereafter. Deleting an image removes it and all its variants:

await this.media.library.delete(mediaId);

Reordering

Records carry an order field. To support drag-to-reorder, persist new order values through your store (a thin reorder of MediaRecords) — list will return them in the new order on the next read.

On this page