Library / SDK
microlinkhq/youtube-dl-exec avatar
microlinkhq/youtube-dl-exec

youtube-dl-exec: a promise-friendly Node wrapper around yt-dlp

Promise-friendly Node.js wrapper around youtube-dl / yt-dlp for downloading media.

617 stars94 forksJavaScriptMIT

At a glance

What is it?
youtube-dl-exec is a small Node library that turns yt-dlp into a promise or a stream, ships the binary for you, and gives you the subprocess when you need it. It is the kind of package you use once, for metadata, and then keep in the tree forever.
Who is it for?
youtube-dl-exec fits a Node service that needs video metadata or a media download without shelling out to yt-dlp by hand, and that wants the same call to work as a promise, a stream or a raw subprocess. It does not fit a build environment that forbids network access at install time, since the binary is fetched during installation unless you skip it, and it does not fit a runtime without Python 3.9 or newer on the path as python3.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 20 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

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

Editorial analysis

Three reasons, and one hard requirement

The library is described as a simple Node.js wrapper for yt-dlp, and its why list has three entries. It auto installs the latest yt-dlp version available. It executes any command in an efficient way. And it supports both a promise and a stream interface. The requirement is stated in a note above the install command: it requires Python 3.9 or above available in the system as python3, and otherwise the library will throw an error. That is an unusual dependency for a Node package to have, and it exists because yt-dlp is a Python program. The install is a single command.

bash
$ npm install youtube-dl-exec --save

By default the library auto installs the latest yt-dlp available, and the README explains that it is downloaded at build time, which is the postinstall hook rather than something that happens on first use. That detail matters for CI images, which is why the environment variables section exists at all.

Any yt-dlp flag is supported, and it maps to the command line

The usage section states plainly that any yt-dlp flag is supported, and the example passes an options object to the function.

js
const youtubedl = require('youtube-dl-exec')

youtubedl('https://www.youtube.com/watch?v=6xKWiCMKKJg', {
  dumpSingleJson: true,
  noCheckCertificates: true,
  noWarnings: true,
  preferFreeFormats: true,
  addHeader: ['referer:youtube.com', 'user-agent:googlebot']
}).then(output => console.log(output))

The README then shows what that call is equivalent to on the command line, with the flags converted to their long forms and the URL placed after a double dash.

bash
$ ./bin/yt-dlp \
  --dump-single-json \
  --no-check-certificates \
  --no-warnings \
  --prefer-free-formats \
  --add-header='user-agent:googlebot' \
  --add-header='referer:youtube.com' \
  -- \
  'https://www.youtube.com/watch?v=6xKWiCMKKJg'

The mapping is mechanical, camelCase in JavaScript to hyphenated flags in the command line, and the array of headers becomes repeated add-header options. The double dash before the URL is the important part, because it stops the target being interpreted as an option. The README points at yt-dlp --help for the full list.

A progress bar over a promise, and the subprocess escape hatch

Because the library returns a promise, any progress estimation library that takes a promise as input can wrap it.

js
const logger = require('progress-estimator')()
const youtubedl = require('youtube-dl-exec')

const url = 'https://www.youtube.com/watch?v=6xKWiCMKKJg'
const promise = youtubedl(url, { dumpSingleJson: true })
const result = await logger(promise, `Obtaining ${url}`)

console.log(result)

For finer control, the exec method returns the internal subprocess instead of a parsed output, and the README shows piping its standard output and error straight into files, then cancelling it on a timer.

js
const youtubedl = require('youtube-dl-exec')
const fs = require('fs')

const subprocess = youtubedl.exec(
  'https://www.youtube.com/watch?v=6xKWiCMKKJg',
  {
    dumpSingleJson: true
  }
)

console.log(`Running subprocess as ${subprocess.pid}`)

subprocess.stdout.pipe(fs.createWriteStream('stdout.txt'))
subprocess.stderr.pipe(fs.createWriteStream('stderr.txt'))

setTimeout(subprocess.cancel, 30000)

The API section defines the two methods. The main function takes a required URL string, an optional flags object containing any flag supported by yt-dlp, and an optional options object that is passed through to the spawn options. The exec variant is the same but returns the subprocess object rather than a parsed output. The create method builds an instance pointed at a binary path you supply, and the update method updates the yt-dlp executable at a given path, or the default instance if no path is given.

Timeout, kill signal and interrupting a running download

Cancellation is handled at the spawn level, and the README shows the third argument carrying the timeout and the signal used to kill the child.

js
const url = 'https://www.youtube.com/watch?v=6xKWiCMKKJg'
const result = await youtubedl.exec(url, ,{ dumpSingleJson: true }, {
  timeout: 5000,
  killSignal: 'SIGKILL'
})

console.log(result)

The same thing can be done by interacting with the subprocess directly, killing it after a delay and then awaiting the result.

js
const url = 'https://www.youtube.com/watch?v=6xKWiCMKKJg'
const subprocess = youtubedl.exec(url, { dumpSingleJson: true })

setTimeout(() => {
  subprocess.kill('SIGKILL')
}, 5000)

const result = await subprocess
console.log(result)

The two forms differ in a way that matters. The timeout option is a property of the spawn, so it applies whether or not you hold the subprocess, while the manual kill needs the handle. For a service where a user can abandon a request, the second form is the one that maps to the requirement, and the README also mentions combining it with the skip download environment variable so the process does no work at all.

Environment variables for the install step, and why they exist

The environment variables customize the postinstall script that runs after npm install, and the README says they are mostly for backward compatibility or debugging purposes, and that you do not need to do anything by default. DEBUG set to a wildcard for the package name enables debug logging during the postinstall. YOUTUBE_DL_DIR determines the folder where the binary is put, defaulting to bin. YOUTUBE_DL_FILENAME determines the binary filename, which can be yt-dlp or youtube-dl.exe depending on the platform variable. YOUTUBE_DL_HOST determines the remote URL used to fetch the binary, defaulting to the latest yt-dlp release. YOUTUBE_DL_PLATFORM determines the architecture, computed from process.platform as unix or win32 when unset. YOUTUBE_DL_SKIP_DOWNLOAD, when present, skips the postinstall fetch entirely, and the README shows it being set before an install.

bash
YOUTUBE_DL_SKIP_DOWNLOAD=true npm install

There is also YOUTUBE_DL_SKIP_PYTHON_CHECK, which skips the Python check on installation. The skip download variable is the one that matters in practice, because it is what lets the package install in an air-gapped build or in a Docker layer that should not fetch a binary at build time.

yt-dlp plugins go in a zip next to the binary

Plugin support works by placing a plugin.zip file inside a yt-dlp-plugins directory under the same binary path. The README gives the default binary path as node_modules/youtube-dl-exec/bin, so the plugin ends up at node_modules/youtube-dl-exec/bin/yt-dlp-plugins/plugin.zip. That is the whole mechanism, and it depends on the plugin packaging format yt-dlp itself defines, so the README points at yt-dlp's own plugin installation guide for the details. The other file in the repository worth knowing about is the example, examples/load-info-json.js, which shows the metadata-only path through the library. The package manifest is small, with the entry point at src/index.js and the type declarations at src/index.d.ts, and the scripts directory holds the postinstall logic that the environment variables configure. The licence is MIT, the repository is not archived, and the last push was on 2026-10-03, the same day as the v3.1.17 release.

Editorial conclusion

youtube-dl-exec fits a Node service that needs video metadata or a media download without shelling out to yt-dlp by hand, and that wants the same call to work as a promise, a stream or a raw subprocess. It does not fit a build environment that forbids network access at install time, since the binary is fetched during installation unless you skip it, and it does not fit a runtime without Python 3.9 or newer on the path as python3. Verify first that your environment has Python available, set YOUTUBE_DL_SKIP_DOWNLOAD if your install pipeline has no network, and prefer the exec variant when you need to cancel a long download rather than waiting for a timeout.

Frequently asked questions

How do I install youtube-dl-exec?

Run npm install youtube-dl-exec --save. The package requires Python 3.9 or above available as python3 in your system, and by default it downloads the latest yt-dlp binary at build time. You can skip that with YOUTUBE_DL_SKIP_DOWNLOAD=true npm install.

How do I cancel a download that is taking too long?

Use youtubedl.exec to get the subprocess handle rather than a parsed result. You can pass a timeout and killSignal in the third argument, which is passed to the spawn options, or kill the subprocess directly and then await the result.

Can I use my own yt-dlp binary?

Yes. The create method builds an instance using the binary path you provide, for example createYoutubeDl with a path, and the update method updates the yt-dlp executable at a given path, or the default instance if no path is given.

How do I add a yt-dlp plugin?

Create a plugin.zip file inside a yt-dlp-plugins directory under the same path as the binary. With the default binary path that means node_modules/youtube-dl-exec/bin/yt-dlp-plugins/plugin.zip.

Official sources

  1. License: MIT
  2. microlinkhq/youtube-dl-exec on GitHub
  3. Project website
  4. README
  5. Releases
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/microlinkhq-youtube-dl-exec.svg)](https://hysenlabs.com/projects/microlinkhq-youtube-dl-exec)

Was this useful?