Build your own backend adapter

If none of our existing adapters fit your use case, you can easily build your own using our factory functions.

Define your adapter arguments

The first thing you need to do is define the arguments that your adapter will receive. This is usually tied to the arguments that your framework receives. For our example, we'll receive a BunRequest and a Server object. The AdapterArgs can be any record shape you want.

type AdapterArgs = {
  req: BunRequest;
  server: Server;
};

createBuilder

The createBuilder function is used to create a file route builder that you will use to define your file routes.

import { createBuilder } from "uploadthing/server";

const f = createBuilder<AdapterArgs>();

makeAdapterHandler

The makeAdapterHandler function is used to create a request handler for your adapter.

The first two arguments are functions that will take all the arguments that your framework provides. The first function should return your adapter arguments, and the second should return a web standard Request object.

import { makeAdapterHandler } from "uploadthing/server";

makeAdapterHandler<[BunRequest, Server], AdapterArgs>(
  (req, server) => Effect.succeed({ req, server }),
  (req) => Effect.succeed(req),
  // ...
);

The third argument is an options object with your file router and configuration options. For information on what configuration can be passed, see the server API reference.

makeAdapterHandler<[BunRequest, Server], AdapterArgs>(
  (req, server) => Effect.succeed({ req, server }),
  (req) => Effect.succeed(req),
  {
    router,
    // config: { ... },
  },
);

example

Here's our full example:

import { Effect } from "effect";

import { createBuilder, makeAdapterHandler } from "uploadthing/server";
import type { FileRouter } from "uploadthing/server";

type AdapterArgs = {
  req: BunRequest;
  server: Server;
};

const f = createBuilder<AdapterArgs>();

const router = {
  imageUploader: f({ image: { maxFileSize: "16MB" } })
    .middleware((opts) => {
      opts.req;
      //   ^? BunRequest
      opts.server;
      //   ^? Server
      return { userId: "user_123" };
    })
    .onUploadError((opts) => {
      opts.req;
      //   ^? BunRequest
      opts.server;
      //   ^? Server
    })
    .onUploadComplete((opts) => {
      opts.req;
      //   ^? BunRequest
      opts.server;
      //   ^? Server
    }),
} satisfies FileRouter;

const requestHandler = makeAdapterHandler<[BunRequest, Server], AdapterArgs>(
  (req, server) => Effect.succeed({ req, server }),
  (req) => Effect.succeed(req),
  { router },
);

Bun.serve({
  routes: {
    "/api/uploadthing": requestHandler,
  },
});

Was this page helpful?