HomeTech NewsHLS Video Upload in Next.js 15: The Essential Developer Guide

HLS Video Upload in Next.js 15: The Essential Developer Guide

  • HLS video upload in Next.js 15 can be built in roughly 120 lines of code across just four files.
  • Direct HLS video upload bypasses your server entirely, solving the 1 MB Server Actions body cap problem.
  • Webhook signature verification with timing-safe comparison prevents a subtle but critical security vulnerability.
  • The same architecture works with Mux, Cloudflare Stream, or api.video — only endpoint names change.

Why HLS Video Upload Is Harder Than It Looks in Next.js 15

Building an HLS video upload and playback feature sounds straightforward until you actually try it inside a modern Next.js 15 app. A page needs a file picker, an upload button, a place to store video state, and a player. That looks like ordinary product work. Video changes the economics and the failure modes almost immediately.

The moment a user tries to upload a 400 MB video, you run headfirst into a wall: Next.js 15 Server Actions cap request bodies at 1 MB by default. A Server Action is a useful tool for small, application-shaped requests: form fields, settings changes, metadata, and other work where the server can quickly validate an input and return a result. A large media file is not that kind of request.

Even if you bump that limit on a Route Handler, you are left with a serverless function sitting there holding hundreds of megabytes of raw video while encoding has not even started. That is not a great use of compute time or money. It also turns an upload into a dependency on the application server’s availability, request limits, and ability to keep a long-lived transfer alive.

That middleman approach can feel natural because application developers are used to posting data to their own backend. For video, it is usually the wrong default. The backend does not need to inspect every byte of a source file simply to authorize an upload. It needs to decide who may upload, what asset the upload belongs to, and what should happen once processing is complete.

Direct upload changes what the application server is responsible for

The cleaner answer — and the one professional video platforms have been pushing for years — is direct upload. The browser sends bytes straight to the storage and encoding layer, your server never touches the file, and you are freed up to handle the lightweight coordination work: issuing upload URLs, receiving webhook callbacks, and serving playback manifests.

That division of labour matters. The client is responsible for transferring the selected file. The video provider is responsible for taking that uploaded source through its media pipeline and making an HLS playback result available. The Next.js application remains the control plane: it creates the upload session, associates the resulting asset with the right user or record, and decides when the finished video belongs in the product.

In practical terms, this architecture also produces a cleaner user experience. Uploading and processing are different states, and treating them as one is a common source of misleading interfaces. A file can finish transferring before it is ready to play. Conversely, a successful request to create an upload does not mean the browser has finished sending the file. A good implementation makes those boundaries explicit rather than presenting a single vague “uploading” label.

HLS is part of why that distinction matters. Playback is typically driven by a manifest that points a player toward media prepared for streaming, rather than asking a browser to consume the original uploaded file as-is. The application’s job at playback time is therefore much smaller than its job at upload time: provide the relevant playback manifest and let the player request the stream it needs.

Four files can be enough, but the boundaries matter more than the count

HLS video upload in Next.js 15 can be built in roughly 120 lines of code across just four files. That is plausible precisely because direct upload removes the need to build a homemade media relay. The compact version generally has four concerns to cover: a client-facing upload interface, a server-side endpoint or action that creates the upload, webhook handling, and a playback surface.

The short code count should not be mistaken for an excuse to blur security boundaries. Upload credentials belong on the server-side coordination path, not in the browser bundle. The browser should receive only what it needs to transfer a specific file. Likewise, a webhook handler should not assume that an inbound request is trustworthy because it appears to come from a video-related endpoint.

This is where webhook signature verification becomes non-negotiable. A webhook is often the moment when an application changes persistent state: marking a video ready, attaching a playback manifest, or exposing an asset to viewers. If an attacker can forge that notification, they may be able to push the application into treating an unverified event as real.

Verification with a timing-safe comparison prevents a subtle but critical security vulnerability. The important detail is that the comparison should not expose useful information through how long it takes to reject an incorrect signature. It is easy to write code that checks two values and appears correct in ordinary testing. It is harder to ensure that the check behaves appropriately under adversarial conditions. For a workflow that determines whether a video becomes usable, that difference is not academic.

Provider choice should not dictate the application design

The same architecture works with Mux, Cloudflare Stream, or api.video — only endpoint names change. That is the real payoff of separating coordination from transfer and processing. The application needs a way to request an upload, a way to receive a completion event, and a way to persist or serve the resulting playback information. Those are stable product requirements even when the provider changes.

Keeping that shape visible in the code makes vendor-specific details easier to contain. The UI should care that a user can select a file and see its state. The database-facing portion should care that an asset has an identity and a readiness state. The provider-facing portion should care about upload creation, webhook verification, and playback manifests. Mixing all three into one large handler may work for a demo, but it makes later changes unnecessarily expensive.

The broader lesson is not that Next.js 15 is unsuitable for video. It is that Next.js should be used for the parts of video delivery that fit an application framework: authorization, orchestration, state, and presentation. Letting a specialized video layer receive the large file directly avoids the 1 MB Server Actions body cap problem and avoids turning serverless infrastructure into an accidental media transport service.

For teams adding video to an existing product, that is the sensible baseline. Start with direct upload, model transfer and processing as separate stages, verify every webhook before changing state, and keep playback tied to the manifest produced by the video workflow. The implementation can remain compact without being careless, which is a better outcome than a larger upload pipeline that makes the app slower, costlier, and harder to trust.

Muhammad Zayn Emad
Muhammad Zayn Emad
Hi! I am Zayn 21-year-old boy immersed in the world of blogging, I blend creativity with digital savvy. Hailing from a diverse background, I bring fresh perspectives to every post. Whether crafting compelling narratives or diving deep into niche topics, I strive to engage and inspire readers, making every word count.
RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular