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/client

View on npm →

Browser client for uploading through your backend file router. The Reupload API key stays on the server — the browser only calls your API and PUTs to the signed CDN URL.

All packages · @reupload/sdk · reupload-sdk · @reupload/react · Client-side uploads (API)

Install

terminal
npm install @reupload/client

Environment

Point at your Node (or other) API — not the Reupload API URL.

.env.local
# Next.js
NEXT_PUBLIC_API_URL=http://localhost:3001
 
# Vite
VITE_API_URL=http://localhost:3001

Quick start

CDN flow: prepare → PUT uploadUrl complete.

upload.ts
import { createReuploadClientFromEnv } from "@reupload/client";
 
const client = createReuploadClientFromEnv();
 
async function onFileSelected(file: File) {
  const { uploadId, fileId } = await client.uploadFile(file);
 
  const final = await client.pollUploadStatus(uploadId);
  if (final.status === "COMPLETED") {
    console.log("Ready:", fileId);
  }
}

Backend file router

Default routes (override with routes in the constructor). Implement these on your server with @reupload/sdk:

MethodPathPurpose
POST/uploads/prepareCreate session → uploadUrl, uploadId, fileId
POST/uploads/completeFinalize CDN upload ({ uploadId })
GET/uploads/:uploadId/statusPoll { status, fileId }
GET/files/:fileId/accessSigned download URL

Custom paths

client.ts
import { ReuploadClient } from "@reupload/client";
 
const client = new ReuploadClient({
  apiUrl: "https://api.myapp.com",
  routes: {
    prepare: "/api/v1/files/prepare",
    status: (id) => `/api/v1/files/uploads/${id}`,
  },
});

API

MethodDescription
uploadFile(file)Full CDN flow via your backend
prepareUpload() / completeUpload()Individual CDN steps
putFileToUploadUrl()CDN PUT with optional progress (XHR)
pollUploadStatus()Poll until terminal status
getFileAccess()Signed URL from your backend
validateFile()Client-side size / MIME checks

React hook

Headless hook at @reupload/client/react. For UI components, prefer @reupload/react.

FileUpload.tsx
"use client";
 
import { useReuploadUpload } from "@reupload/client/react";
 
export function FileUpload() {
  const { upload, state, reset, isUploading } = useReuploadUpload({
    validation: { maxBytes: 52_428_800, accept: ["image/*"] },
  });
 
  return (
    <div>
      <input
        type="file"
        disabled={isUploading}
        onChange={(e) => {
          const file = e.target.files?.[0];
          if (file) void upload(file);
        }}
      />
      {state.status === "completed" ? <p>Done — {state.fileId}</p> : null}
      {state.status === "error" ? <p>{state.message}</p> : null}
      <button type="button" onClick={reset}>Reset</button>
    </div>
  );
}

Errors

errors.ts
import { isReuploadClientError } from "@reupload/client";
 
try {
  await client.uploadFile(file);
} catch (error) {
  if (isReuploadClientError(error)) {
    // error.phase === "backend" | "cdn"
    console.error(error.status, error.message);
  }
}

What this package does not do