tus-node-server

The official Node.js implementation of the tus resumable upload protocol, embeddable in any HTTP server or meta-framework.

Library
npm
v2.4.5
1,094stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
89/100Excellent
Development Activity88
Maintenance92
Community88
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
85/100Excellent
Architecture90
Code Quality88
Innovation78
Learning Curve85

@tus/server is the official Node.js server for the tus resumable upload protocol, the open standard that lets file uploads pause and resume after network interruptions instead of restarting from scratch. It exposes a Server class with no required dependencies of its own, so it can run standalone with .listen() or be wired into an existing HTTP server, Fastify, Express, or any Node-compatible runtime (Bun, Deno Deploy, Cloudflare Workers, AWS Lambda) by calling .handle() from an existing request handler.

The protocol logic — header validation, offset tracking, CORS handling, locking, and lifecycle events (POST_CREATE, POST_RECEIVE, POST_FINISH, POST_TERMINATE) — lives entirely in this package, while storage is delegated to a pluggable DataStore supplied by sibling packages (@tus/file-store, @tus/s3-store, @tus/gcs-store, @tus/azure-store). This separation means the same server code works identically whether uploads land on local disk or in S3-compatible cloud storage.

It targets teams that need reliable large-file or spotty-network uploads — video platforms, backup tools, mobile apps on unstable connections — without hand-rolling chunked-upload and resume logic, and without being locked into one specific storage backend or web framework.

What You Get

  • A Server class implementing the full tus v1.0.0 protocol, including Creation, Creation-with-upload, Expiration, and Termination extensions depending on the store used
  • Framework-agnostic .handle() method that plugs into Node’s raw http, Fastify, Express, or any server exposing a compatible request/response, plus .handleWeb() for Fetch API-based runtimes
  • Configurable locking (in-memory by default, Redis/ioredis-backed for multi-instance deployments) to prevent concurrent writes to the same upload
  • Lifecycle event hooks (POST_CREATE, POST_RECEIVE, POST_FINISH, POST_TERMINATE) for wiring in logging, virus scanning, or post-processing pipelines
  • Built-in CORS handling, configurable allowed origins, and request validation hooks (onIncomingRequest, onResponseError) for auth and custom error mapping
  • TypeScript types for every option and extension point, shared with the sibling store packages via @tus/utils

Common Use Cases

  • Video and media upload pipelines - accept large video/image files over unreliable client connections without restarting failed uploads from zero
  • Mobile app backends - resume uploads interrupted by app backgrounding or spotty cellular connections using the same tus client protocol
  • Backup and sync tools - move large files to S3/GCS/Azure reliably, resuming after network drops instead of re-transferring whole files
  • Meta-framework upload routes - mount a spec-compliant upload endpoint inside Next.js, Nuxt, SvelteKit, or React Router API routes
  • Multi-instance deployments - use the Redis-backed locker to coordinate uploads safely across multiple server processes or containers

Under The Hood

Architecture The Server class (packages/server/src/server.ts) injects a DataStore through its constructor and eagerly instantiates one handler per HTTP verb (GetHandler, HeadHandler, OptionsHandler, PatchHandler, PostHandler, DeleteHandler), each extending a shared BaseHandler that centralizes locking, streaming writes, and URL generation. Requests flow through a single handler() method that validates the Tus-Resumable header, applies CORS, dispatches by method, and funnels errors through one onError path; cancellation is modeled with a dual-AbortController CancellationContext that distinguishes an immediate abort from a delayed one, giving in-flight writes time to release locks before a connection is torn down. This is a clearly layered design (Server dispatch -> per-verb Handlers -> BaseHandler shared logic -> DataStore abstraction implemented in sibling store packages), so a change to the core DataStore/Upload contract in @tus/utils would ripple through every handler and every store package.

Tech Stack Strict TypeScript targeting Node >=20.19, built with tsc --build project references across an npm-workspaces monorepo versioned via Changesets. The srvx library bridges Node’s raw http.IncomingMessage/ServerResponse and the Fetch API Request/Response, letting the same handler code run on Node and edge/Workers-style runtimes. Locking is pluggable, with optional ioredis/@redis/client peer dependencies for coordinating uploads across multiple server instances; debug provides namespaced logging and lodash.throttle throttles the POST_RECEIVE progress event.

Code Quality Tests use Mocha, Sinon, Supertest, and node-mocks-http, with one dedicated test file per handler class. Biome enforces linting and formatting repo-wide, and three GitHub Actions workflows (build, lint, test) gate every change. Error handling is centralized through a typed ERRORS constant with explicit status codes rather than ad hoc throws, and cancellation is always explicit via AbortController signals rather than implicit timeouts.

API Design The public surface is small and idiomatic: instantiate with new Server({path, datastore}), then call .listen() for a standalone server or .handle()/.handleWeb() to integrate into an existing Node or Fetch-based framework, with typed EventEmitter overloads mapping lifecycle events (POST_CREATE, POST_RECEIVE, POST_FINISH, POST_TERMINATE) to their listener signatures. Getting started requires only a DataStore instance, keeping boilerplate low. The implementation faithfully follows the existing tus protocol and established DataStore/EventEmitter patterns rather than introducing new abstractions, so it scores as solid rather than novel on originality.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search