Skip to content

Start typing. Errors match on their exact yt-dlp output.

to move, to open esc to close

yt-dlp Output Templates: Name and Sort Files Automatically

Tested on yt-dlp 2026.07.28 Updated

Quick answer

The -o template turns a folder of random filenames into a library. Fields go in %(name)s, and slashes create directories. Preview it with --print filename before committing to 400 videos:

bash
yt-dlp -o "%(uploader)s/%(title)s [%(id)s].%(ext)s" "URL"
see the paths without downloading anything
yt-dlp --simulate --print filename -o "%(uploader)s/%(title)s.%(ext)s" "PLAYLIST_URL"

Fields worth knowing

FieldExample
%(title)sHow to fix yt-dlp 403 errors
%(id)sdQw4w9WgXcQ
%(ext)smp4
%(uploader)sSome Channel
%(channel)sSome Channel
%(upload_date)s20260801
%(duration)s212
%(resolution)s1920x1080
%(playlist)sMy Playlist
%(playlist_index)s7
%(view_count)s1048576
%(artist)s, %(track)s, %(album)sMusic metadata, where the site provides it

For any specific video, this prints every field that actually exists — more useful than a generic list, because the answer varies by site:

bash
yt-dlp --dump-json "URL" | python -m json.tool | head -60

The three modifiers that matter

Padding numbers

%(playlist_index)s gives 1, 2, … 10, and a file manager sorts those as 1, 10, 11, 2. %(playlist_index)02d gives 01, 02, … 10, which sorts correctly:

bash
yt-dlp -o "%(playlist)s/%(playlist_index)02d - %(title)s.%(ext)s" "PLAYLIST_URL"

Formatting dates

A > inside the field applies a strftime format:

bash
yt-dlp -o "%(upload_date>%Y-%m-%d)s - %(title)s.%(ext)s" "URL"

Fallbacks

A comma lists alternatives, and the first present one wins. This is how you stop NA appearing in filenames:

bash
yt-dlp -o "%(artist,uploader,channel)s/%(album,playlist,title)s/%(track,title)s.%(ext)s" "URL"

Templates worth copying

ForTemplate
Simple%(title)s.%(ext)s
No collisions%(title)s [%(id)s].%(ext)s
By channel%(uploader)s/%(title)s [%(id)s].%(ext)s
Playlist, ordered%(playlist)s/%(playlist_index)02d - %(title)s.%(ext)s
Chronological archive%(uploader)s/%(upload_date>%Y)s/%(upload_date>%Y-%m-%d)s - %(title)s.%(ext)s
Music%(artist,uploader)s/%(album,playlist)s/%(track_number,playlist_index)02d - %(track,title)s.%(ext)s
Plex / Jellyfin%(uploader)s/Season %(upload_date>%Y)s/%(uploader)s - S%(upload_date>%Y)sE%(playlist_index)03d - %(title)s.%(ext)s

Including [%(id)s] is worth the ugliness on any archive. Titles are not unique, get edited, and collide; the id never does. It is also what lets you find the source of a file two years later.

Separate paths for separate things

-P sets base directories, optionally per type. Keeping temporary files on fast local disk while finished files go to a network share is the useful case:

bash
yt-dlp -P "home:/media/archive" -P "temp:/var/tmp" -o "%(uploader)s/%(title)s.%(ext)s" "URL"

It also avoids a real failure: merging over SMB is slow and occasionally produces postprocessing errors that do not happen locally.

Filenames that survive contact with a filesystem

Video titles contain colons, quotes, slashes and emoji. Windows rejects several outright, and every filesystem has a path length limit a long title inside a deep folder will find:

bash
yt-dlp --restrict-filenames --trim-filenames 120 -o "%(uploader)s/%(title)s.%(ext)s" "URL"

--restrict-filenames reduces names to ASCII with no spaces — worth having permanently if files ever touch a network share, an external drive or an Android device.

Making it permanent

In a config file, and remember: no quotes there.

yt-dlp.conf
-o %(uploader)s/%(title)s [%(id)s].%(ext)s
-P ~/Videos/yt-dlp
--restrict-filenames

Testing before committing

Never point a new template at 400 videos untested. This prints the paths and downloads nothing:

bash
yt-dlp --simulate --print filename -o "YOUR TEMPLATE" "PLAYLIST_URL" | head -20

NA anywhere in the output means a field that does not exist for those videos — add a fallback. Everything landing in one folder when you expected several means a missing slash.

Frequently asked

Why does my filename say NA?
The field does not exist for that video — %(album)s on a video that is not music, for instance. Use a comma to give alternatives: %(album,playlist,title)s takes the first one present.
How do I number playlist items so they sort correctly?
%(playlist_index)02d pads to two digits, so 01 sorts before 10. Without padding, a file manager orders them 1, 10, 11, 2 — which is the single most common complaint about downloaded playlists.
Can I include the upload date?
Yes, and it needs formatting: %(upload_date>%Y-%m-%d)s produces 2026-08-01. The raw %(upload_date)s gives 20260801, which sorts fine but reads badly.
Where do I find the full list of fields?
yt-dlp --dump-json "URL" prints every field available for that specific video. That is more useful than a generic list, because which fields exist depends on the site.