Strapi can be used to store and deliver video files either locally or through providers such as AWS S3, Cloudinary, or DigitalOcean Spaces. When these files are accessed directly, playback may be slow for users who are far from the storage location.
To solve this issue, a Content Delivery Network (CDN) is placed in front of the storage backend. The CDN caches and serves video files from edge servers closer to users, which reduces latency and makes playback more stable.
Configuring Strapi Upload Provider with CDN
By default, Strapi returns direct storage links such as an S3 URL or Cloudinary link. If you want traffic to pass through a CDN, Strapi must return CDN-based URLs instead. This is done by setting the baseUrl in the upload provider configuration.
After this change, any video URL served by Strapi points to the CDN. The CDN then fetches the file from storage on the first request and caches it at the edge for later requests, improving delivery speed.
Example config/plugins.js for AWS S3 + CloudFront:
module.exports = ({ env }) => ({
upload: {
config: {
provider: 'aws-s3',
providerOptions: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_ACCESS_SECRET'),
region: env('AWS_REGION'),
params: {
Bucket: env('AWS_BUCKET'),
},
},
baseUrl: env('CDN_URL'), // e.g., https://cdn.example.com
},
},
});Cache Control Headers
CDNs rely on HTTP headers to decide how long to cache files. For video segments, you can set a long cache duration because those files do not change. For playlists or manifests like .m3u8 or .mpd, you set shorter cache durations so updates are picked up quickly.
Using headers such as Cache-Control, ETag, and Last-Modified ensures that the CDN can handle updates correctly without unnecessary requests to the origin.
Segmenting for Adaptive Bitrate Streaming
Large MP4 files are not efficient for streaming because the player must load big chunks at once. Instead, videos are transcoded into smaller segments using formats like HLS or DASH. Each segment is just a few seconds long.
The player requests segments as needed, and the CDN caches them individually. This allows adaptive bitrate streaming, where the player switches between resolutions depending on network conditions, and it also reduces buffering for users.
ffmpeg -i input.mp4 -c:v libx264 -c:a aac
-b:v:0 2000k -s:v:0 1280x720
-b:v:1 1000k -s:v:1 854x480
-f hls -hls_time 6 -hls_playlist_type vod
output.m3u8Tokenized or Signed URLs
If videos should not be publicly accessible, you can protect them with signed URLs. A signed URL contains a token and an expiry time, and the CDN validates it before serving the content. This means that only users with valid tokens can access the video.
Signed URLs can be generated inside Strapi using custom controllers or middleware. This adds an extra security layer without requiring videos to be fully public.
Example: Strapi custom controller generating signed CloudFront URL
const AWS = require('aws-sdk');
const cloudfront = new AWS.CloudFront();
const signedUrl = cloudfront.getSignedUrl({
url: `https://cdn.example.com/videos/output.m3u8`,
expires: Math.floor((Date.now() + 3600 * 1000) / 1000), // 1 hour
});Edge Caching Strategy
Different types of video files need different caching strategies. Static video segments can be cached for a long time because they never change. Playlist files that describe which segments to play should have shorter cache times because they may be updated.
Subtitles and metadata files can be cached with validation so that they are refreshed only when changed. These strategies make sure playback is smooth but still up-to-date when content changes.
Monitoring and Validation
After setup, it is important to verify that the CDN is working as expected. Tools like HLS and DASH validators can check whether playlists and segments are properly structured for CDN delivery. CDN logs provide information about cache hit ratios and traffic distribution across regions. Monitoring playback metrics such as buffering time and delivered bitrate confirms whether the optimizations are improving the viewing experience.

