REST API: Upload files
The Media Library feature is powered in the back-end server of Strapi by the upload package. To upload files to Strapi, you can either use the Media Library directly from the admin panel, or use the REST API, with the following available endpoints :
| Method | Path | Description |
|---|---|---|
| GET | /api/upload/files | Get a list of files |
| GET | /api/upload/files/page | Get a paginated list of files |
| GET | /api/upload/files/:id | Get a specific file |
| POST | /api/upload | Upload files |
| POST | /api/upload?id=x | Update fileInfo |
| DELETE | /api/upload/files/:id | Delete a file |
GET /api/upload/filesreturns a flat array of all files and ignores pagination parameters. To retrieve files in pages, useGET /api/upload/files/pageinstead.- Folders are an admin panel-only feature and are not part of the Content API (REST or GraphQL). Files uploaded through REST are located in the automatically created "API Uploads" folder.
- The GraphQL API does not support uploading media files. To upload files, use the REST API or directly add files from the Media Library in the admin panel. Some GraphQL mutations to update or delete uploaded media files are still possible (see GraphQL API documentation for details).
Upload files
Upload one or more files to your application.
files is the only accepted parameter, and describes the file(s) to upload. The value(s) can be a Buffer or Stream.
When using AWS S3 with the ACL parameter set to "private", file URLs returned by the upload endpoints are automatically signed. Signed URLs include X-Amz-Signature query parameters and an isUrlSigned: true flag in the response, making them accessible despite the private bucket ACL. Signed URLs expire based on your signedUrlExpires configuration (default: 15 minutes).
When uploading an image, include a fileInfo object to set the file name, alt text, and caption.
- Browser
- Node.js
<form>
<!-- Can be multiple files -->
<input type="file" name="files" />
<input
type="hidden"
name="fileInfo"
value='{"name":"homepage-hero","alternativeText":"Person smiling while
holding laptop","caption":"Hero image used on the homepage"}'
/>
<input type="submit" value="Submit" />
</form>
<script type="text/javascript">
const form = document.querySelector('form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
await fetch('/api/upload', {
method: 'post',
body: new FormData(e.target)
});
});
</script>
import { FormData } from 'formdata-node';
import fetch, { blobFrom } from 'node-fetch';
const file = await blobFrom('./1.png', 'image/png');
const form = new FormData();
form.append('files', file, "1.png");
form.append(
'fileInfo',
JSON.stringify({
name: 'Homepage hero',
alternativeText: 'Person smiling while holding laptop',
caption: 'Hero image used on the homepage',
})
);
const response = await fetch('http://localhost:1337/api/upload', {
method: 'post',
body: form,
});
You have to send FormData in your request body.
Upload entry files
Upload one or more files that will be linked to a specific entry.
The following parameters are accepted:
| Parameter | Description |
|---|---|
files | The file(s) to upload. The value(s) can be a Buffer or Stream. |
path (optional) | The folder where the file(s) will be uploaded to (only supported on strapi-provider-upload-aws-s3). |
refId | The ID of the entry which the file(s) will be linked to. |
ref | The unique ID (uid) of the model which the file(s) will be linked to (see more below). |
source (optional) | The name of the plugin where the model is located. |
field | The field of the entry which the file(s) will be precisely linked to. |
For example, given the Restaurant model attributes:
{
// ...
"attributes": {
"name": {
"type": "string"
},
"cover": {
"type": "media",
"multiple": false,
}
}
// ...
}
The following is an example of a corresponding front-end code:
<form>
<!-- Can be multiple files if you setup "collection" instead of "model" -->
<input type="file" name="files" />
<input type="text" name="ref" value="api::restaurant.restaurant" />
<input type="text" name="refId" value="5c126648c7415f0c0ef1bccd" />
<input type="text" name="field" value="cover" />
<input type="submit" value="Submit" />
</form>
<script type="text/javascript">
const form = document.querySelector('form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
await fetch('/api/upload', {
method: 'post',
body: new FormData(e.target)
});
});
</script>
You have to send FormData in your request body.
Update fileInfo
Update a file in your application.
fileInfo is the only accepted parameter, and describes the fileInfo to update:
import { FormData } from 'formdata-node';
import fetch from 'node-fetch';
const fileId = 50;
const newFileData = {
alternativeText: 'My new alternative text for this image!',
};
const form = new FormData();
form.append('fileInfo', JSON.stringify(newFileData));
const response = await fetch(`http://localhost:1337/api/upload?id=${fileId}`, {
method: 'post',
body: form,
});
Get a paginated list of files
GET /api/upload/files/page
GET /api/upload/files/page returns files using the standard paginated response envelope ({ data, meta: { pagination } }). The GET /api/upload/files endpoint returns a flat array of all files and ignores pagination parameters.
Use /api/upload/files/page for any non-trivial Media Library. GET /api/upload/files remains available for backward compatibility.
Parameters
The endpoint accepts the same query parameters as other REST collection endpoints:
| Parameter | Description |
|---|---|
pagination[page] | Page number (1-based). Defaults to 1. |
pagination[pageSize] | Number of files per page. Defaults to the api.rest.defaultLimit config value (25), and is capped by api.rest.maxLimit when set. |
pagination[start] | Offset-based pagination: the number of files to skip. |
pagination[limit] | Offset-based pagination: the maximum number of files to return. |
pagination[withCount] | Whether to run the count query and include total and pageCount in the response. Accepts true or false. Defaults to the api.rest.withCount config value (true). |
filters | Filter the results. See Filters. |
sort | Sort the results. See Sort. |
fields | Select which fields to return. See Fields selection. |
populate | Populate relations. See Population. |
Use the nested format for pagination parameters (pagination[page]=2&pagination[pageSize]=10), not the flat format (page=2&pageSize=10).
Page-based pagination (pagination[page] and pagination[pageSize]) and offset-based pagination (pagination[start] and pagination[limit]) are mutually exclusive. Mixing the two returns a 400 error.
Example requests
curl "http://localhost:1337/api/upload/files/page?pagination[page]=2&pagination[pageSize]=10"
curl "http://localhost:1337/api/upload/files/page?pagination[start]=20&pagination[limit]=5&pagination[withCount]=false&filters[mime][\$startsWith]=image/"
Response
With page-based pagination, the meta.pagination object includes page, pageSize, pageCount, and total:
{
"data": [
{
"id": 1,
"documentId": "a1b2c3...",
"name": "photo.jpg",
"url": "/uploads/photo.jpg",
"mime": "image/jpeg",
"size": 12.34
// ...standard file fields
}
],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25,
"pageCount": 4,
"total": 100
}
}
}
With offset-based pagination, the meta.pagination object includes start, limit, and total:
{
"data": [ /* ... */ ],
"meta": {
"pagination": {
"start": 0,
"limit": 10,
"total": 100
}
}
}
When pagination[withCount] is false, the count query is skipped and total and pageCount are omitted:
{
"data": [ /* ... */ ],
"meta": {
"pagination": {
"page": 1,
"pageSize": 25
}
}
}
The objects in the data array use the same file fields as the other Upload endpoints (see Models definition).
Models definition
Adding a file attribute to a model (or the model of another plugin) is like adding a new association.
The following example lets you upload and attach one file to the avatar attribute:
{
// ...
{
"attributes": {
"pseudo": {
"type": "string",
"required": true
},
"email": {
"type": "email",
"required": true,
"unique": true
},
"avatar": {
"type": "media",
"multiple": false,
}
}
}
// ...
}
The following example lets you upload and attach multiple pictures to the restaurant content-type:
{
// ...
{
"attributes": {
"name": {
"type": "string",
"required": true
},
"covers": {
"type": "media",
"multiple": true,
}
}
}
// ...
}