tusd: the reference server for resumable HTTP uploads
Reference server implementation in Go of tus: the open protocol for resumable file uploads
At a glance
- What is it?
- tusd is the Go reference implementation of the tus 1.0.0 resumable upload protocol. It accepts uploads of arbitrary size and writes them to local disk, Google Cloud Storage, AWS S3 or any S3-compatible store, and the documentation for installing and configuring it lives on the project site rather than in the README.
- Who is it for?
- Adopt tusd if you control the storage backend and need uploads that survive a dropped connection, and you are willing to read the website documentation because the README points there instead of repeating it. Do not adopt it if you need a hosted upload service or a language other than Go in the same process; tusd is a server binary, not a library you embed casually.
- 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 1 day ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem tusd solves: uploads that survive the network
A plain HTTP POST upload is all-or-nothing. If the connection drops at 90 percent, the client starts again at zero. That is tolerable for a profile picture and unacceptable for a multi-gigabyte video, a database dump or a medical scan on a mobile connection. The tus protocol defines an HTTP conversation in which an upload is created, then extended chunk by chunk, so a client that reconnects can ask the server how many bytes it already holds and continue from there. tusd is the official reference implementation of that protocol, written in Go, and it targets protocol version 1.0.0.
The intended user is a backend or platform engineer who runs their own storage and wants resumable uploads without designing the resumable part. The README is explicit about the storage options: local disk, Google Cloud Storage, AWS S3 or any other S3-compatible system. It also notes that the code is modular, so other cloud providers could be added. That sentence is doing real work: it tells you the storage layer is an interface with several implementations behind it, not a hardcoded path. If your provider is not on the list, you are signing up to write and maintain a backend yourself, which changes the cost calculation considerably.
How the protocol maps onto the Go codebase
The repository is split into cmd/, internal/ and pkg/, with go.mod declaring the module as github.com/tus/tusd/v2. The binary is built from cmd/tusd/main.go, which is the entry point the Dockerfile compiles. Everything above that is library code, which is why the same project can be consumed as a server or imported into a larger Go service.
The dependency list shows where the storage and operational weight sits. cloud.google.com/go/storage and the AWS SDK v2 packages (aws/aws-sdk-go-v2 plus the s3 service module) provide the two named cloud backends, and the Azure SDK for Go appears as well, so blob storage support is present in the module graph even though the README names only S3 and GCS in prose. Prometheus client libraries are a direct dependency, so metrics are part of the server rather than an add-on. The HashiCorp go-plugin and go-hclog packages point at the hook system: tusd can call out to external hook processes, and the Docker image reflects that by shipping with --hooks-dir /srv/tusd-hooks as its default command. Locking is handled by github.com/tus/lockfile, which is what keeps two concurrent requests from corrupting the same upload.
The data flow for a single upload is therefore: an HTTP request arrives, the server checks or creates an upload resource, the storage backend writes the bytes, and the lockfile layer serialises access to that resource. Hooks, metrics and the storage backend are the three places where behaviour diverges from a bare file write.
Installing tusd with Docker and starting a first upload
The README does not contain installation steps. It states that the entire documentation, including guides on installing, using and configuring tusd, is on the website at tus.github.io/tusd. So the honest answer to "how do I install this" is: go to the website. What the repository does give you is a Dockerfile and an examples directory, and the image exposes port 8080.
The Dockerfile declares the port the server listens on:
EXPOSE 8080The image runs as a non-root user named tusd with UID 1000, and its working directory is /srv/tusd-data, so a volume mounted there is where local-disk uploads land. The default container command is the hooks directory flag:
CMD [ "--hooks-dir", "/srv/tusd-hooks" ]That means a container started without overriding the command expects /srv/tusd-hooks to exist and to be mounted if you intend to use hook scripts. The Dockerfile creates the directory and the entrypoint script handles environment loading, but a deployment that mounts a volume over that path with the wrong ownership will not behave as expected.
For a first real upload you need a tus client, not curl. The related searches around this project include tus-js-client and a Python client, and the protocol expects a client that knows the creation and offset semantics. Point your client at the server's base URL on port 8080 and it will create an upload resource. If you are putting tusd behind nginx or Apache, the repository provides examples/nginx.conf and examples/apache2.conf specifically because the default proxy configurations are not sufficient for tus.
Where tusd is the wrong choice
The strongest limitation is visible in the repository layout rather than in any warning: tusd is a server. If you wanted a Go library that adds resumable upload handling to an existing HTTP handler, you are working against the grain of a project whose main artifact is a binary built from cmd/tusd/main.go. The pkg/ directory exists and the module is importable, but the documentation the README points to is written for operators of the server.
The second constraint is the storage matrix. Local disk, Google Cloud Storage, S3 and S3-compatible systems are the named options. Azure SDK packages appear in go.mod, but the README's prose does not promise Azure, so a reader should not treat the dependency list as a support statement. Anything outside that set means implementing a backend yourself, and the README's claim that support "could easily be added" is a statement about the architecture, not a promise about your timeline.
The third is operational: tusd is a stateful service. Uploads in progress occupy disk or object storage, and the lockfile dependency means concurrent requests against the same upload are serialised rather than freely parallel. If your workload is thousands of small files uploaded once, the tus handshake is overhead you are paying for resilience you will never use, and a plain multipart POST behind a CDN is simpler. Resumability earns its keep on large files and unreliable networks, and costs you a stateful service on everything else.
tusd against a plain object-storage upload path
The realistic alternative is not another tus server. It is skipping tus and uploading directly to object storage using presigned URLs, where the client sends the bytes to S3 or GCS and your application server never touches them. The architectural difference is where the state lives. With presigned URLs, the storage provider owns the upload session and your server is stateless; resuming a failed multipart upload is the provider's problem and its API. With tusd, your server owns the session, which is why it needs a lockfile implementation, a hooks system and a metrics endpoint.
That difference cuts both ways. Presigned URLs keep your server out of the data path, which is a large operational win, but they tie you to one provider's multipart semantics and give you no protocol-level control over chunk size, offset reporting or the exact HTTP conversation the client has. tusd gives you that control and a protocol implemented by multiple clients, at the price of running and monitoring a stateful Go service. The related searches for this project pair it with tus-js-client and a Python client, which is the real argument for tus: one server, several client ecosystems, one protocol.
A second alternative is writing the resumable logic yourself against your existing framework. That is the option people underestimate. The tus specification is public and versioned at 1.0.0, and a minimal implementation for one storage backend is not enormous. What you would be reimplementing includes the locking behaviour and the hook surface that tusd already ships, and you would own the compatibility burden with every client that speaks tus.
Maintenance, releases and the MIT licence
The repository is not archived and the last push was on 2026-09-16, the same day as the v2.10.1 release. The preceding releases were v2.10.0 on 2026-06-16 and v2.9.2 on 2026-03-11, so the cadence over the past six months is a minor release roughly quarterly with a patch on top of the most recent one. That is a project that is still being worked on, and the release workflow badge in the README points at an automated release pipeline.
The v2 branch matters for upgrade planning. The README states plainly that this branch contains tusd v2 and that breaking changes were introduced after the previous major release, pointing readers to the 1.13.0 tag for the older line. If you are running tusd v1, the migration is a major-version migration, not a patch, and the README does not document a rollback path. The go.mod file requires Go 1.25.14, while the Dockerfile builds with golang:1.26.8-alpine, so building from source requires a recent Go toolchain and the container build is the path of least resistance.
The licence is MIT, stated in the README and in LICENSE.txt. MIT is permissive: it allows commercial use and modification with the copyright notice retained. That is a statement about the licence text, not legal advice, and if you are redistributing tusd inside a product you should read LICENSE.txt yourself. Note that the Dockerfile pulls in Alpine and a set of Go module dependencies under their own licences, which MIT on tusd itself does not cover.
Editorial conclusion
Adopt tusd if you control the storage backend and need uploads that survive a dropped connection, and you are willing to read the website documentation because the README points there instead of repeating it. Do not adopt it if you need a hosted upload service or a language other than Go in the same process; tusd is a server binary, not a library you embed casually. Before committing, verify three things: that your chosen storage backend is one of the supported ones, that your reverse proxy forwards the tus headers and allows the request methods the protocol uses, and that the hooks directory your deployment mounts actually exists, since the Docker image starts with --hooks-dir /srv/tusd-hooks.
Frequently asked questions
What does tusd mean?
The name combines tus, the protocol, with d for daemon, following the convention of naming a server process after the protocol it speaks. The README describes tusd as the official reference implementation of the tus resumable upload protocol.
What is the tus protocol?
It is a protocol based on HTTP for resumable file uploads, meaning an upload can be interrupted at any moment and resumed without re-uploading the previous data. Interruptions may be deliberate, such as a user pausing, or accidental, such as a network issue or server outage.
Which storage backends does tusd support?
The README names local disk, Google Cloud Storage and AWS S3 or any other S3-compatible storage system. It adds that the modular design means support for nearly any other cloud provider could be added.
What protocol version does tusd implement?
The README states the protocol version as 1.0.0. The current branch contains tusd v2, and the README points to the 1.13.0 tag for the previous major release.
How do I install tusd?
The README does not contain installation steps and instead directs readers to the website at tus.github.io/tusd for guides on installing, using and configuring tusd. The repository does provide a Dockerfile and an examples directory.
What licence is tusd released under?
The README states the project is licensed under the MIT license, with the text in LICENSE.txt. The bundled container image and Go module dependencies carry their own licences separately.
Official sources
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.
[](https://hysenlabs.com/projects/tus-tusd)