TransformKit

andrevenancio2 pts0 comments

TransformKit — media transforms as an API

The pipeline you were about to build.<br>TransformKit is the transform pipeline — already built, already hosted. You describe the output; the upload, the job, and the delivery URL are handled. Your media stays yours.<br>Create an API keynpm i @transform-kit/sdk<br>Free plan. No credit card.

ImageVideoAudioDocument<br>import { TransformKit } from '@transform-kit/sdk';

const tk = new TransformKit({ apiKey: process.env.API_KEY! });

await tk<br>.runQueue([{ bytes, filename: 'photo.png' }], 'image')<br>.convert({ format: 'jpg', quality: 90 });

01<br>Start with a photo upload<br>At some point your app needs a photo upload. A user picks a photo from their camera roll and you show it in their profile.<br>runQueuerunPipeline<br>import { TransformKit } from '@transform-kit/sdk';

const tk = new TransformKit({ apiKey: process.env.API_KEY! });

export async function onProfilePhotoUpload(formData: FormData) {<br>const file = formData.get('photo') as File;<br>const bytes = Buffer.from(await file.arrayBuffer());

const [result] = await tk.runQueue(<br>[{ bytes, filename: file.name }],<br>'image',<br>);

return result.outputs[0]!.media.url;

02<br>Make every upload consistent<br>Photos arrive in different formats, sizes, and orientations. Normalize them once as they enter your system so every screen can rely on the same output.<br>runQueuerunPipeline<br>import { TransformKit } from '@transform-kit/sdk';

const tk = new TransformKit({ apiKey: process.env.API_KEY! });

export async function onProfilePhotoUpload(formData: FormData) {<br>const file = formData.get('photo') as File;<br>const bytes = Buffer.from(await file.arrayBuffer());

const [result] = await tk<br>.runQueue([{ bytes, filename: file.name }], 'image')<br>.maxSize(2048)<br>.convert({ format: 'webp', quality: 82 });

return result.outputs[0]!.media.url;

03<br>Handle real-world file sizes<br>Small images work in development. Production brings multi-megabyte photos from modern phones. Keep uploads fast and reliable without routing everything through your server.<br>runQueuerunPipeline<br>import { TransformKit } from '@transform-kit/sdk';

const tk = new TransformKit({ apiKey: process.env.API_KEY! });

export async function startProfilePhotoUpload(contentType: string) {<br>const ticket = await tk.createUpload({ contentType });<br>return {<br>uploadUrl: ticket.upload_url,<br>inputKey: ticket.input_key,<br>};

export async function putProfilePhotoFile(uploadUrl: string, file: File) {<br>await fetch(uploadUrl, {<br>method: 'PUT',<br>body: file,<br>headers: { 'Content-Type': file.type },<br>});

export async function onProfilePhotoUpload(inputKey: string, filename: string) {<br>const [result] = await tk<br>.runQueue([{ inputKey, filename, contentType: 'image/jpeg' }], 'image')<br>.maxSize(2048)<br>.convert({ format: 'webp', quality: 82 });

return result.outputs[0]!.media.url;<br>export async function uploadProfilePhoto(file: File) {<br>const ticket = await startProfilePhotoUpload(file.type);<br>await putProfilePhotoFile(ticket.uploadUrl, file);<br>return onProfilePhotoUpload(ticket.inputKey, file.name);

04<br>Process uploads in batches<br>Users upload one image. Teams upload hundreds. Run transformations across entire folders with progress, retries, and per-file results instead of failing the whole job.<br>runQueuerunPipeline<br>import { TransformKit } from '@transform-kit/sdk';

const tk = new TransformKit({ apiKey: process.env.API_KEY! });

export async function onProfilePhotoBatchUpload(formData: FormData) {<br>const files = formData.getAll('photos') as File[];<br>const inputs = await Promise.all(<br>files.map(async (file) => ({<br>bytes: Buffer.from(await file.arrayBuffer()),<br>filename: file.name,<br>})),<br>);

const results = await tk<br>.runQueue(inputs, 'image')<br>.maxSize(2048)<br>.convert({ format: 'webp', quality: 82 })<br>.options({<br>concurrency: 6,<br>onProgress: (e) => console.log(e),<br>});

for (const r of results) {<br>if (r.ok) console.log(r.filename, r.outputs[0]?.media.url);<br>else console.error(r.filename, r.error);

05<br>Generate every size you need<br>One original should produce every asset your product needs. Profile photos, thumbnails, banners, and high-resolution exports—all from a single upload.<br>import { TransformKit } from '@transform-kit/sdk';

const tk = new TransformKit({ apiKey: process.env.API_KEY! });

export async function onProfilePhotoUpload(formData: FormData) {<br>const file = formData.get('photo') as File;<br>const bytes = Buffer.from(await file.arrayBuffer());

const [photo] = await tk.runPipeline(<br>[{ bytes, filename: file.name }],<br>nodes: [<br>{ id: 'in', type: 'pipeline.input' },<br>{ id: 'thumb', type: 'image.resize', config: { mode: { value: 'pixels' }, width: { value: 400 }, height: { value: 400 }, fit: { value: 'inside' } } } },<br>{ id: 'thumbOut', type: 'pipeline.output', config: { suffix: { value: 'thumb' } } },<br>{ id: 'banner', type: 'image.resize', config: { mode: { value: 'pixels' }, width: { value: 1200 }, height: { value: 630 }, fit: { value: 'inside' } } } },<br>{ id: 'bannerOut', type: 'pipeline.output', config: { suffix: { value: 'banner' } } },<br>{ id: 'export', type:...

file const transformkit await from formdata

Related Articles