File Storage
Example: File Storage in Convex Chat
Convex supports uploading and serving files, such as images, via Convex storage.
Each file is stored keyed by a specific string storage ID. You can save the storage IDs within your documents
Uploading Files
Uploading files require three steps:
- Generate an upload URL using a mutation that calls
storage.generateUploadUrl()
. - POST a file to that URL and receive a storage ID.
- Save the storage ID into your data model via a mutation.
As an example, these might appear in a form submission handler.
src/App.jsx
// Step 1: Get a short-lived upload URL
const postUrl = await generateUploadUrl();
// Step 2: POST the file to the URL
const result = await fetch(postUrl, {
method: "POST",
headers: { "Content-Type": selectedImage.type },
body: selectedImage,
});
const { storageId } = await result.json();
// Step 3: Save the newly allocated storage id to the messages table
await sendImage(storageId, name);
convex/sendMessage.js
// Generate a short-lived upload URL.
export const generateUploadUrl = mutation(async ({ storage }) => {
return await storage.generateUploadUrl();
});
// Save the storage ID within a message.
export const sendImage = mutation(async ({ db }, storageId, author) => {
const message = { body: storageId, author, format: "image" };
await db.insert("messages", message);
});
Fetching Files
Download URLs can be generated from storage IDs inside of queries and mutations.
convex/listMessages.js
export default query(async ({ db, storage }) => {
const messages = await db.query("messages").collect();
for (const message of messages) {
if (message.format == "image") {
message.url = await storage.getUrl(message.body);
}
}
return messages;
});
Rendering Images
Download URLs can be used in img
tags to render images.
src/App.jsx
function Image({ message }) {
return <img src={message.url} height="300px" width="auto" />;
}
Deleting Files
Files can be deleted inside of mutations using
storage.delete()
. The delete
method returns true if successful and false if the storage id is not found.
export const deleteById = mutation(async ({ storage }, storageId) => {
return await storage.delete(storageId);
});