Vue Guide

File Storage

Configure the Vue storage plugin, upload files, and read file URLs reactively.

Use this guide when you want storage helpers in a standalone Vue app.

Before you begin

Make sure:

  • the base convexVue plugin is already installed
  • you already have generated Convex types
  • your Convex backend exposes storage functions you can pass to the storage plugin

Create the backend functions

convex/storage.ts
import { v } from 'convex/values'
import { mutation, query } from './_generated/server'

export const generateUploadUrl = mutation(async (ctx) => {
  return await ctx.storage.generateUploadUrl()
})

export const getUrl = query({
  args: { storageId: v.id('_storage') },
  handler: async (ctx, { storageId }) => {
    return await ctx.storage.getUrl(storageId)
  },
})

export const remove = mutation({
  args: { storageId: v.id('_storage') },
  handler: async (ctx, { storageId }) => {
    await ctx.storage.delete(storageId)
  },
})

Register the storage plugin

src/main.ts
import { convexVue } from 'vue-convex'
import { convexVueStorage } from 'vue-convex/storage'
import { createApp } from 'vue'
import { api } from '../convex/_generated/api'
import App from './App.vue'

const app = createApp(App)

app.use(convexVue, {
  url: import.meta.env.VITE_CONVEX_URL,
})

app.use(convexVueStorage, {
  generateUploadUrl: api.storage.generateUploadUrl,
  getUrl: api.storage.getUrl,
  remove: api.storage.remove,
})

app.mount('#app')

Upload a file

src/components/FileUpload.vue
<script setup lang="ts">
import { useConvexUpload } from 'vue-convex/storage'

const { upload, isUploading, progress, error } = useConvexUpload({
  onSuccess(storageId, file) {
    console.log(`Uploaded ${file.name} as ${storageId}`)
  },
})

async function onSelect(event: Event) {
  const file = (event.target as HTMLInputElement).files?.[0]
  if (file)
    await upload(file)
}
</script>

Read the file URL

src/components/AvatarUpload.vue
<script setup lang="ts">
import { useConvexStorage, useConvexUpload } from 'vue-convex/storage'

const storage = useConvexStorage()
const storageId = ref<string | null>(null)
const url = computed(() => storageId.value ? storage.getUrl(storageId.value) : null)

const { upload } = useConvexUpload({
  onSuccess(id) {
    storageId.value = id
  },
})
</script>

useConvexStorage().getUrl(storageId) returns a reactive ref that updates when the underlying file URL changes.

Verify the result

The setup is working when:

  • the storage plugin installs without errors
  • upload(file) returns a storageId
  • getUrl(storageId) resolves to a public URL

Uploads are client-only. Calling upload() during SSR returns null and sets an error.

Next steps

Copyright © 2026