tus-node-server

repository·main·Indexed 22 days ago

https://github.com/tus/tus-node-server

Official Node.js implementation of the tus resumable upload protocol. It provides a server for reliable, interruptible file uploads and supports multiple storage backends including local disk (@tus/file-store), AWS S3 and S3-compatible storage (@tus/s3-store), GCS, and Azure (@tus/azure-store). It can be run as a standalone server or integrated into existing Node.js frameworks like Express, Koa, and Fastify, as well as meta-frameworks using the Web Request/Response API.

Tokens
17.5K
Snippets
50
Records
75
Agent score
77%

What's inside tus-node-server

  1. Available tus-node-server packages and storage providers

    main

    The project is modularized into several packages depending on your storage needs:

    • @tus/server: The core tus server implementation. Can be used standalone or integrated into existing servers.
    • @tus/file-store: Stores uploaded files on the local file system.
    • @tus/s3-store: Stores uploaded files on AWS S3 or S3-compatible storage.
    • @tus/gcs-store: Stores uploaded files on Google Cloud Storage.
    • @tus/azure-store: Stores uploaded files on Azure.
  2. Use Key-Value Stores (KvStores) for caching

    main

    Tus stores typically save both the uploaded file and an info file (metadata). You can use KvStore implementations as a cache in stores like @tus/s3-store to improve performance. Supported implementations include:

    • MemoryKvStore: In-memory cache.
    • FileKvStore: Persists metadata to files on disk.
    • RedisKvStore: Uses a standard redis client.
    • IoRedisKvStore: Uses the ioredis client.
    import { MemoryKvStore } from "@tus/server";
    import S3Store, { type MetadataValue } from "@tus/s3-store";
    
    new S3Store({
      // ...
      cache: new MemoryKvStore<MetadataValue>(),
    });
  3. Manage expired uploads with S3 Lifecycle policies

    main

    The @tus/s3-store uses a Tus-Completed tag to indicate if an upload is finished. You can use an S3 Lifecycle policy to automatically clean up incomplete uploads (where Tus-Completed is false) without needing a CRON job to call server.cleanUpExpiredUploads().

    {
      "Rules": [
        {
          "Filter": {
            "Tag": {
              "Key": "Tus-Completed",
              "Value": "false"
            }
          },
          "Expiration": {
            "Days": 2
          }
        }
      ]
    }
  4. Integrate @tus/server with Next.js

    main

    Pages Router

    In the Pages router, use an optional catch-all route (e.g., /pages/api/upload/[[...file]].ts). You must disable the default body parser in the route config to allow tus to handle the stream.

    import type { NextApiRequest, NextApiResponse } from "next";
    import { Server } from "@tus/server";
    import { FileStore } from "@tus/file-store";
    
    export const config = {
      api: {
        bodyParser: false,
      },
    };
    
    const tusServer = new Server({
      path: "/api/upload",
      datastore: new FileStore({ directory: "./files" }),
    });
    
    export default function handler(req: NextApiRequest, res: NextApiResponse) {
      return tusServer.handle(req, res);
    }

    App Router

    In the App router, export the server.handleWeb method for all supported HTTP methods (GET, POST, PATCH, DELETE, OPTIONS, HEAD) in your route handler file (e.g., /app/api/upload/[[...slug]]/route.ts).

    import { Server } from "@tus/server";
    import { FileStore } from "@tus/file-store";
    
    const server = new Server({
      path: "/api/upload",
      datastore: new FileStore({ directory: "./files" }),
    });
    
    export const GET = server.handleWeb;
    export const POST = server.handleWeb;
    export const PATCH = server.handleWeb;
    export const DELETE = server.handleWeb;
    export const OPTIONS = server.handleWeb;
    export const HEAD = server.handleWeb;
  5. Run a standalone tus server with FileStore

    main

    To run a standalone tus server that stores uploaded files on your local disk, use the Server class from @tus/server and provide a FileStore instance from @tus/file-store. Configure the path for the upload endpoint and the directory where files should be saved.

    import { Server } from "@tus/server";
    import { FileStore } from "@tus/file-store";
    
    const host = "127.0.0.1";
    const port = 1080;
    const server = new Server({
      path: "/files",
      datastore: new FileStore({ directory: "./files" }),
    });
    
    server.listen({ host, port });
  6. Configure @tus/server for use behind a reverse proxy

    main

    When running behind a reverse proxy like Nginx or HAProxy, follow these steps:

    1. Enable Forwarded Headers: Set respectForwardedHeaders: true in the Server options so the server respects X-Forwarded-* or Forwarded headers.
    2. Disable Request Buffering: Ensure the proxy does not buffer the entire request body before forwarding. Buffering defeats the purpose of resumable uploads.
    3. Adjust Maximum Request Size: Ensure the proxy's maximum request size limit is high enough to accommodate large uploads.
    4. Forward Hostname and Scheme: Configure the proxy to set X-Forwarded-Host and X-Forwarded-Proto headers. This prevents the server from returning incorrect redirect URLs to the client.
    import { Server } from "@tus/server";
    // ...
    
    const server = new Server({
      // ..
      respectForwardedHeaders: true,
    });
  7. Integrate tus into existing Node.js servers

    main
    To integrate @tus/server into an existing Node.js server (like Express, Koa, or Fastify), use the server.handle(req, res) method. This method converts standard Node.js http.IncomingMessage and http.ServerResponse objects into the Request and Response objects used by the tus server. You can access the original Node.js objects via req.runtime.node.req and res.runtime.node.res within hooks.
  8. Quick start: Create a standalone tus server

    main

    To create a basic standalone tus server that stores files on the local disk, use the Server class from @tus/server combined with a datastore like @tus/file-store.

    import { Server } from "@tus/server";
    import { FileStore } from "@tus/file-store";
    
    const host = "127.0.0.1";
    const port = 1080;
    
    const server = new Server({
      path: "/files",
      datastore: new FileStore({ directory: "./files" }),
    });
    server.listen({ host, port });
  9. Configure CORS and allowed origins

    main

    The server handles CORS automatically based on the allowedOrigins option in ServerOptions.

    • If allowedOrigins is not provided: The server defaults to * (allow all).
    • If allowedOrigins is an array of strings: The server checks if the incoming Origin header matches any string in the array. If it matches, that origin is returned in Access-Control-Allow-Origin. If not, it defaults to the first origin in the array.
    • If allowedOrigins is a function: The server calls the function with the incoming Origin header. If the function returns a truthy value, that value is used as the allowed origin.