Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/swift-beds-explain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"uploadthing": minor
---

Add Convex Adapter
144 changes: 144 additions & 0 deletions docs/src/app/(docs)/backend-adapters/convex/page.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { docsMetadata } from "@/lib/utils";

export const metadata = docsMetadata({
title: "Convex",
description: "Adapter to integrate UploadThing into your Convex application",
category: "Backend Adapters",
});

# Getting started with Convex

> Added in `v7.8`

## Package Setup

### Install the package

```sh npm2yarn
npm install uploadthing
```

### Add env variables (in Convex dashboard)

<Note>
If you don't already have a uploadthing secret key, [sign
up](https://uploadthing.com/sign-in) and create one from the
[dashboard!](https://uploadthing.com/dashboard)
</Note>

```bash
UPLOADTHING_TOKEN=... # A token for interacting with the SDK
CLIENT_ORIGIN=... # The origin of the client
```

## Set Up A FileRouter

### Creating your first FileRoute

All files uploaded to uploadthing are associated with a FileRoute. The following
is a very minimalistic example, with a single FileRoute "imageUploader". Think
of a FileRoute similar to an endpoint, it has:

- Permitted types ["image", "video", etc]
- Max file size
- How many files are allowed to be uploaded
- (Optional) `input` validation to validate client-side data sent to the route
- (Optional) `middleware` to authenticate and tag requests
- `onUploadComplete` callback for when uploads are completed

To get full insight into what you can do with the FileRoutes, please refer to
the [File Router API](/file-routes).

```ts {{ title: "convex/uploadthing.ts" }}
"use node";

import crypto from "node:crypto";

import {
createInternalAction,
createUploadthing,
FileRouter,
} from "uploadthing/convex";

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

globalThis.crypto = crypto as Crypto;

const f = createUploadthing();

const router = {
// Define as many FileRoutes as you like, each with a unique routeSlug
imageUploader: f({
image: {
/**
* For full list of options and defaults, see the File Route API reference
* @see https://docs.uploadthing.com/file-routes#route-config
*/
maxFileSize: "4MB",
maxFileCount: 1,
},
}).onUploadComplete((data) => {
console.log("upload completed", data);
}),
} satisfies FileRouter;

export type OurFileRouter = typeof router;

export const handler = createInternalAction({ router });
```

### Create an API route using the FileRouter

<Note>
File path here doesn't matter, you can serve this from any route. We recommend
serving it from `/api/uploadthing`.
</Note>

```ts {{ title: "convex/http.ts" }}
import { httpRouter } from "convex/server";

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

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

const http = httpRouter();

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

export default http;
```

> See configuration options in
> [server API reference](/api-reference/server#create-route-handler)

### Use the FileRouter in your app

Client side usage differs ever so slightly from the fullstack framework setups
when using a separate backend server. You'll need to set the URL of your server
when you generate the components and helpers.

```tsx
import { generateUploadButton } from "@uploadthing/react";

export const UploadButton = generateUploadButton({
url: "https://your-server.com/api/uploadthing",
});
// ...
```

For the remaining usage, please refer to client side examples of the fullstack
framework guides:

- [Next.js](/getting-started/appdir#create-the-upload-thing-components)
- [Solid.js](/getting-started/solid#creating-the-upload-thing-components)
- [Vue](https://github.com/pingdotgg/uploadthing/tree/main/examples/backend-adapters/client-vue)
- [Svelte](/getting-started/svelte#creating-the-upload-thing-helpers)

or check out the full API reference:

- [`@uploadthing/react`](/api-reference/react)
- [`uploadthing/client`](/api-reference/client)
9 changes: 8 additions & 1 deletion docs/src/components/Libraries.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Button } from "@/components/Button";
import { Heading } from "@/components/Heading";
import {
AstroIcon,
ConvexIcon,
ExpressIcon,
FastifyIcon,
H3Icon,
Expand Down Expand Up @@ -85,6 +86,12 @@ const backends = [
"UploadThing's core builds on web standards, making it easy to integrate into any web framework following the WinterCG spec.",
Logo: WinterCGIcon,
},
{
href: "/backend-adapters/convex",
name: "Convex",
description: "The open-source reactive database for app developers",
Logo: ConvexIcon,
},
];

const frontends = [
Expand Down Expand Up @@ -166,7 +173,7 @@ export function BackendAdapters() {
Not using a framework? We also have adapters for common backend
libraries.
</Prose>
<div className="not-prose mt-4 grid grid-cols-1 gap-x-6 gap-y-10 border-t border-zinc-900/5 pt-10 sm:grid-cols-2 xl:max-w-none xl:grid-cols-2 dark:border-white/5">
<div className="not-prose mt-4 grid grid-cols-1 gap-x-6 gap-y-10 border-t border-zinc-900/5 pt-10 sm:grid-cols-2 xl:max-w-none xl:grid-cols-3 dark:border-white/5">
{backends.map((library) => (
<div key={library.name} className="flex gap-6">
<library.Logo className="size-12" />
Expand Down
24 changes: 24 additions & 0 deletions docs/src/components/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -727,3 +727,27 @@ export function WinterCGIcon(props: IconProps) {
</svg>
);
}

export function ConvexIcon(props: IconProps) {
return (
<svg
viewBox="28 28 128 132"
xmlns="http://www.w3.org/2000/svg"
fill="none"
{...props}
>
<path
fill="#F3B01C"
d="M108.092 130.021c18.166-2.018 35.293-11.698 44.723-27.854-4.466 39.961-48.162 65.218-83.83 49.711-3.286-1.425-6.115-3.796-8.056-6.844-8.016-12.586-10.65-28.601-6.865-43.135 10.817 18.668 32.81 30.111 54.028 28.122Z"
/>
<path
fill="#8D2676"
d="M53.401 90.174c-7.364 17.017-7.682 36.94 1.345 53.336-31.77-23.902-31.423-75.052-.388-98.715 2.87-2.187 6.282-3.485 9.86-3.683 14.713-.776 29.662 4.91 40.146 15.507-21.3.212-42.046 13.857-50.963 33.555Z"
/>
<path
fill="#EE342F"
d="M114.637 61.855C103.89 46.87 87.069 36.668 68.639 36.358c35.625-16.17 79.446 10.047 84.217 48.807.444 3.598-.139 7.267-1.734 10.512-6.656 13.518-18.998 24.002-33.42 27.882 10.567-19.599 9.263-43.544-3.065-61.704Z"
/>
</svg>
);
}
1 change: 1 addition & 0 deletions docs/src/site-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const navigation: Array<NavGroup> = [
{ title: "Fastify", href: "/backend-adapters/fastify" },
{ title: "H3", href: "/backend-adapters/h3" },
{ title: "WinterCG Fetch", href: "/backend-adapters/fetch" },
{ title: "Convex", href: "/backend-adapters/convex" },
{ title: "Custom adapters", href: "/backend-adapters/custom" },
],
},
Expand Down
5 changes: 5 additions & 0 deletions examples/minimal-convex/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Deployment used by `npx convex dev`
CONVEX_DEPLOYMENT=

NEXT_PUBLIC_CONVEX_URL=
NEXT_PUBLIC_CONVEX_SITE_URL=
2 changes: 2 additions & 0 deletions examples/minimal-convex/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

.env.local
25 changes: 25 additions & 0 deletions examples/minimal-convex/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# @example/appdir-minimal

## null

### Patch Changes

- Updated dependencies
[[`2e8b410`](https://github.com/pingdotgg/uploadthing/commit/2e8b410bb15c2688e9b6938c4a2cd17cf6110289)]:
- [email protected]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Changelog generation signal looks auto-derived; verify example package metadata.

These entries only note dependency bumps for [email protected]/5.5.2/5.5.1. That’s fine, but “null” headings usually come from missing "version" or misconfigured "private"/"publishConfig". Please confirm:

  • examples/minimal-convex/package.json has a name like @example/minimal-convex, private: true, and a version (e.g., 0.0.0).
  • .changeset/config.json either ignores this package or is intended to produce a changelog.

I can run a quick repo scan script to verify and propose exact edits.

Example verification script:

Also applies to: 15-18, 23-26


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check example package metadata
jq -r '.name, .private, .version' examples/minimal-convex/package.json 2>/dev/null || echo "package.json missing?"

# Check if Changesets ignores the example
if [ -f ".changeset/config.json" ]; then
  echo "Changesets ignore list:"
  jq '.ignore // []' .changeset/config.json
else
  echo ".changeset/config.json missing"
fi

Length of output: 292


Fix example package metadata
examples/minimal-convex/package.json has "name": "@example/minimal-appdir" and no "version" (null), causing null headings in CHANGELOG.md. Update it to "name": "@example/minimal-convex" and add a "version" (e.g., "0.0.0"). Note that .changeset/config.json ignores @example/*, so this example uses a manual changelog.

🧰 Tools
🪛 LanguageTool

[grammar] ~7-~7: There might be a mistake here.
Context: ...## Patch Changes - Updated dependencies [[2e8b410](https://github.com/pingdotg...

(QB_NEW_EN)


[grammar] ~8-~8: There might be a mistake here.
Context: ...b410bb15c2688e9b6938c4a2cd17cf6110289)]: - [email protected] ## null ### Patch Ch...

(QB_NEW_EN)

🤖 Prompt for AI Agents
In examples/minimal-convex/CHANGELOG.md around lines 7 to 10, the changelog
shows null headings because examples/minimal-convex/package.json currently has
an incorrect "name" ("@example/minimal-appdir") and no "version"; update
package.json to set "name": "@example/minimal-convex" and add a "version" field
(for example "0.0.0"), then regenerate or manually update the CHANGELOG entry so
it reflects the correct package name and version instead of null.

## null

### Patch Changes

- Updated dependencies
[[`8cfdade`](https://github.com/pingdotgg/uploadthing/commit/8cfdade9fee61a636fa1c88bc9380d4ac77e91d9)]:
- [email protected]

## null

### Patch Changes

- Updated dependencies
[[`353f6d0`](https://github.com/pingdotgg/uploadthing/commit/353f6d026fbee7480573d735d0406477dcb9e0bc)]:
- [email protected]
22 changes: 22 additions & 0 deletions examples/minimal-convex/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Minimal Next.js App Router + Convex example for UploadThing

<a href="https://stackblitz.com/github/pingdotgg/uploadthing/tree/main/examples/minimal-convex">
<img height="64" src="https://github.com/pingdotgg/uploadthing/assets/51714798/45907a4e-aa64-401a-afb3-b6c6df6eb71f" />
</a>

## QuickStart

1. `pnpm i`
2. `pnpm dev:setup`
3. Add the `NEXT_PUBLIC_CONVEX_SITE_URL` to the .env file
4. Grab an API key from the UploadThing dashboard:
https://uploadthing.com/dashboard
5. `pnpm dev:convex`
6. `pnpx convex env set UPLOADTHING_SECRET=<your-secret>`
7. `pnpx convex env set CLIENT_ORIGIN=http://localhost:3000`
8. `pnpm dev`
9. Upload files!

## Further reference

Check out the docs at: https://docs.uploadthing.com/backend-adapters/convex
Loading