Amazon S3 is the default home for video assets on AWS. It scales without ceremony, keeps original files safe, and integrates with everything else in the AWS ecosystem.
What S3 doesn't do is stream those videos the way YouTube or Netflix do. Out of the box you get progressive MP4 delivery, which is fine for short internal clips but not enough for a real video experience.
In this post we'll look at how to stream videos from S3 in 2026, why standing up the full AWS Elemental stack (MediaConvert plus MediaPackage plus CloudFront) is more than most teams need, and how to get adaptive bitrate streaming, format optimization, and real-time transformations by attaching ImageKit to your existing S3 bucket.
Using AWS S3 for video hosting and streaming
For this demonstration, we have uploaded a 14.7 MB sample MP4 video test-video.mp4 to an S3 bucket.
If the object is publicly readable, you can drop the S3 URL straight into a <video> tag:
<video controls>
<source src="https://bucketname.s3.us-east-1.amazonaws.com/test-video.mp4" type="video/mp4" />
</video>When you load this URL on an HTML page, the browser issues multiple range requests to access the file in smaller chunks. The response status code for each request is 206, indicating a partial response from the server that matches the browser's requested segment.

Direct S3 delivery gives you progressive MP4 playback via HTTP range requests, which works as a baseline. It is not, however, what services like YouTube and Netflix do. Those use adaptive bitrate streaming, where a larger video file is broken into smaller chunks encoded at different bitrates. A manifest file describes the available chunks. A video player then decides which chunk to load and at what resolution based on the viewer's device and network conditions. That's the adjustment in quality you've probably seen on YouTube when your connection slows down.
Without adaptive bitrate, viewers on slow networks see buffering. Viewers on fast networks see a single quality regardless of their device. Progressive MP4 delivery can be acceptable for small clips, but it gives every viewer the same encoded file. That means slower networks may buffer, mobile users may receive more data than needed, and you do not get automatic quality switching. For anything beyond simple internal clips, you need a real streaming pipeline on top of S3.
You can pair S3 with CloudFront to cut the round trip from a centrally located bucket. That helps load time, but keeping the bucket private means configuring Origin Access Control, cache behaviors, and invalidation pipelines, and none of it solves the streaming problems above: the same 14.7 MB MP4 is now just delivered from an edge instead of us-east-1.

Why the AWS Elemental stack is more than most teams need
AWS's recommended path for VOD streaming is MediaConvert. You upload the original to S3, run a transcoding job that produces HLS or DASH manifests and segments, write them to an output bucket, and deliver through CloudFront. The result works: it is the same primitive Netflix and Disney+ are built on.
In practice, MediaConvert rarely ships alone. A production VOD setup usually adds MediaPackage for just-in-time packaging, DRM, and DVR features, plus EventBridge or SNS for job orchestration, and a third-party player for browsers that don't support HLS natively. For live or interactive streaming, Amazon IVS is a separate service with its own SDKs.
What you take on with the VOD path:
- A job-definition format with about 200 lines of JSON per pipeline
- Two pricing tiers (Basic vs Professional) with normalized-minute multipliers that scale with resolution, frame rate, and codec, pricing every job before you submit it
- Queue management, retry logic, and failure alerting through SNS or EventBridge
- An ABR ladder design (which resolutions to encode, at what bitrates)
- A second S3 bucket for outputs and lifecycle policies for cleanup
- MediaPackage configuration if you need DRM or DVR-style playback features
- CloudFront cache invalidation strategy when masters change
- A player integration (Video.js + hls.js, Shaka, or a paid player vendor)
A baseline VOD pipeline using MediaConvert, EventBridge, CloudFront, and a third-party player runs about four to six weeks of senior engineering work to get to production, plus ongoing maintenance. For a media company shipping hundreds of new hours per week, that investment pays for itself. For a marketing site, a course platform, a help center, or an e-commerce product page, it usually does not.
There is a third option that doesn't appear in AWS's guide: attach your existing S3 bucket to ImageKit and let ImageKit's URL-based video API handle the streaming pipeline. Your videos stay in S3 and the setup takes about fifteen minutes.
Connecting AWS S3 to ImageKit

ImageKit is a real-time media optimization, transformation, and management platform that natively integrates with popular cloud storage including AWS S3, whether the bucket is private or public. Once attached, ImageKit's URL endpoint becomes a transformation and delivery layer in front of your bucket.
Read more on configuring external storage with ImageKit.
ImageKit does not move or copy any content from your S3 bucket. The integration provides on-demand access to the original file when a request comes in. The first request triggers any required encoding or transformation, and the result is cached at the CDN edge for subsequent requests.
ImageKit needs read-only access to your bucket, and there are two ways to grant it. The recommended approach is an IAM role: instead of sharing long-lived access keys, you attach a bucket policy that trusts ImageKit's AWS account. After verifying bucket ownership in the dashboard, attach a policy like this, replacing my-video-bucket with your bucket name:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ImageKitRead",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::674898232578:root"
},
"Action": [
"s3:ListBucket",
"s3:GetObject",
"s3:GetObjectVersion"
],
"Resource": [
"arn:aws:s3:::my-video-bucket",
"arn:aws:s3:::my-video-bucket/*"
]
}
]
}The arn:aws:iam::674898232578:root principal is ImageKit's AWS account, so it can fetch objects from your bucket with no access keys to rotate or leak.
If your objects are encrypted with SSE-KMS using a customer-managed key, also grant kms:Decrypt on that key to the same principal in the KMS key policy. Objects encrypted with the AWS-managed aws/s3 key can't be shared cross-account and won't be served through ImageKit, so switch those objects to a customer-managed key or SSE-S3. Buckets using SSE-S3 (AES256) need no KMS permissions.
If you prefer key-based access, create a dedicated IAM user scoped to your video bucket with read-only s3:GetObject permission rather than reusing an account-wide key, and provide its access and secret keys during origin configuration. Either way, keep the access scoped to exactly the bucket that holds your videos.

Streaming optimized video with ImageKit and S3
With our bucket attached to ImageKit, we can access our video at:
https://ik.imagekit.io/ikmedia/videodemo/test-video.mp4When you load a video using this URL, ImageKit automatically identifies the requesting device and its video format support to deliver the video in WebM (VP9 or AV1 codecs) or MP4 (H264), the two most widely used web-safe video formats. ImageKit also compresses the video in near real time without significantly degrading its visual quality.
These optimizations are dashboard settings, not code. Turn them on once and ImageKit handles the rest when you deliver video through its URL.

When we deliver our 14.7 MB sample video through ImageKit, it goes from 14.7 MB to 9.1 MB when compressed and delivered as WebM in Chrome. Exact savings depend on the source content and the requesting browser, but no encoding job runs, no manifest is generated, and there is no setup beyond the bucket attachment.

Transforming videos for different use cases
ImageKit offers a URL-based real-time video transformation API, making it easy to adapt videos to different devices and placements. You can resize, crop, watermark, generate snippets, or generate thumbnails in real time. These transformations help you deliver a complete video experience on the client device without external products or custom code.
To scale our video to 200 px width, add the transformation parameter tr=w-200 to the URL:
https://ik.imagekit.io/ikmedia/videodemo/test-video.mp4?tr=w-200ImageKit still applies format and quality optimization while resizing. The video gets compressed to 184 KB and is delivered as WebM.

For vertical formats like Instagram Reels or TikTok-style content, specify both height and width. ImageKit handles the cropping in real time and returns the requested aspect ratio. For a 400 by 640 vertical video:
https://ik.imagekit.io/ikmedia/videodemo/test-video.mp4?tr=w-400,h-640The output is 2.3 MB.

For a deeper look at video cropping and resizing with ImageKit, see Crop and resize videos in React.
We can also watermark our video and control placement and formatting in real time. The example below uses ImageKit's layers syntax to overlay a logo image on the underlying video. You can also overlay text or another video on top of the base. No extensive setup. A URL change does it.
https://ik.imagekit.io/ikmedia/videodemo/test-video.mp4?tr=w-400,h-640,l-image,i-logo_HuFO6vJ2x.png,lx-10,ly-10,w-200,l-end
All of these transformations work without a specific player like Video.js. You can load the resulting URLs directly in a <video> tag and the browser will play them.
Adaptive bitrate streaming with S3 and ImageKit
Adaptive bitrate streaming encodes videos at different bitrates and resolutions and switches between them based on the viewer's network and device. All popular streaming services use it, and it's the central capability you'd otherwise reach for MediaConvert (plus MediaPackage) to get.
ImageKit makes DASH and HLS available as URL parameters. As with everything else in the platform, you don't run encoding jobs or manage manifest files. You modify the URL.
For an HLS stream at 360p, 480p, and 720p:
https://ik.imagekit.io/ikmedia/videodemo/test-video.mp4/ik-master.m3u8?tr=sr-360_480_720For DASH, swap
ik-master.m3u8forik-master.mpd. The same source URL produces both protocols on demand.
When the URL is requested for the first time, ImageKit starts transcoding the video to the requested resolutions in the background, and if the processing takes long, the first request for a manifest may return a 202 response. It stores the manifest file and segment chunks internally and serves them from the CDN on subsequent requests after all transcoding is complete.
For production workflows, trigger the ABS URL during upload/publish, listen for the webhook, and expose the player only after the
video.transformation.readyevent. This way, you avoid the 202 response and ensure a smooth experience for the first viewer.
You can load the manifest URL directly in any HLS-capable player. Safari supports HLS playback natively. For Chrome, Firefox, and Edge, use a JavaScript player such as Video.js, hls.js, or ImageKit's Video Player SDK. DASH usually requires a player such as Shaka Player or dash.js.
In the network panel of any browser, you can watch the player request a 360p segment first for fast initial load, then switch to 720p once the player determines the device and connection support it.

Webhooks for transcoding completion
Generating manifests and segments at multiple resolutions takes time on the first request. To improve the development experience and provide certainty about when an asset is ready, ImageKit offers video webhooks that fire on transcoding completion:
{
"type": "video.transformation.ready",
"id": "a03031b5-ad5f-4985-8cf5-4de67630f6d7",
"created_at": "2026-05-15T12:00:11.703Z",
"request": {
"x_request_id": "fa98fa2e-d6cd-45b4-acf5-bc1d2bbb8ba9",
"url": "https://ik.imagekit.io/ikmedia/videodemo/test-video.mp4/ik-master.m3u8?tr=sr-360_480_720",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:101.0) Gecko/20100101 Firefox/101.0"
}
}Webhooks are optional. The transcoding process described above works the same whether or not you subscribe to them.
No re-processing required when delivery requirements change
One of the operational costs of a traditional MediaConvert pipeline is that changes to delivery requirements (a new watermark, a new aspect ratio, a new resolution tier) require re-running encoding jobs across your entire back catalog. That cost compounds as your library grows: you pay for the normalized encoding minutes, the additional S3 storage for derivatives, and the engineering time to coordinate the re-processing.
With ImageKit, requirement changes are URL changes. You modify the transformation parameters and the new variant is generated on the next request and cached at the edge. Videos that aren't requested are never processed. Videos that need an updated transformation get it the first time someone asks for it.
For a team weighing MediaConvert against ImageKit and worried about the operational overhead of running encoding jobs going forward, this is the piece that disappears entirely.
What we built
AWS S3 continues to be the right place to store original video assets. What it doesn't do on its own is turn those assets into a streaming experience: that requires either MediaConvert with its associated pipeline work or a real-time API like ImageKit on top of the bucket.
Keep your videos in S3 and attach the bucket to ImageKit as an origin. The setup takes about fifteen minutes. From that point, every video in your bucket is streamable through ImageKit's URL endpoint, with HLS or DASH adaptive bitrate, format optimization, real-time transformations, watermarking, and webhook notifications, all configured as URL parameters or dashboard settings.
ImageKit's free plan includes 500 seconds of SD video processing and 20 GB of streaming bandwidth per month, which is enough to validate the approach against your real content before committing.
Sign up for a free ImageKit account and try it against an existing video in your S3 bucket.
If your videos are on a different cloud provider, the same approach works for Azure Blob Storage and Google Cloud Storage.