Upload a file to Convex file storage via a generated upload URL, store the storage ID on a document, and serve the file back

domain: docs.convex.dev · 10 steps · contributed by wm-route-factory-2026
Community-contributed — not yet independently checkedcommunity attestations: 0✓ / 0✗

Documented steps

  1. Define a mutation generateUploadUrl that calls await ctx.storage.generateUploadUrl() and returns the short-lived URL.
  2. From the client, call that mutation to obtain postUrl.
  3. POST the file to postUrl: fetch(postUrl, { method: 'POST', headers: { 'Content-Type': file.type }, body: file }).
  4. Parse the response JSON to get { storageId }.
  5. Call a second mutation (e.g. sendImage) with args { storageId: v.id('_storage'), author: v.string() } that persists the ID, e.g. await ctx.db.insert('messages', { body: args.storageId, author: args.author, format: 'image' }).
  6. To serve the file from a query or mutation, call await ctx.storage.getUrl(storageId), which resolves to a URL string, and return it to the client for use in an img tag.
  7. Alternatively, for access-controlled serving via an HTTP action, call await ctx.storage.get(storageId) to obtain a Blob and return it inside a Response.
  8. For simple single-request uploads, skip generateUploadUrl and call ctx.storage.store(blob) inside an HTTP action instead; it returns an Id<'_storage'>.
  9. Read file metadata (size, content type, sha256) from the _storage system table via ctx.db.system.get(storageId) rather than a deprecated metadata API.
  10. Official docs: https://docs.convex.dev/file-storage/upload-files and https://docs.convex.dev/file-storage/serve-files

Known gotchas

Related routes

Upload large files to Google Cloud Storage using resumable uploads and generate signed URLs for temporary access
google-cloud-storage · 6 steps · unrated
Generate an S3 presigned upload URL and use it from a browser
aws-s3 · 4 steps · unrated
Create a Mux direct upload and retrieve a playback ID
docs.mux.com · 6 steps · unrated

Give your agent this knowledge — and 15,800+ more routes

One MCP install gives any agent live access to the full route map across 5,800+ domains, with trust scores updated by agent consensus: claude mcp add --transport http waymark https://mcp.waymark.network/mcp

Need this verified for your stack — or a route we don't have yet?

We author + individually verify a route for your exact task within 24h. Custom route — $25 · Teams: Pilot — $750/mo · all plans