
npm install @transloadit/convexA Convex component for creating Transloadit Assemblies, signing Uppy uploads, and persisting status/results in Convex.
@uppy/transloadit.yarn add @transloadit/convex// convex/convex.config.ts
import { defineApp } from "convex/server";
import transloadit from "@transloadit/convex/convex.config";
const app = defineApp();
app.use(transloadit);
export default app;npx convex env set TRANSLOADIT_KEY <your_auth_key>
npx convex env set TRANSLOADIT_SECRET <your_auth_secret>assemblyOptions (auth secret stays server-side).@uppy/transloadit with assemblyOptions().queueWebhook for durable processing.// convex/transloadit.ts
import { makeTransloaditAPI } from "@transloadit/convex";
import { components } from "./_generated/api";
export const {
createAssembly,
createAssemblyOptions,
handleWebhook,
queueWebhook,
refreshAssembly,
getAssemblyStatus,
listAssemblies,
listResults,
storeAssemblyMetadata,
} = makeTransloaditAPI(components.transloadit);Note: pass expires in createAssembly when you need a custom expiry; otherwise the component defaults to 1 hour from now.
The component stores Transloadit metadata in two tables:
assemblies 1 ──── * resultsassemblies: one row per Transloadit Assembly (status/ok, notify URL, uploads, raw payload, etc).results: one row per output file, grouped by assemblyId + stepName (a step can yield multiple rows). Each row includes normalized fields (name/size/mime/url), optional resultId, and the raw Transloadit output object.Lifecycle:
createAssembly inserts the initial assemblies row.handleWebhook, queueWebhook, or refreshAssembly upserts the assembly + replaces results.listResults returns flattened step outputs for use in UIs.Transloadit sends webhooks as multipart/form-data with transloadit (JSON) and signature fields.
// convex/http.ts
import { httpRouter } from "convex/server";
import { handleWebhookRequest } from "@transloadit/convex";
import { api } from "./_generated/api";
import { httpAction } from "./_generated/server";
const http = httpRouter();
http.route({
path: "/transloadit/webhook",
method: "POST",
handler: httpAction((ctx, request) =>
handleWebhookRequest(request, {
mode: "queue",
runAction: (args) => ctx.runAction(api.transloadit.queueWebhook, args),
}),
),
});
export default http;Most integrations should use makeTransloaditAPI (above). If you prefer a class-based API
(similar to other Convex components), use Transloadit:
import { Transloadit } from "@transloadit/convex";
import { components } from "./_generated/api";
const transloadit = new Transloadit(components.transloadit, {
authKey: process.env.TRANSLOADIT_KEY!,
authSecret: process.env.TRANSLOADIT_SECRET!,
});import Uppy from "@uppy/core";
import Transloadit from "@uppy/transloadit";
import { api } from "../convex/_generated/api";
const uppy = new Uppy().use(Transloadit, {
waitForEncoding: true,
assemblyOptions: async () => {
const { assemblyOptions } = await runAction(
api.wedding.createWeddingAssemblyOptions,
{ fileCount, guestName, uploadCode },
);
return assemblyOptions;
},
});
await uppy.upload();Note: assemblyOptions() is called once per batch, so pass per-file metadata via Uppy file meta
(e.g. uppy.setFileMeta(fileId, {...})) and use fields for shared values.
Migration note: the @transloadit/convex/react entrypoint has been removed; use Uppy +
@uppy/transloadit directly.
For status parsing and polling helpers, see docs/advanced.md.
The example/ app is a wedding gallery where guests upload photos + short videos. It uses Uppy on
the client and Convex Auth (anonymous sign-in) to create assemblies securely. Uploads are stored via
Transloadit directly into Cloudflare R2.
Live demo: https://convex-demo.transload.it
For setup, deployment, and verification details, see CONTRIBUTING.md.