Storage
Per project file storage served from your own CDN link.
On this page
Every project gets its own object storage: a private bucket fronted by a public CDN. Use it for anything created or changed at runtime, such as form submissions, user uploads, generated files and datasets. Static assets that ship with the design belong in the site's public folder instead.
Open the Storage panel
Open a project and pick the Storage icon in the editor's toolbar, in the same pill as Preview, CMS and Analytics. The panel has three sub-tabs: Storage, Analytics and Configuration.
Browse and upload files
The Storage sub-tab is a file browser. Breadcrumbs run along the top starting from Storage, and folders open on click.
The folder you are in is part of the page address, under /storage/files/. A link to a folder reopens it, a refresh keeps you where you were, and the browser's back button walks you back out.
There are three ways to get files in:
- Drag files onto the panel. A dashed overlay appears reading "Drop files to upload".
- Open the three dots menu in the toolbar and choose Upload files.
- Use the same menu's New folder first, if you want somewhere to put them.
Uploads run one file at a time and a single file is capped at 100 MB. When it finishes you get a toast: "Uploaded", with a count. If some files fail you get "Some uploads failed" with the split.
An empty folder reads No files, "Drag files here or upload them instead."
Work with what is there
The search box is placeholdered "Search all files…" and searches the whole bucket, not just the folder you are in.
Each row has a three dots menu with View file, Download file and Delete file. A folder's menu has Open and Delete folder. Tick several rows and a bar appears above the list reading "3 selected", with its own menu holding Download and Delete.
Drag a file or a selection onto a folder row, or onto a breadcrumb, to move it. Moving into the folder it already sits in, or a folder into itself, is ignored.
The Modified column reads in your own timezone, down to the minute.
Deleting asks first. A folder delete warns that everything inside goes too, and none of it can be undone.
Files load fifty at a time. The footer reads "Showing 50 of 312" with a Load more button while there is more to fetch.
Public and private
Everything you write is publicly readable at its CDN URL. There is no per file access control, no signed link mode for public reads, and no way to mark one file private.
Treat that as the rule when deciding what goes in: do not store secrets or personal data you would not want readable at a guessable URL. For private data, keep it under its own prefix and read it back from your server code with the storage API rather than linking to it.
Downloads you start from the panel use a temporary signed link, but that is a convenience for the download, not a protection on the file.
The CDN link and the storage key
The Configuration sub-tab holds both, under Connection.
CDN link is the public base URL for this project's storage. Append a file path to it to link to a file, for example https://your-cdn-link/logo.png. Copy and open buttons sit beside it. If storage has not been provisioned yet, the card reads "A CDN link has not been provisioned for this site yet."
Private Storage Key is the server only key your site uses to read and write at runtime. It is masked as msk_•••• and never shown in full in the panel. The copy button puts the real key on your clipboard and clears it again after a minute, telling you so in the toast.
Your site reads the key as CDN_PRIVATE_KEY and the base URL as CDN_URL, both injected into the environment. Both are server only. Never reference either from a client component.
Rotating the key
The rotate button next to copy asks "Rotate storage key?" and warns that the current key stops working immediately and anything using the old key fails until you republish. On success: "Key rotated", with the reminder to republish the site to apply it.
Reading and writing from your site
Sites created from the Modulify starter ship with a server only helper at src/lib/modulify/storage:
import { putObject, listObjects, getObjectText } from '@/lib/modulify/storage'
await putObject('submissions/123.json', JSON.stringify(data))
const { files } = await listObjects('submissions/')
const raw = await getObjectText('submissions/123.json')Import it only from API routes, getServerSideProps or other server code. It throws in the browser by design.
Caching is handled for you. Objects are cached hard at the edge, but every write, move and delete purges that object, so the next fetch returns the latest bytes. Reuse the same key to update a file in place rather than adding a cache busting query string.
You rarely need to write this yourself. The Configuration sub-tab has a collapsible Using your storage section with two tabs. Modulify explains that describing what you want in chat is enough, and its Add it with AI button drops a ready made prompt into the composer for you to review and send. External holds the raw endpoint reference with your own host filled in.
For calling the endpoints directly, from outside the site or from another language, see Storage HTTP API.
Usage and limits
Each site can store up to 500 GB, and that ceiling can be raised on request.
The Analytics sub-tab shows Total data, Files and Folders for the bucket, then CDN delivery over a period you pick from Last day, Last week, Last month, Last 3 months or Last year: Bandwidth, Requests and Cache hit rate, with a requests over time chart. Before the CDN has served anything the chart reads No traffic, "Requests appear once the CDN serves files."
CMS uploads land here too
Image and file fields in the CMS upload into this same storage, under a CMS/ prefix organised by collection and row. They appear in the file browser like anything else, and they are public at their CDN URL like anything else.
From an AI client over MCP
Everything on this page is also reachable from a connected AI client. list_storage_files, read_storage_file, get_storage_stats, get_storage_info and get_storage_file_url cover browsing and reading; upload_storage_file, create_storage_folder, move_storage_files, delete_storage_files, delete_storage_folder and clear_storage cover the writes.
The private storage key sits behind its own credentials:reveal scope, unticked by default, because get_storage_key and rotate_storage_key return it in plain text into the client's transcript. See MCP tools and Tokens and scopes.
Next
- Storage HTTP API documents the endpoints and their bodies.
- Clearing and exporting covers the storage export and the clear action.