Self-hosted service
kern/filepizza avatar
kern/filepizza

FilePizza: file transfer with no upload step at all

:pizza: Peer-to-peer file transfers in your browser

10,240 stars620 forksTypeScriptNOASSERTION

At a glance

What is it?
A Next.js and WebRTC service that skips the server entirely, so the uploader's browser talks straight to the downloader's browser and nothing is stored in between.
Who is it for?
FilePizza is the right tool for a specific and fairly common job: getting a large file to someone without uploading it anywhere first. That design also explains its limits, which the README states without hedging.
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 4 days 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 October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The upload step is the thing it removes

Most web file sharing works the same way: the sender uploads to a server, the server stores it, the receiver downloads. Every one of those services needs disk, has a size limit, and holds your file for some window of time.

FilePizza inverts that. Using WebRTC, the data goes from the uploader's browser directly to the downloader's browser and never passes through the server. The README attributes the design to an xkcd comic about file transfer, and credits Alex Kern and Neeraj Baid for building it at UC Berkeley.

That single decision explains almost every feature and every limitation in the project. It explains why transfer is fast, since there is no round trip to storage. It explains why it is private, since the server has nothing to hand over. And it explains why the sender has to keep their browser window open, because they are the server for the duration.

At 10181 stars and 616 forks this is by far the most popular project in this batch, and it is also the one with the fewest things to configure.

What version 2 changed, and why it matters

Version 2 is the current state and the change list explains why the project feels different from the v1 screenshots people still find in search results.

The significant item is the third: transfers are now directly from the uploader to the downloader's browser, WebRTC without WebTorrent, with faster handshakes. The original implementation used WebTorrent, which meant a torrent swarm and a tracker. Dropping it removed a layer and made the handshake faster, at the cost of the swarm resilience where a downloader could keep seeding after the uploader left.

The rest of the list is ordinary product work. A new UI with dark mode support built on modern browser technologies. Support for most mobile browsers including Mobile Safari, which was historically the hard case for WebRTC-based transfer. Uploaders can monitor progress and stop a transfer, which is a real improvement when you are accidentally sending the wrong file. Password protection and reporting. Uploading multiple files at once, delivered to downloaders as a zip. Streaming downloads through a Service Worker. And server state moved out of process into Redis.

Multi-file to zip and streaming downloads are the two that change how you use it day to day.

The honest limits are in the FAQ

The README's FAQ is where the design's cost shows up, and it does not hide anything.

The sender must leave their browser window open until the transfer completes. That is the one requirement people forget. Multiple people can download from the same URL at once, and the answer is simply to share the short or long URL. The size limit is described as as big as your browser can handle, which is deliberately vague but directionally correct: the constraint is memory, not a configured maximum.

What happens when you close the browser is the interesting answer. The URLs stop working, so no new downloads can start. But if a downloader already completed their transfer, that downloader continues to seed to any incomplete downloaders. So the network degrades gracefully rather than vanishing, which is a leftover from the WebTorrent design and still useful.

Encryption is answered directly: all WebRTC communication is automatically encrypted with public-key cryptography because of DTLS, and you can add an optional password on top for an extra layer.

Self-hosting with Redis and coturn

Running your own instance takes a pnpm install and a dev server, and the full local stack is one script.

code
$ git clone https://github.com/kern/filepizza.git
$ pnpm install
$ pnpm dev
$ pnpm build
$ pnpm start
code
$ pnpm docker:build
$ pnpm docker:up
$ pnpm docker:down

The docker compose file brings up three services: redis, coturn and filepizza itself. The coturn container is configured with DETECT_EXTERNAL_IP and DETECT_RELAY_IP and points at redis for its user database, and it publishes 3478 for STUN plus 5349 for TURN over both TCP and UDP.

Configuration is seven environment variables, and the defaults are sensible enough that you can run without setting any of them.

- `REDIS_URL` stores channel metadata, falling back to in-memory storage when unset. - `COTURN_ENABLED` turns on TURN support for peers behind NAT. - `TURN_HOST` defaults to `127.0.0.1` and `TURN_REALM` defaults to `file.pizza`. - `STUN_SERVER` defaults to `stun:stun.l.google.com:19302` and is used when coturn is off. - `PEERJS_HOST` defaults to `0.peerjs.com` and `PEERJS_PATH` to `/`, so a self-hosted PeerJS signalling server is a drop-in replacement.

TURN is the piece that decides whether transfers work behind restrictive NATs, and the dev:full script starts redis and coturn together and then sets COTURN_ENABLED and REDIS_URL for you.

Next.js, PeerJS, and a licence worth checking

The stack list is short: Next.js, Tailwind, TypeScript, React, PeerJS for WebRTC, View Transitions and Redis as an option. PeerJS handles signalling, which is the part that cannot be peer to peer since the two browsers have to find each other first. PeerJS runs as a separate server, which is why PEERJS_HOST is configurable and why the repository has a bin directory containing a peerjs.js script, with a package.json script called start:peerjs to launch it.

One detail is worth flagging, because the metadata and the source disagree. The repository's licence field reads NOASSERTION, while the README states FilePizza is released under the BSD 3-Clause licence and the package.json records the same. The README also carries an illustration credit to iblowyourdesign. For anything beyond personal use, the BSD 3-Clause statement in both the README and package.json is the one to rely on, with the NOASSERTION metadata apparently reflecting that GitHub could not classify it automatically.

The rest of the repository shows a maintained application rather than a weekend project: eslint.config.mjs, playwright.config.ts, vitest.config.ts and a tests directory, plus a package.json ci script that chains lint check, format check, type check, unit tests, a build, end-to-end tests and a Docker build. Renovate is configured for dependency updates, and there are Claude and cursorrules files at the root.

The topics field is the smallest one in this batch

FilePizza declares exactly two GitHub topics, react and webrtc, against 10181 stars. Every other project reviewed here carries between six and nineteen.

It is a small detail that says something real. The project is finished enough to have a polished v2, a Docker image, an end-to-end test suite and a changelog-shaped README, and it has not needed the discovery machinery that a growing project leans on. There are no tagged releases at all, so the version lives in package.json as 2.0.0 and in the README's v2 section rather than in the releases list.

The last push was 2026-09-16, which is inside the current maintenance window, and there are 51 open issues.

For a tool whose entire job is one browser-to-browser data channel, that is the right amount of surface area. The hosted instance at file.pizza is the fastest way to judge it, and the FAQ answers above are the fastest way to know whether it fits the transfer you have in front of you.

Editorial conclusion

FilePizza is the right tool for a specific and fairly common job: getting a large file to someone without uploading it anywhere first. That design also explains its limits, which the README states without hedging. The uploader must keep their window open, the URL stops working when the browser closes, and there is no size cap beyond what a browser can handle. For a one-off transfer of a video or an archive this is better than every upload-first service. For a link you need to send next Tuesday, it is the wrong tool, and no amount of configuration changes that. Self-host it with pnpm dev:full if you need TURN for peers behind NAT.

Frequently asked questions

Is file pizza safe to use?

The transfer is encrypted by DTLS as part of WebRTC, and the files never pass through FilePizza's servers, so there is nothing stored for anyone to hand over. You can add an optional password on the upload for an extra layer. The practical caveat is not privacy but availability, since the uploader must keep their browser window open until the transfer finishes.

What does file pizza do?

It transfers files directly between two browsers over WebRTC, with no upload to a server and no storage in between. Multiple people can download from the same URL at once, multiple files are delivered as a zip, and downloads stream through a Service Worker rather than buffering the whole file.

How big can my files be?

The README says as big as your browser can handle, which puts the real limit on memory rather than on a configured maximum. There is no server-side size cap, but a very large file needs the sender's browser to buffer it in memory while streaming it.

What happens when I close my browser?

The URLs for your files stop working, so no new downloads can be started. If a downloader already finished their copy, they keep seeding to any downloaders who have not, which is leftover behaviour from the earlier WebTorrent implementation and still useful for a group transfer.

Do I need a TURN server to self-host FilePizza?

Only for peers behind restrictive NATs. The default STUN server is Google's, and setting COTURN_ENABLED to true turns on TURN support, with TURN_HOST and TURN_REALM naming the server. The pnpm dev:full script starts redis and coturn together and sets both variables for you.

Official sources

  1. Issues
  2. kern/filepizza on GitHub
  3. Project website
  4. README
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/kern-filepizza.svg)](https://hysenlabs.com/projects/kern-filepizza)