Skip to main content

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 :

MethodPathDescription
GET/api/upload/filesGet a list of files
GET/api/upload/files/pageGet a paginated list of files
GET/api/upload/files/:idGet a specific file
POST/api/uploadUpload files
POST/api/upload?id=xUpdate fileInfo
DELETE/api/upload/files/:idDelete a file
Notes
  • GET /api/upload/files returns a flat array of all files and ignores pagination parameters. To retrieve files in pages, use GET /api/upload/files/page instead.
  • 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.

Signed URLs with private S3 buckets

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

Tip

When uploading an image, include a fileInfo object to set the file name, alt text, and caption.

<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>
Caution

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:

ParameterDescription
filesThe 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).
refIdThe ID of the entry which the file(s) will be linked to.
refThe 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.
fieldThe field of the entry which the file(s) will be precisely linked to.

For example, given the Restaurant model attributes:

/src/api/restaurant/content-types/restaurant/schema.json
{
// ...
"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>
Caution

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:

ParameterDescription
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).
filtersFilter the results. See Filters.
sortSort the results. See Sort.
fieldsSelect which fields to return. See Fields selection.
populatePopulate relations. See Population.

Use the nested format for pagination parameters (pagination[page]=2&pagination[pageSize]=10), not the flat format (page=2&pageSize=10).

Caution

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

Get the second page of 10 files
curl "http://localhost:1337/api/upload/files/page?pagination[page]=2&pagination[pageSize]=10"
Get 5 images, skipping the first 20, without a total count
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:

Page-based response
{
"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:

Offset-based response
{
"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:

Response with withCount=false
{
"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:

/src/api/restaurant/content-types/restaurant/schema.json

{
// ...
{
"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:

/src/api/restaurant/content-types/restaurant/schema.json
{
// ...
{
"attributes": {
"name": {
"type": "string",
"required": true
},
"covers": {
"type": "media",
"multiple": true,
}
}
}
// ...
}