Overview
This task processes and watermarks an image using the Sharp library, and then uploads it to R2 storage.
Prerequisites
Adding the build configuration
To use this example, you’ll first need to add these build settings to your trigger.config.ts
file:
import { defineConfig } from "@trigger.dev/sdk/v3";
export default defineConfig({
project: "<project ref>",
build: {
external: ["sharp"],
},
});
Any packages that install or build a native binary should be added to external, as native binaries
cannot be bundled.
Key features
- Resizes a JPEG image to 800x800 pixels
- Adds a watermark to the image, positioned in the bottom-right corner, using a PNG image
- Uploads the processed image to R2 storage
Task code
trigger/sharp-image-processing.ts
import { S3Client } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
import { logger, task } from "@trigger.dev/sdk/v3";
import fs from "fs/promises";
import os from "os";
import path from "path";
import sharp from "sharp";
const r2Client = new S3Client({
region: "auto",
endpoint: process.env.R2_ENDPOINT,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID ?? "",
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY ?? "",
},
});
export const sharpProcessImage = task({
id: "sharp-process-image",
retry: { maxAttempts: 1 },
run: async (payload: { imageUrl: string; watermarkUrl: string }) => {
const { imageUrl, watermarkUrl } = payload;
const outputPath = path.join(os.tmpdir(), `output_${Date.now()}.jpg`);
const [imageResponse, watermarkResponse] = await Promise.all([
fetch(imageUrl),
fetch(watermarkUrl),
]);
const imageBuffer = await imageResponse.arrayBuffer();
const watermarkBuffer = await watermarkResponse.arrayBuffer();
await sharp(Buffer.from(imageBuffer))
.resize(800, 800)
.composite([
{
input: Buffer.from(watermarkBuffer),
gravity: "southeast",
},
])
.jpeg()
.toBuffer()
.then(async (outputBuffer) => {
await fs.writeFile(outputPath, outputBuffer);
const r2Key = `processed-images/${path.basename(outputPath)}`;
const uploadParams = {
Bucket: process.env.R2_BUCKET,
Key: r2Key,
Body: await fs.readFile(outputPath),
};
const upload = new Upload({
client: r2Client,
params: uploadParams,
});
await upload.done();
logger.log("Image uploaded to R2 storage.", {
path: `/${process.env.R2_BUCKET}/${r2Key}`,
});
await fs.unlink(outputPath);
return { r2Key };
});
},
});
Testing your task
To test this task in the dashboard, you can use the following payload:
{
"imageUrl": "<an-image-url.jpg>",
"watermarkUrl": "<an-image-url.png>"
}
Local development
To test this example task locally, be sure to install any packages from the build extensions you added to your trigger.config.ts
file to your local machine. In this case, you need to install .