Folders
Organize Media Library assets into a navigable hierarchy with folders.
Beta primitive
Folders are built on the hierarchy primitive in Content Lake, which is currently in public beta. The underlying API surface may change.
Folder document types
A folder hierarchy in Media Library is made up of three document types from the Content Lake hierarchy primitive: sanity.tree, sanity.directory, and sanity.symlink.
Assets (sanity.asset) sit inside folders by carrying a parent reference to a sanity.directory.
Get started with the API
These examples use @sanity/client configured against your Media Library. They also work through the standard Media Library mutate and query endpoints.
Step 1: Create the tree
Every folder hierarchy starts with one sanity.tree document. In the following code, replace MEDIA_LIBRARY_ID with your library's ID, and set the SANITY_TOKEN environment variable to your personal authentication token.
import {createClient} from '@sanity/client'
const libraryId = 'MEDIA_LIBRARY_ID'
const client = createClient({
apiVersion: '2025-02-19',
resource: {type: 'media-library', id: libraryId},
token: process.env.SANITY_TOKEN,
})
await client.createIfNotExists({
_id: `tree.${libraryId}`,
_type: 'sanity.tree',
name: 'folders',
})const libraryId = 'MEDIA_LIBRARY_ID'
const token = process.env.SANITY_TOKEN
await fetch(`https://api.sanity.io/v2025-02-19/media-libraries/${libraryId}/mutate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
mutations: [
{
createIfNotExists: {
_id: `tree.${libraryId}`,
_type: 'sanity.tree',
name: 'folders',
},
},
],
}),
})Media Library requires the tree's _id to be tree.{libraryId}.
Step 2: Create folders
Create a sanity.directory with a name and a parent reference. Top-level folders point at the tree; nested folders point at their parent directory.
// Use the same `tree.${libraryId}` ID created in Step 1
const treeId = `tree.${libraryId}`
// Top-level folder
const marketing = await client.create({
_type: 'sanity.directory',
name: 'Marketing',
parent: {_ref: treeId},
})
// Nested folder
const campaigns = await client.create({
_type: 'sanity.directory',
name: 'Campaigns',
parent: {_ref: marketing._id},
})For directory creation patterns, validation rules, and the error reference, see Creating directories in the hierarchy primitive.
Step 3: Place assets in a folder
For assets that are already uploaded, set parent on the sanity.asset document to move it into a folder. In the following code, replace ASSET_ID with the _id of the sanity.asset document.
await client
.patch('ASSET_ID')
.set({parent: {_ref: campaigns._id}})
.commit()Place assets inside a sanity.directory rather than directly under the tree. The schema permits both, but the Media Library app browses, lists, and operates on assets through directories. Leave parent unset to keep an asset outside of the folder hierarchy.
Upload directly into a folder
When uploading a new asset, set the parent query parameter on the upload endpoint to place it in a folder in a single request, without a follow-up patch.
parent must reference a sanity.directory.
sanity.tree is not a valid value. Assets in Media Library cannot live directly under the tree, only inside a folder.
For the full upload pattern, see Upload assets programmatically.
Query assets and folders
Media Library hierarchy is queried with standard GROQ. The same patterns documented in Querying the hierarchy apply.
You can query assets inside a specific folder with:
*[_type == "sanity.asset" && parent._ref == $folderId]Move folders and assets
Patch parent to a new destination. The server validates the destination before any change is applied. See the error reference.
// Move Campaigns out of Marketing to the top level
await client
.patch(campaigns._id)
.set({parent: {_ref: treeId}})
.commit()The same pattern applies to assets. Set parent to move an asset into a different folder, or unset it to take the asset out of its folder. Shortcuts that target the asset remain until you delete them.
Shortcuts
A shortcut makes a single asset visible inside an additional folder without duplicating the underlying file. Shortcuts are sanity.symlink documents that reference a destination folder using parent and an asset using target.
await client.create({
_type: 'sanity.symlink',
parent: {_ref: marketing._id},
target: {_ref: 'ASSET_ID'},
})Media Library constraint
In Media Library, target must reference a sanity.asset. Targeting a sanity.directory (a “folder shortcut”) is not supported and will not render correctly in the app.
Delete folders
Delete a folder with the standard delete mutation. In the following code, replace FOLDER_ID with the _id of the sanity.directory document:
await client.delete('FOLDER_ID')No cascade delete
Deleting a folder does not cascade. The server rejects any delete where children still reference the folder through parent, with an error in the form Document "FOLDER_ID" cannot be deleted as there are references to it from "CHILD_ID". See deleting a hierarchy primitive.
In the Media Library app, the Delete folder action handles this for you. It deletes children recursively and displays a confirmation dialog that surfaces information about contents and potential warnings. If an asset inside the folder is in use by a document in one of your studios, the app blocks the deletion until you remove those references. See Deleting folders in the interface.
Was this page helpful?
Feedback submitted, thanks for helping us improve the docs. Have you tried these alternatives?