---
title: Images and files
status: current
phase: 2
order: 5
---

# Images and files

An **asset** is a file in your site: a photo, a logo, a PDF, a short video. You upload it once and use it in any entry.

## Upload

In your site, go to **Files → Upload**. You can upload several at once.

- Images: JPG, PNG, WebP, GIF and [SVG](#svg). Documents: PDF. Up to **20 MB**.
- Video: MP4 and WebM, up to **50 MB**. For long videos, it's better to use YouTube or Vimeo and store the link in a text field.
- Over the API you can also upload from a URL, and many at once with a [batch](../api/management.md#batch).

Each file has:

| Field | What it's for |
| --- | --- |
| Title | How you find it in the list. Suggested from the file name |
| Alt text | What a screen reader reads and what Google sees. **Required for images before using them in a published entry** |
| Description | Optional |

A file has no draft: as soon as it's uploaded, it can be used. What gets published is the entry that uses it.

### SVG

An SVG is code, not just an image: it can carry scripts or load things from another site. Pluma accepts SVGs that are **drawing only**, and rejects, saying why, the ones that contain:

- `<script>`, `<foreignObject>`, `<iframe>`, `<embed>` or `<object>`;
- attributes that run code (`onload`, `onclick`…) or `javascript:`;
- links or CSS that load something from outside (`href` to another site, `@import`, `url(https://…)`). Internal links (`#id`) and base64-embedded images are fine;
- XML entities (`<!ENTITY>`).

Nothing is cleaned up silently: if your SVG doesn't pass, export it again as "optimized SVG" (in Figma or Illustrator) or run it through SVGO. On top of that, Pluma serves it with a policy that doesn't let anything run even if something slips through.

## Use it in an entry

- **`asset` or `assets` field:** in the entry form you pick the image from the grid.
- **Inside a rich text:** write `![alt text](asset:ID)` in its own paragraph. The ID is on the file's page. It is stored as an `image` block that points to the asset; see [Rich text](../reference/rich-text.md).

Publishing checks that each file used exists and, if it's an image, has alt text.

## A file's URL

`fields.file.url` in the API looks like `https://pluma.so/files/acton-estero/4-k3x9q2m7ab/playground.jpg`: your site, the file's id with a short random key, and its name.

- It **doesn't change while the file stays the same**, and it's served with a cache that never expires. If you [replace the file](../api/management.md#edit-or-replace-a-file), the URL changes, so no cache shows the old one: read it again from the API.
- The domain is `pluma.so` (until October 1, 2026 it was `pluma.fly.dev`, which still serves the same files). If your framework only optimizes images from allowed domains (Astro `image.domains`, Next `images.remotePatterns`), allow both. See the [Astro recipe](../frameworks/astro.md#3-images).
- The random key makes it impossible to guess: nobody finds an unpublished photo by trying ids.
- In your site build you can use it directly, or download the files and serve them yourself from your usual paths (that's what the [Astro recipe](../frameworks/astro.md) does).

With a `delivery` key you only see the files used by something **published** in an `asset`/`assets` field or inside a rich text. A file id stored inside a `json` field doesn't count: if an image is used, put it in an `asset` field.

## Metadata

Photos carry hidden data: the camera, the date and often the **GPS position** where they were taken. File URLs are public, so Pluma removes that data from JPG, PNG and WebP images before storing them.

- The photo looks the same: if the camera stored it sideways with a rotation flag, Pluma rotates the pixels first. Width and height are the ones you see.
- The color profile stays, so colors don't change.
- An image with no metadata is stored exactly as you uploaded it. One with metadata is saved again at high quality.
- GIF, SVG, PDF and video are stored as they are.

If you need a photo's EXIF (the date it was taken, for example), save it in a field of the entry.

## Delete

A file used by any entry **can't be deleted**: Pluma tells you which entries use it. Remove it from those entries first.

## Where they are stored

Today, on the disk of Pluma's machine, with a daily backup. When Cloudflare R2 storage is ready (no egress fees), files will be served from there and behind a CDN; the API URLs won't change shape.

## Possible errors

| Message | What to do |
| --- | --- |
| "That file type isn't accepted" | Convert it to JPG, PNG, WebP, GIF, SVG, PDF, MP4 or WebM. |
| "The file is larger than 20 MB" (50 MB for video) | Compress it. For photos, 2000 px wide is enough; for video, 720p. |
| "This SVG isn't accepted: …" | The message says what it contains. Export it optimized; see [SVG](#svg). |
| "Alt text is missing" | Describe the image in one sentence. |
| "These entries use it" | Remove it from them and try again. |
