Docs

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.

Updated October 12, 2026
On this page
  1. How files are served
  2. Content types
  3. Upload a file
  4. Paths
  5. Size
  6. List files
  7. Rename or move a file
  8. Delete a file
  9. Upload from your app

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.png

It 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 .html file is served as a download, not rendered. Every file is sent with X-Content-Type-Options: nosniff and Content-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 404 with no 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 browserSent 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:

Terminal
curl -X POST https://api.fortly.com/projects/my-app-ada/files/images/logo.png \
  -H "Authorization: Bearer $FORTLY_TOKEN" \
  --data-binary @logo.png

A 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.png and images/logo.png are the same file.
  • .. is refused with a 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

Terminal
curl https://api.fortly.com/projects/my-app-ada/files \
  -H "Authorization: Bearer $FORTLY_TOKEN"
JSON
{
  "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:

Terminal
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

Terminal
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.

  1. Create an API token under Settings › API tokens in the console.
  2. Save it as a secret on the project under a name such as FORTLY_API_TOKEN.
  3. Call the files API from your server code:
upload.js
// 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.

Something missing or unclear? Tell us and we will fix the page.© 2026 Fortly