Spritz is a nano multi-platform DLNA media server for the terminal. No setup, no config.
Run spritz in a folder, such as ~/Media, and every video and audio file in it and its subfolders instantly shows up on the TVs, phones, and speakers on your local network. Unlike most DLNA servers, Spritz also checks your network and tells you when something will keep devices from finding it, like a VPN, a blocked port, or macOS denying Local Network access.
Install:
brew install dfallman/tap/spritzNavigate to the folder your media files are in and start Spritz:
cd /mnt/nas/movies
spritz
...alternatively, run it from anywhere and specify which path(s) to serve up:
spritz /mnt/nas/movies /mnt/nas/music
DLNA clients (including most modern TVs, Apple TV (via Infuse or VLC), PS5, Xbox, Kodi, tablets, phones, and many more) should now see the Spritz share appear in their network sources within a few seconds.
- Runs from a single command,
spritz— zero config, zero state - Announces itself via SSDP/UPnP, so clients find it without typing an IP
- Serves one or more folders (recursively, subdirectories are indexed automatically) from a single instance
- Presents three browse views at the root:
Videos,Music, andBy folder(the on-disk structure) - Supports video and audio formats (MP4/MKV/AVI/MOV/... and MP3/FLAC/OGG/...)
- Implements
ContentDirectory:1andConnectionManager:1for DLNA Browse and Search - Advertises sidecar subtitles (
.srt/.vtt/.ass/.ssa) next to matching media files, including language-tagged ones (Movie.en.srt,Movie.sv.forced.srt) - Advertises duration, resolution, honest DLNA profile names (from the file, not the extension), and sidecar album art (
cover.jpg/ matching stem) - Exposes an M3U playlist at
/spritzfor VLC, Infuse, and similar players - Sends
ssdp:byebyeon Ctrl+C so clients drop it immediately
Most DLNA and media servers (such as Plex, Jellyfin, Emby, MiniDLNA/ReadyMedia, Rygel, Serviio, and others) are meant to be persistent servers: that is, you install a service, point a config file at your media library, often on a NAS or similar, maintain a database, and leave it running.
Spritz is the opposite: you've downloaded a file, you point spritz opportunistically at the folder that file is in, share it for as long as you need, and Ctrl+C when done.
cd Downloads
spritz
No config files, no database, no indexing and reindexing jobs, and no background services. As we say in Australia, no dramas.
Hence, Spritz isn't so much a replacement for other media servers; it sits alongside them. Spritz is built for ad hoc sharing, as in folders you don't serve every day. That said, Spritz also works as a no-nonsense alternative to the heavier media servers above. Point it at your NAS's media folder, leave it running, and it does its thing.
Note: Spritz reads the file tree at startup and doesn't watch it for changes. Hence, if you add files to a share, restart Spritz to rebuild its index. Or, let watchexec do it for you: watchexec -r -- spritz. With watchexec, the app restarts and rebuilds its index when it detects change to the shared folder(s). Note however that any active streams are shut down as well, so depending on your use case relying on watchexec might or might not be desirable.
brew install dfallman/tap/spritzDownload the latest archive for your platform from the Releases page. Builds are provided for:
- Linux x86_64 and aarch64
- macOS x86_64 and Apple Silicon
- Windows x86_64
Each archive ships with a .sha256 checksum.
To compile Spritz from source, you'll need Rust. Use rustup for the installation:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Once installed:
git clone https://github.com/dfallman/spritz
cd spritz
cargo install --path cliUsage: spritz [OPTIONS] [FOLDER]...
Arguments:
[FOLDER]... Folders to serve (defaults to current directory)
Options:
-p, --port <PORT> Port to listen on [default: 8080]
--bind <BIND> Address to bind (a specific interface IP on multi-homed hosts) [default: 0.0.0.0]
-n, --name <NAME> Friendly name shown to DLNA clients [default: "Spritz Media Server"]
--allow-remote Also answer devices outside the local network. There is no password:
anyone who can reach this computer can browse and stream the folders
-h, --help Print help
-V, --version Print version
DLNA has no authentication, so spritz only answers devices on the local network: loopback,
private IPv4 ranges, 100.64.0.0/10 (Tailscale), link-local, IPv6 unique-local, and any address
on a subnet this computer is directly attached to. Anything else gets 403 Forbidden, and the
first refusal per address is logged. --allow-remote turns this off; a public-address warning
then names any public address the computer has.
# Serve the current directory
spritz
# Serve a specific folder
spritz /mnt/nas/movies
# Serve multiple folders
spritz /mnt/nas/movies /mnt/nas/tv /mnt/nas/music
# Use a different port
spritz --port 9000 /media/videos
# Bind a specific interface and set the name TVs display
spritz --bind 192.168.1.10 --name "Living Room" /media/videosBesides SSDP, spritz speaks a small spritz protocol that Spritz players (to be released!) use when multicast does not get through:
-
GET /.well-known/spritzreturns who this server is (name, UPnP UDN, port, LAN addresses,.localhostname) as JSON. -
The server advertises itself over Bonjour as
_spritz._tcp(through mDNSResponder on macOS, so a sleeping Mac stays reachable through the Bonjour Sleep Proxy when "Wake for network access" is on). -
It sees Spritz players that advertise
_spritz-player._tcp, so it can report a player that is on the network but never connects. -
It tells you on the terminal which Spritz clients searched for it and how far they got, and warns about network problems it can see (no LAN address, a VPN carrying the advertised address, Local Network access denied on macOS, UDP 1900 taken):
Client: Apple TV (tvOS 26.0) at 192.168.1.40 found this server Client 192.168.1.41: tvOS searched for this server but never connected. Check the firewall on this computer (port 8080). Client: Apple TV (tvOS 26.6) at 192.168.1.40 is on the network
The full protocol is in PROTOCOL.md.
Open your TV's Media Server or Network source. Spritz should show up within a few seconds. Inside, you'll see three containers — Videos, Music, and By folder. The first two are flat lists of every file by type; By folder mirrors your on-disk directory structure so you can navigate Shows → Season 1 → ep1.mkv the way you'd expect.
Media → Open Network Stream → http://<your-spritz-server-ip>:8080/spritz, or browse via View → Playlist → Local Network → Universal Plug and Play. VLC only scans at startup and when it receives a NOTIFY packet, so if it doesn't appear, restart VLC once Spritz is already running.
Add Files → Network Share and pick Spritz Media Server from the list, or enter the M3U URL manually. Works on tvOS as well — the share browses the three-container layout described above.
Point it at http://<your-spritz-server-ip>:8080/spritz.
Note: <your-spritz-server-ip> is the IP address of the machine you run spritz on, that's the "server" here — the "client" (see above) is the device from which you play your content. To find your server's IP, use ipconfig in the Windows Command Prompt. On macOS, check System Settings → Network (or use ipconfig getifaddr en0 in a terminal). On linux, run ip addr or hostname -I.
Video
| Extension | MIME type |
|---|---|
.mp4, .m4v |
video/mp4 |
.mkv |
video/x-matroska |
.avi |
video/x-msvideo |
.mov |
video/quicktime |
.webm |
video/webm |
.flv |
video/x-flv |
Audio
| Extension | MIME type |
|---|---|
.mp3 |
audio/mpeg |
.m4a |
audio/mp4 |
.aac |
audio/aac |
.flac |
audio/flac |
.ogg, .oga, .opus |
audio/ogg |
.wav |
audio/wav |
.wma |
audio/x-ms-wma |
.aiff, .aif |
audio/aiff |
Subtitles (sidecar files next to a video/audio item; not listed as their own library entries)
| Extension | MIME type |
|---|---|
.srt |
text/srt |
.vtt |
text/vtt |
.ass, .ssa |
text/x-ssa |
A sidecar is <stem>.<ext> or carries one or two dot-separated tags before the extension, such as a language and forced; when several media files in a folder could own it, the one with the longest name wins.
| Device | Status | Notes |
|---|---|---|
| Samsung (Tizen) | Works | Requires <dc:date> on each DIDL item — included |
| LG (webOS) | Works | Device icon served at /upnp/icon.png |
| Sony / Bravia | Works | Strict about Content-Type: text/xml; charset="utf-8" — handled |
| Apple TV — Infuse (tvOS, iOS, iPadOS) | Works | Requires the full DIDL treatment for tvOS playback |
| Apple TV — VLC (tvOS, iOS, iPadOS) | Works | tvOS VLC sometimes misses SSDP; add the M3U URL manually |
| Xbox | Works | Advertises Microsoft MediaReceiverRegistrar |
DLNA is fiddly by nature, especially in combination with certain devices and operating systems (looking at you, Apple TV).
If a client gets 403 Forbidden and the log says Refused <address>: not on the local network, that client reaches this computer from outside its local subnets (a routed VLAN, a public IPv6 address from another network). Use --allow-remote if that is intended.
If your client can't find Spritz, check your firewall rules first (on both the server and client side, but typically the server side): SSDP needs UDP 1900 open, and HTTP needs your serving port (8080 by default).
On a VPN, Docker, or multi-homed machine, discovery may succeed while playback URLs point at the wrong address. Infuse and VLC using the M3U URL (/spritz) pick up the Host header; SSDP LOCATION tries to reply with the interface on the same subnet as the client.
IPv6-only LANs: SSDP also joins [FF02::C]:1900. When --bind is the default unspecified address, HTTP tries a dual-stack socket so IPv6 clients can fetch LOCATION. Link-local (fe80::) addresses are not advertised.
On Apple TV, Infuse tends to work better than VLC. If you're using VLC and can't find the share, you can bypass discovery entirely by pasting the M3U URL into VLC: Media → Open Network Stream → http://192.168.X.X:8080/spritz. If that plays, the server is fine and the issue is discovery.
Restart VLC once Spritz is already running as VLC only scans at startup and on NOTIFY packets.
Spritz works under WSL2 with mirrored networking. Add this to your ~/.wslconfig:
[wsl2]
networkingMode=mirroredThen open the required ports in Windows Firewall (PowerShell, running as Administrator):
New-NetFirewallRule -DisplayName "Spritz HTTP" `
-Direction Inbound -Protocol TCP -LocalPort 8080 -Action Allow
New-NetFirewallRule -DisplayName "Spritz SSDP" `
-Direction Inbound -Protocol UDP -LocalPort 1900 -Action AllowKnown issue: SSDP multicast sometimes requires elevated privileges under WSL2. If devices don't auto-discover the server, you could try granting the binary CAP_NET_RAW or (as a last resort) sudo spritz. HTTP file serving and the M3U endpoint work either way.
Spritz implements DLNA/UPnP AV directly instead of wrapping an existing library. At a glance:
- Discovery (SSDP). Sends
ssdp:aliveon IPv4 and IPv6 on startup, responds toM-SEARCH, and sendsssdp:byebyeon exit. - Device description.
GET /upnp/description.xmlreturns aMediaServer:1description advertising ContentDirectory, ConnectionManager, and Xbox MediaReceiverRegistrar. - Browse / Search (SOAP).
POST /upnp/control/contentdirectoryhandlesBrowse,Search, and related actions, exposing three root containers: Videos (flat), Music (flat), and By folder (recursive). - File serving. Each source directory is mounted at
/m/{index}/and served over HTTP with range support. Only media, sidecar-subtitle, and album-art extensions are reachable; directory listings, other files, and symlinks are not.
See ARCHITECTURE.md for the full protocol walkthrough.
Spritz is written in Rust, with help from tools like Anthropic's Claude Code. I've been writing code for over 30 years, and working with coding agents has rekindled my sense of awe at what code can do. They let me move faster, try more ideas, and test them more thoroughly than I would on my own.
MIT — see LICENSE.
