Remix Setup

Feeling a little musical are we? Remix has backend and frontend built in, so everything you need to get started is on this page.

Setting up your environment

Install the packages

npm install uploadthing @uploadthing/react

Add env variables

UPLOADTHING_TOKEN=... # A token for interacting with the SDK

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.

app/routes/api.uploadthing.ts

import type { ActionFunctionArgs } from "@remix-run/node"; // or cloudflare/deno

import { createUploadthing, type FileRouter } from "uploadthing/remix";
import { UploadThingError } from "uploadthing/server";

const f = createUploadthing();

const auth = (args: ActionFunctionArgs) => ({ id: "fakeId" }); // Fake auth function

// FileRouter for your app, can contain multiple FileRoutes
const uploadRouter = {
  // 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,
    },
  })
    // Set permissions and file types for this FileRoute
    .middleware(async ({ event }) => {
      // This code runs on your server before upload
      const user = await auth(event);

      // If you throw, the user will not be able to upload
      if (!user) throw new UploadThingError("Unauthorized");

      // Whatever is returned here is accessible in onUploadComplete as `metadata`
      return { userId: user.id };
    })
    .onUploadComplete(async ({ metadata, file }) => {
      // This code RUNS ON YOUR SERVER after upload
      console.log("Upload complete for userId:", metadata.userId);

      console.log("file url", file.url);

      // !!! Whatever is returned here is sent to the clientside `onClientUploadComplete` callback
      return { uploadedBy: metadata.userId };
    }),
} satisfies FileRouter;

export type UploadRouter = typeof uploadRouter;

Create a Remix Resource route using the FileRouter

We'll create a Resource Route exporting the action and loader functions.

app/routes/api.uploadthing.ts

import { createRouteHandler } from "uploadthing/remix";

const uploadRouter = {
  // ...
};

export const { action, loader } = createRouteHandler({
  router: uploadRouter,

  // Apply an (optional) custom config:
  // config: { ... },
});

See configuration options in server API reference

Create The UploadThing Components

app/utils/uploadthing.ts

import {
  generateUploadButton,
  generateUploadDropzone,
} from "@uploadthing/react";

import type { UploadRouter } from "~/routes/api.uploadthing";

export const UploadButton = generateUploadButton<UploadRouter>();
export const UploadDropzone = generateUploadDropzone<UploadRouter>();

Add UploadThing's Styles

Wrap your Tailwind config with the withUt helper. You can learn more about our Tailwind helper in the "Theming" page

import { withUt } from "uploadthing/tw";

export default withUt({
  // Your existing Tailwind config
  content: ["./src/**/*.{ts,tsx,mdx}"],
  ...
});

Mount A Button And Upload!

The @uploadthing/react package includes an "UploadButton" component that you can simply drop into your app, and start uploading files immediately.

routes/_index.tsx

import { UploadButton } from "~/utils/uploadthing";

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <UploadButton
        endpoint="imageUploader"
        onClientUploadComplete={(res) => {
          // Do something with the response
          console.log("Files: ", res);
          alert("Upload Completed");
        }}
        onUploadError={(error: Error) => {
          // Do something with the error.
          alert(`ERROR! ${error.message}`);
        }}
      />
    </main>
  );
}

🎉 You're Done!

Want to customize the components? Check out the "Theming" page

Want to make your own components? Check out our useUploadThing hook

Was this page helpful?