Library / SDK
video-dev/hls.js avatar
video-dev/hls.js

HLS.js: a JavaScript HLS client that transmuxes into MediaSource Extensions

HLS.js is a JavaScript library that plays HLS in browsers with support for MSE.

16,958 stars2,759 forksTypeScriptNOASSERTION

At a glance

What is it?
HLS.js plays HTTP Live Streaming in browsers that lack native support, by transmuxing MPEG-2 TS and AAC/MP3 into ISO BMFF fragments fed to MSE. It suits teams that need control over quality switching, DRM and low-latency playback; it does not help where the browser already plays HLS natively.
Who is it for?
Adopt hls.js when you need a JavaScript-controlled HLS player with adaptive quality switching, DRM, low-latency HLS or timed metadata, and you are willing to own error recovery and buffer tuning. Skip it when Safari, iOS or another browser already plays your HLS natively, or when you want a ready-made UI.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What hls.js solves, and who actually needs it

A standard HTML video element plays HLS only where the browser implements it natively. hls.js fills that gap: it is a JavaScript library that implements an HTTP Live Streaming client on top of HTML5 video and MediaSource Extensions. The README states it works by transmuxing MPEG-2 Transport Stream and AAC/MP3 streams into ISO BMFF (MP4) fragments, performed asynchronously in a Web Worker when the browser has one. The audience is web video engineers who ship a player, not end users. If your pages already rely on native HLS, adding hls.js buys you little. If you need to control quality switching, decrypt segments, read timed metadata or support low-latency playlists in Chrome, Firefox and Edge, this is the library that does that work in JavaScript rather than in a plugin.

The transmuxing pipeline from playlist to video element

The flow is: fetch a multivariant playlist, pick a rendition, load media playlists, fetch segments, transmux them into fragmented MP4, and append the resulting buffers to a MediaSource attached to the video element. Because the transmux runs off the main thread when a Web Worker is available, parsing does not block rendering. The library also supports HLS with fmp4, so segments that are already fragmented MP4 skip the container conversion. Codec coverage depends on the runtime: the README lists HEVC, AV1, VP9 and Dolby Vision video, plus AC-3, EC-3, FLAC, Opus and ALAC audio, all subject to runtime support, and notes that H.265 and AC-3 elementary streams in MPEG-2 TS require the full build. That is the first real constraint to internalize: the light build is not a drop-in replacement for every stream.

Installing hls.js and playing a stream in a page

The package is published to npm as hls.js, and the README's demo directory contains a basic-usage.html example. Install it with npm, then construct a player against an existing video element and attach a source. The demo/basic-usage.html file in the repository shows the pattern of creating an Hls instance, calling loadSource with a manifest URL, and calling attachMedia with the video element.

Where the light build and the codec matrix bite

The exports map in package.json exposes a second entry point, hls.js/light, backed by ./dist/hls.light.mjs and ./dist/hls.light.js. The README ties H.265 in MPEG-2 TS and AC-3 elementary streams to the full build, so a stream carrying those codecs will not behave the same under the light bundle. The README also scopes several features to specific containers: identity-format SAMPLE-AES decryption is stated as supported only with MPEG-2 TS segments, and IMSC1 (TTML) subtitles are limited to the text profile and a subset of TTML styling. FairPlay, PlayReady and Widevine CDMs are listed with fmp4 segments. None of these are bugs; they are boundaries you have to check against your own packaging before you promise a format to a product team.

Error recovery is your code, not the library's

The README describes a retry mechanism embedded in the library and says recovery actions can be triggered to fix fatal media or network errors. That wording matters: fatal errors surface to your application, and you decide what recovery to attempt. A network error during a live playlist reload and a media error caused by a decode gap are different problems, and the library exposes them as events rather than resolving them for you. Teams that expect a player to heal itself silently will be disappointed. Teams that want to instrument failures, switch levels, or reload the source will find the analytics surface useful, since the README states that all internal events can be monitored and playback session metrics are exposed, along with Common Media Client Data (CMCD).

Quality switching modes and what they cost you

Adaptive streaming here is not a single behavior. The README lists three quality switching modes controllable through the API: instant switching, which changes quality at the current video position; smooth switching, which applies the change to the next loaded fragment; and bandwidth conservative switching, which changes for the next loaded fragment without flushing the buffer. In auto-quality mode the library performs an emergency switch down when bandwidth drops suddenly, to minimize buffering. The trade-off is visible: instant switching reacts fastest and risks a visible discontinuity, while the conservative mode protects the buffer at the cost of slower adaptation. Choosing between them is a product decision about how much rebuffering your audience tolerates, and the library deliberately leaves that choice exposed rather than defaulting it away.

Alternatives: Shaka Player, dash.js and native playback

The closest alternative is Shaka Player, which targets both DASH and HLS and is built around the same MSE foundation. The difference in approach is scope: hls.js implements one protocol and goes deep on HLS-specific features such as Low-Latency HLS partial segments, blocking playlist reload, delta updates, rendition reports, content steering and HLS interstitials scheduled with DATERANGE tags. If your delivery is HLS-only, that focus is the reason to pick it. If you must serve DASH alongside HLS from one player codebase, a multi-protocol player avoids running two stacks. The other alternative is not a library at all: native HLS in Safari and iOS. The snippet above already branches to video.canPlayType('application/vnd.apple.mpegurl'), and on those platforms the browser does the work without shipping a JavaScript transmuxer.

Licence, releases and the cost of keeping up

The repository's package.json declares "license": "Apache-2.0", while the repository metadata reports the licence as NOASSERTION. Treat that discrepancy as something to confirm with your own legal review rather than assuming either value. The library publishes a canary tag alongside stable versions, and the recent release cadence is frequent: v1.7.1 on 2026-08-19, v1.7.2 on 2026-09-02 and v1.7.3 on 2026-09-11, with the last push to the default branch on 2026-09-21. Frequent releases are not automatically a cost, but they mean API deprecations arrive on a schedule you do not control. The repository carries a MIGRATING.md file and a dist-size-budget.json with a size:check script, which tells you the project tracks bundle size as a first-class constraint. Upgrading means re-checking that budget and reading the migration notes, not just bumping the version.

Editorial conclusion

Adopt hls.js when you need a JavaScript-controlled HLS player with adaptive quality switching, DRM, low-latency HLS or timed metadata, and you are willing to own error recovery and buffer tuning. Skip it when Safari, iOS or another browser already plays your HLS natively, or when you want a ready-made UI. Before committing, verify the codec support in your target browsers, check which build (full or light) covers your containers, and confirm that the dist bundle size fits your budget.

Frequently asked questions

What does hls.js do?

It is a JavaScript library that implements an HTTP Live Streaming client on top of HTML5 video and MediaSource Extensions, transmuxing MPEG-2 TS and AAC/MP3 streams into ISO BMFF fragments for playback.

How to install hls.js?

It is published to npm as hls.js, so npm install hls.js adds it to a project. The package exports an ESM build at ./dist/hls.mjs and a CommonJS build at ./dist/hls.js, with types at ./dist/hls.d.ts.

How to use hls.js in a page?

Create an Hls instance, guard with Hls.isSupported(), call loadSource with the manifest URL, then call attachMedia with the video element. The repository's demo/basic-usage.html shows this pattern.

What is an hls.js error?

The README describes a retry mechanism embedded in the library and says recovery actions can be triggered to fix fatal media or network errors, so errors surface as events your application handles rather than being resolved silently.

How does hls.js compare with Shaka Player?

Shaka Player targets both DASH and HLS, while hls.js implements HLS alone and goes deep on HLS-specific features such as Low-Latency HLS partial segments, content steering and HLS interstitials. Choose based on whether you need a single multi-protocol stack.

Official sources

  1. Issues
  2. Project website
  3. README
  4. Releases
  5. video-dev/hls.js on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/video-dev-hls-js.svg)](https://hysenlabs.com/projects/video-dev-hls-js)