Files
Store uploads in your project and serve them from its address at /_files/, even while your app is asleep, with no extra storage to set up.
Every project can store files: images, PDFs, videos, downloads. Fortly serves them from your project's own address at /_files/<path>. Fortly answers these requests itself and never starts your app to serve a file, so an idle project still serves its images instantly. Files are kept in object storage, not on the machine your app runs on, so they outlive any one server.
The examples on this page use a project created as my-app on the account ada. Its full name, which API paths use, is my-app-ada, and it is served at https://my-app-ada.fortly.com.
How files are served
A file stored at images/logo.png is served at:
https://my-app-ada.fortly.com/_files/images/logo.pngIt is also served at the same path on any custom domain connected to the project.
- Public. Anyone who has the URL can fetch the file, with no token. Do not store anything private here.
- Served by the platform. Requests under
/_files/never reach your app, even when it is running. Do not use/_files/for routes of your own. - Never run as a page. An uploaded
.htmlfile is served as a download, not rendered. Every file is sent withX-Content-Type-Options: nosniffandContent-Security-Policy: default-src 'none'; sandbox. An upload therefore cannot run script on your project's origin, read its cookies, or call its API as the visitor. - Missing files return
404withno such file.
Content types
The content type comes from the file's extension. The file's contents and anything sent with the upload are ignored. Some types are shown in the browser, and everything else is sent as a download (Content-Disposition: attachment).
| Shown in the browser | Sent as a download |
|---|---|
Images: .png, .jpg, .jpeg, .gif, .webp, .avif, .ico | .svg (an SVG can carry script) |
Video and audio: .mp4, .webm, .mp3 | .json, .csv, .zip |
Fonts: .woff, .woff2 | .html, .js, .css and any other extension, as application/octet-stream |
.pdf, .txt, .log |
An <img src> pointing at an .svg still displays it. Only opening the file directly downloads it.
Upload a file
In the console, open the project and go to Storage. Drop files onto the page or choose Upload. Folders are part of a file's path: images/logo.png is one file, and the images folder exists because that file does. A folder you create in the console is kept only once a file is stored inside it.
With the API, send the file's bytes as the request body. The path after /files/ is where the file is stored:
curl -X POST https://api.fortly.com/projects/my-app-ada/files/images/logo.png \
-H "Authorization: Bearer $FORTLY_TOKEN" \
--data-binary @logo.pngA successful upload returns 201 with the stored path, its size in bytes, and its url. Uploading to a path that already holds a file replaces that file, and the new version is served from then on.
Use --data-binary, not -d. curl's -d strips line breaks from the data it sends, which corrupts most files.
Paths
- Up to 512 characters. A leading
/is ignored, so/images/logo.pngandimages/logo.pngare the same file. ..is refused witha file path cannot step outside the project.- Line breaks are refused.
Use letters, digits, -, _, . and / in file paths. Then the stored path and the URL that serves it are the same string, and you never have to think about URL encoding.
Size
One file can be up to 64 MB. A larger file is refused with 413 Payload Too Large, and an empty one with 400 and that file is empty. All your projects' files count toward your account's storage. See limits.
List files
curl https://api.fortly.com/projects/my-app-ada/files \
-H "Authorization: Bearer $FORTLY_TOKEN"{
"files": [
{
"path": "images/logo.png",
"bytes": 48213,
"modified": 1760256000,
"url": "https://my-app-ada.fortly.com/_files/images/logo.png"
}
]
}modified is a Unix timestamp in seconds. It is null when storage does not report one.
Rename or move a file
Send the new path as to:
curl -X POST https://api.fortly.com/projects/my-app-ada/rename-file/images/logo.png \
-H "Authorization: Bearer $FORTLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"to": "brand/logo.png"}'The file is copied to the new path first and deleted from the old one only after the copy succeeds. Links to the old URL stop working.
Delete a file
curl -X DELETE https://api.fortly.com/projects/my-app-ada/files/images/logo.png \
-H "Authorization: Bearer $FORTLY_TOKEN"The response is 204, and the file stops being served. In the console, select one or more files under Storage and delete them. There is no undo.
Deleting a project deletes all of its files.
Upload from your app
A running project has no files API of its own. To store files from your code, for example images your users upload, call the management API above from your server.
- Create an API token under Settings › API tokens in the console.
- Save it as a secret on the project under a name such as
FORTLY_API_TOKEN. - Call the files API from your server code:
// Store a file and return the public URL it is served at.
// `token` is the API token you saved as the FORTLY_API_TOKEN secret,
// read the way your framework exposes secrets on the server.
export async function storeFile(path, bytes, token) {
const res = await fetch(`https://api.fortly.com/projects/my-app-ada/files/${path}`, {
method: "POST",
headers: { Authorization: `Bearer ${token}` },
body: bytes,
});
if (!res.ok) throw new Error(`upload failed (${res.status}): ${await res.text()}`);
return `https://my-app-ada.fortly.com/_files/${path}`;
}An API token can do anything your account can do, including deleting projects. Keep it on the server and never send it to a browser. If your users upload files, check each file's size and type in your own code before you store it, because whatever you store is public at its URL.
For every route, its parameters and responses, see the files API reference.