Downloading YouTube Videos in Node, the Streaming Way
You've got a Node script that needs to pull video from YouTube, and you'd rather not fight with a bloated dependency or some wrapper around a command-line tool. You want a stream you can pipe somewhere. That's the problem ytdl-core was built to solve—a YouTube downloading module written in plain JavaScript with a node-friendly streaming interface.
What It Does
ytdl-core is a Node module that attempts to download a video from a given YouTube URL. You call ytdl(url, [options]), and it hands you back a readable stream. That's the core of it: no downloading to disk first, no temporary files—just a stream you can pipe wherever you need it, like a file write stream.
Under the hood the module fetches video info, lets you choose a format, and then streams the download. It exposes events along the way—an info event when the video's info is fetched along with the chosen format, and a progress event on each new chunk with values describing how far along the download is. It also forwards miniget events from the underlying request layer, so you can listen for things like redirects from the returned stream. There's a Stream#destroy() method to abort and stop downloading, plus async helpers like getInfo() and getBasicInfo() for when you only want metadata.
Why It's Cool
-
The streaming interface is the whole point. Piping straight to
fs.createWriteStream()in a single line is the kind of ergonomics you want from a Node library. You're not managing buffers or waiting for a full download before you can do anything with the data. -
The options go deeper than you'd expect. You can request a byte
rangeto grab part of a file, or usebeginto specify where in the video to start—and for live videos, that option also accepts a unix timestamp or a Date object. There's aliveBuffersetting for how much time buffer to use on live streams (defaults to 20 seconds). -
It thinks about throttling. When the chosen format is video-only or audio-only, the download is split into multiple chunks to avoid throttling, with
dlChunkSizecontrolling the chunk size in bytes (10MB by default, and setting it to 0 disables chunking). That's a practical detail you'd otherwise have to discover the hard way. -
It offers an IPv6 rotation option.
IPv6Blocklets you rotate through an IPv6 block as an alternative to using a proxy. That's a genuinely useful escape hatch for a common pain point.
One honest caveat worth flagging: the begin option is described in the README as "not very reliable for non-live videos," with links to open issues. And range isn't supported on segmented formats like DASH MPD or m3u8. It's good that the docs say so up front.
How to Try It
First, a heads-up that matters: active development on the repository has been paused since July 2023. Support is now handled by the community, PRs aren't being merged, and the maintainers point people toward forks like @distube/ytdl-core for ongoing updates. So go in knowing the state of things.
That said, if you want to see how it works, the usage is about as short as it gets:
const fs = require('fs');
const ytdl = require('ytdl-core');
ytdl('http://www.youtube.com/watch?v=aqz-KE-bpKQ')
.pipe(fs.createWriteStream('video.mp4'));
If you're using TypeScript, the README lists the import variations depending on your compiler flags (esModuleInterop, allowSyntheticDefaultImports, or neither). From there you can add options to your call—a range for partial downloads, a begin time, or a larger highWaterMark if you want to buffer more than the 512KB default into memory. Listen for progress to wire up a progress bar, and call destroy() on the stream if you need to cancel.
You can find the full API and documentation in the repo: github.com/fent/node-ytdl-core.
Final Thoughts
ytdl-core is a focused library with a clean streaming API and a handful of options that show real thought about how people actually use these downloads. The paused development is the main thing to weigh—if you're building something you need to maintain for a while, the recommended fork is probably the safer bet. But as a reference for how to design a streaming downloader in Node, or for quick scripts where the community fork doesn't matter, it's still worth a look.
Follow @githubprojects for more developer tools and open source projects.