Getting Started using Nuxt

The UploadThing Nuxt module makes it super easy to get started with uploading in Nuxt apps. It is a wrapper around @uploadthing/vue and the H3 backend adapter.

Package Setup

Install the packages

npm install uploadthing @uploadthing/nuxt

Add env variables

NUXT_UPLOADTHING_TOKEN=... # A token for interacting with the SDK
# πŸ‘† NUXT_ prefix is **important**

Initialize the Uploadthing module

Add the @uploadthing/nuxt module to your nuxt.config.ts file:

nuxt.config.ts

export default {
  modules: ["@uploadthing/nuxt"],
  uploadthing: {
    /**
     * Path to your router definition file
     * @default `~/server/uploadthing.ts`
     */
    routerPath: "",
  },
};

You can set some module options in the uploadthing property of your nuxt.config.ts file:

/**
 * See https://docs.uploadthing.com/api-reference/server#createroutehandler
 * for more information about the `RouteHandlerConfig` options.
 */
export type ModuleOptions = RouteHandlerConfig & {
  /**
   * Path to your router definition file
   * @default `~/server/uploadthing.ts`
   */
  routerPath?: string;
};

Set Up A FileRouter

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
  • (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.

src/lib/server/uploadthing.ts

import type { H3Event } from "h3";

import { createUploadthing } from "uploadthing/h3";
import type { FileRouter } from "uploadthing/h3";

const f = createUploadthing();

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

// FileRouter for your app, can contain multiple FileRoutes
export const uploadRouter = {
  // Define as many FileRoutes as you like, each with a unique routeSlug
  imageUploader: f({ image: { maxFileSize: "4MB" } })
    // 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 Error("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);
    }),
} satisfies FileRouter;

export type UploadRouter = typeof uploadRouter;

Upload some files!

Just mount one of our components in your app and start uploading files!

pages/index.vue

<script setup lang="ts">
const alert = (msg: string) => {
  window.alert(msg);
};
</script>

<template>
  <div>
    <UploadButton
      :config="{
        endpoint: 'imageUploader',
        onClientUploadComplete: (file) => {
          console.log('uploaded', file);
          alert('Upload complete');
        },
        onUploadError: (error) => {
          console.error(error, error.cause);
          alert('Upload failed');
        },
      }"
    />
    <UploadDropzone
      :config="{
        endpoint: 'imageUploader',
        onClientUploadComplete: (file) => {
          console.log('uploaded', file);
          alert('Upload complete');
        },
        onUploadError: (error) => {
          console.error(error, error.cause);
          alert('Upload failed');
        },
      }"
    />
  </div>
</template>

Custom flows with the useUploadThing composable

If the premade components don't fit your needs, you can use the useUploadThing to create your own custom components.

pages/index.vue

<script setup lang="ts">
const alert = (msg: string) => {
  window.alert(msg);
};

const { startUpload } = useUploadThing("videoAndImage", {
  onClientUploadComplete(res) {
    console.log(`onClientUploadComplete`, res);
    alert("Upload Completed");
  },
});
</script>

<template>
  <label>
    <input
      type="file"
      @change="
        async (e) => {
          console.log(`e`, e);
          const file = (e.target as HTMLInputElement).files?.[0];
          if (!file) return;

          // Do something with files

          // Then start the upload
          await startUpload([file]);
        }
      "
    />
  </label>
</template>

Was this page helpful?