File Storage
You can connect files from file storage (opens in a new tab) to your ents.
The basic way to do this is the same as in vanilla Convex, adding a storage ID field:
defineEntSchema({
users: defineEnt({
name: v.string(),
photoId: v.id("_storage"),
}),
});
You can then retrieve the file URL for serving, update the ID etc. For example, to retrieve all users with URLs to their photos:
return ctx.table("users").map(async (user) => ({
...user,
photoUrl: await ctx.storage.getUrl(user.photoId),
}));
Using edges for cascading deletes
The one downside to this approach is that cascading deletes do not propagate to referenced files, leaving orphaned files behind. To handle this scenario Ents support specifying the connection to files as a 1:1 edge:
defineEntSchema({
users: defineEnt({
name: v.string(),
}).edge("photo", { to: "_storage", deletion: "hard" }),
});
The field name is derived from the edge name (here fieldId
), you can also
specify it with the field
option.
You can automatically delete a connected file via the deletion
option. Only
the "hard"
value is valid, since there is no way to mark soft deletion on a
document in file storage.
Note that if you use ctx.storage.delete
to delete a file that is referenced in
other ents, Ents will not cascade that deletion. Ideally do not use
ctx.storage.delete
, or handle any other required deletions manually.
Get file metadata via edge
If you traverse the edge you will receive the file metadata (opens in a new tab):
const photoMetadata = await user.edge("photo");