Try it

Pick a file once — Create session and PUT upload use the same name, type, and size.

Upload file
No file chosen

Required for upload session and CDN PUT examples.

Packages

@reupload/sdk

View on npm →

Official server-side Node.js SDK for the Reupload public API. TypeScript-first, zero runtime dependencies (Node 20.9+, native fetch).

All packages · reupload-sdk (Python) · @reupload/client · Server-side uploads

Install

terminal
npm install @reupload/sdk

Environment variables

VariableRequiredDescription
REUPLOAD_API_KEYYesAPI key (ru_…)
REUPLOAD_PROJECT_IDYesProject UUID for uploads (from project settings in the dashboard)
REUPLOAD_API_BASE_URLNoDefault https://api.reupload.dev/api/v1

Quick start

server.ts
import { createReuploadFromEnv } from "@reupload/sdk";
 
const reupload = createReuploadFromEnv();
 
const me = await reupload.whoami();
console.log(me.projects);

API overview

MethodDescription
reupload.whoami()Verify key and list projects
reupload.uploads.createSession()Start CDN upload session
putToUploadUrl()PUT bytes to signed CDN URL
reupload.uploads.complete()Finalize CDN upload
reupload.uploads.upload()Session + CDN PUT + complete in one call
reupload.uploads.uploadDirect()Server multipart direct upload (single file)
reupload.uploads.uploadDirectBatch()Multiple files in one multipart request
reupload.uploads.getSession()Poll session status
reupload.files.get() / access() / delete()File metadata and signed URLs

HTTP equivalents: API reference.

CDN upload from Node

upload.ts
import { createReuploadFromEnv, putToUploadUrl } from "@reupload/sdk";
import { readFile } from "node:fs/promises";
 
const reupload = createReuploadFromEnv();
const bytes = await readFile("./photo.jpg");
 
const session = await reupload.uploads.createSession({
  projectId: process.env.REUPLOAD_PROJECT_ID!,
  filename: "photo.jpg",
  contentType: "image/jpeg",
  size: bytes.length,
  isPublic: true, // optional
});
 
await putToUploadUrl(session.uploadUrl, bytes, "image/jpeg");
 
const done = await reupload.uploads.complete({ uploadId: session.uploadId });
console.log(done.fileId);

Direct upload

One multipart request to Reupload — use when the browser uploads to your API first. See Server-side uploads.

direct.ts
const result = await reupload.uploads.uploadDirect({
  projectId: process.env.REUPLOAD_PROJECT_ID!,
  isPublic: true, // optional — multipart field isPublic=true
  file: {
    data: buffer,
    filename: "photo.jpg",
    contentType: "image/jpeg",
    size: buffer.length,
  },
});
// { uploadId, fileId, status: "processing" }

Direct upload stores your file before the response returns

202 + processing means background work (scan, finalize, quotas) is still running — not that the upload failed. Use webhooks or poll GET /uploads/session/:uploadId for path, url, and confirmed sizeBytes. Why this design →

Multiple files

direct-batch.ts
import { buildDirectUploadBatchFormData } from "@reupload/sdk";
 
const { files } = await reupload.uploads.uploadDirectBatch({
  projectId: process.env.REUPLOAD_PROJECT_ID!,
  files: [fileA, fileB],
});
 
// Or build FormData yourself:
const form = buildDirectUploadBatchFormData({
  projectId: process.env.REUPLOAD_PROJECT_ID!,
  files: [fileA, fileB],
});

Framework route helpers

Handle incoming multipart from your app and forward to uploadDirect. Subpath imports:

ImportRuntime
@reupload/sdk/nextNext.js App + Pages Router
@reupload/sdk/expressExpress (+ multer)
@reupload/sdk/fastifyFastify (+ multipart)
@reupload/sdk/h3H3 / Nitro
@reupload/sdk/solidSolidStart (H3-compatible)

Next.js App Router

app/api/upload/route.ts
import { createReuploadFromEnv } from "@reupload/sdk";
import { handleNextDirectUpload } from "@reupload/sdk/next";
 
const client = createReuploadFromEnv();
 
export async function POST(request: Request) {
  return handleNextDirectUpload(request, { client });
}

Express

routes/upload.ts
import multer from "multer";
import { createReuploadFromEnv } from "@reupload/sdk";
import { createExpressMulterDirectUploadHandler } from "@reupload/sdk/express";
 
const upload = multer({ storage: multer.memoryStorage() });
const client = createReuploadFromEnv();
 
app.post(
  "/api/upload",
  upload.single("file"),
  createExpressMulterDirectUploadHandler({
    client,
    getFile: (req) => req.file,
  }),
);

Backend file router (CDN)

For browser CDN uploads, expose routes your front end calls — then use @reupload/client or @reupload/react in the UI. Example with the SDK on the server:

  • POST /uploads/prepare uploads.createSession()
  • POST /uploads/completeuploads.complete()
  • GET /uploads/:id/statusuploads.getSession()

CDN walkthrough: React/Next + Node.js. Direct upload: Server-side upload.

Errors

errors.ts
import { isReuploadError, isReuploadCdnError } from "@reupload/sdk";
 
try {
  await reupload.files.get(fileId);
} catch (error) {
  if (isReuploadError(error)) {
    console.error(error.status, error.code, error.message);
  }
  if (isReuploadCdnError(error)) {
    console.error("CDN PUT failed", error.status);
  }
}