Skip to content

feat: Add Convex Adapter#1235

Open
IslamIhab wants to merge 15 commits intopingdotgg:mainfrom
IslamIhab:convex-adapter
Open

feat: Add Convex Adapter#1235
IslamIhab wants to merge 15 commits intopingdotgg:mainfrom
IslamIhab:convex-adapter

Conversation

@IslamIhab
Copy link

@IslamIhab IslamIhab commented Sep 2, 2025

Summary

  • This PR adds Convex adapter.
  • This repo is an example for how to implement it.
  • It was highly inspired from PR feat: add Convex adapter #929.
  • New Convex adapter entrypoints
    • packages/uploadthing/src/convex.ts
    • packages/uploadthing/src/convex-helpers.ts

Design decisions

  • Internal action boundary: Keep UploadThing’s core handler pure over Request/Response, and adapt at the Convex boundary using internalActionGeneric. Mirrors existing framework adapters and avoids Convex-specific leakage.
  • Request envelope: Convex internal actions require serializable args; we pass { url, method, headers, body? } and reconstruct a Request inside the action.
  • CORS handling: Uses convex-helpers corsRouter to handle cors

Developer experience

Usage sketch:

// convex/http.ts
import corsRouter from "convex-helpers/server/cors";
import { httpRouter } from "convex/server";

import { createRouteHandler } from "uploadthing/convex-helpers";

import { internal } from "./_generated/api";

const http = httpRouter();

const cors = corsRouter(http, {
  allowedOrigins: ["http://localhost:3000"],
});

createRouteHandler({
  http: cors,
  internalAction: internal.uploadthing.handler,
  path: "/api/uploadthing",
});

export default http;
// convex/uploadthing.ts
"use node";

import { createInternalAction, createUploadthing, FileRouter } from "uploadthing/convex";
import { api } from "./_generated/api";
import crypto from "node:crypto";
// globalThis.crypto is not defined in convex
globalThis.crypto = crypto as Crypto;

const f = createUploadthing();

const router = {
  imageUploader: f({ image: { maxFileSize: "4MB" } })
    .middleware(async (opts) => {
      const identity = await opts.ctx.auth.getUserIdentity();

      return { userId: identity?.subject };
    })
    .onUploadComplete(async (opts) => {
      await opts.ctx.runMutation(api.media.add, { url: opts.file.ufsUrl });
      return { uploadedBy: opts.metadata.userId };
    }),
} satisfies FileRouter;

export type OurFileRouter = typeof router;

export const handler = createInternalAction({ router });

Required env on convex:

  • UPLOADTHING_TOKEN

Thanks for taking a look! I’m happy to iterate on naming, paths, or API surface to fit project.

Summary by CodeRabbit

  • New Features

    • Convex backend adapter: upload builders, internal action bridge, and HTTP route helper; optional Convex peer support.
  • Documentation

    • New Convex integration guide, docs page, navigation entry, and Convex logo/icon added.
  • Examples

    • Minimal Next.js + Convex example with upload routes, handlers, schema, and client wiring.
  • Chores

    • Build and publish config updated to include Convex artifacts and example assets.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants