Skip to main content
The tusky.file module handles uploading, downloading, listing, and deleting files within environments. Files uploaded to encrypted environments are automatically encrypted client-side before being published to the Walrus network.

Upload a File

From a File Path (Node.js)

The simplest way to upload in a Node.js environment:
const file = await tusky.file.upload("env_abc123", "./documents/report.pdf", {
  name: "Q4 Report.pdf",
});

console.log("Uploaded:", file.id);
console.log("Size:", file.size, "bytes");

From a Buffer

Upload file content directly from a Buffer or Uint8Array:
const buffer = Buffer.from("Hello, Walrus!");

const file = await tusky.file.upload("env_abc123", buffer, {
  name: "greeting.txt",
  mimeType: "text/plain",
});

From a ReadableStream

Stream large files without loading them entirely into memory:
import { createReadStream } from "fs";

const stream = createReadStream("./large-video.mp4");

const file = await tusky.file.upload("env_abc123", stream, {
  name: "presentation.mp4",
  mimeType: "video/mp4",
});

Upload Options

OptionTypeDefaultDescription
namestringFilename from pathDisplay name for the file.
mimeTypestringAuto-detectedMIME type of the file content.
epochsnumberEnvironment defaultNumber of Walrus storage epochs for this file.
autoExtendbooleanEnvironment defaultAutomatically renew storage before expiry.
Use the upload cost endpoint to preview the storage cost before uploading. Cost = Walrus storage cost (WAL) + gas fee (SUI). Tusky charges no infrastructure fee.

Upload Cost

Preview the cost of uploading one or more files before committing. Pass a list of file sizes to get a per-file breakdown and totals:
const estimate = await tusky.upload.cost({
  files: [
    { size: 10485760, name: "video.mp4" },
    { size: 2097152, name: "document.pdf" },
    { size: 524288, name: "image.png" },
  ],
  epochs: 5,
});

// Per-file breakdown
for (const file of estimate.files) {
  console.log(`${file.name}: ${file.walCost} WAL, ${file.gasCost} SUI`);
}

// Totals
console.log("Total WAL:", estimate.totals.totalWal);
console.log("Total SUI:", estimate.totals.totalSui);
console.log("Balance sufficient:", estimate.balance.sufficient);
The estimate includes your current wallet balance and whether it covers the batch. If the publisher has autoConvert: true, a WAL shortfall is covered by swapping SUI automatically.

Get File Metadata

Retrieve metadata for a specific file:
const file = await tusky.file.get("file_xyz789");

console.log(file.name);        // "Q4 Report.pdf"
console.log(file.size);        // 2048576
console.log(file.mimeType);    // "application/pdf"
console.log(file.environmentId);     // "env_abc123"
console.log(file.blobId);      // Walrus blob identifier
console.log(file.createdAt);   // ISO 8601 timestamp

List Files

List all files in an environment:
const files = await tusky.file.list("env_abc123");

for (const file of files) {
  console.log(`${file.name} (${file.size} bytes)`);
}

Download a File

Retrieve the file content as an ArrayBuffer:
const content = await tusky.file.arrayBuffer("file_xyz789");

// Write to disk in Node.js
import { writeFileSync } from "fs";
writeFileSync("./downloaded-report.pdf", Buffer.from(content));
The SDK auto-detects encrypted files and decrypts transparently using your wallet credentials. No separate method or flag needed — arrayBuffer() handles both public and private content.

Download via a custom aggregator

Fetch files from any Walrus aggregator by setting aggregatorUrl at init. Works even if Tusky’s API is unavailable:
const tusky = new Tusky({
  wallet: keypair,
  aggregatorUrl: "https://aggregator.walrus.site",
});

const content = await tusky.file.arrayBuffer("file_xyz789");
// Fetched from the public aggregator, decrypted client-side
See Decryption without Tusky for the full offline scenario.

Delete a File

Remove a file from an environment:
await tusky.file.delete("file_xyz789");
console.log("File deleted");
Deleting a file removes it from Tusky and your aggregator. The underlying Walrus blob persists until its storage epochs expire.

Complete Example

import { Tusky } from "@tusky-io/ts-sdk";
import { readFileSync, writeFileSync } from "fs";

const tusky = new Tusky({ apiKey: process.env.TUSKY_API_KEY });

// Upload a file
const file = await tusky.file.upload("env_abc123", "./photo.jpg", {
  name: "vacation.jpg",
  epochs: 5,
  autoExtend: true,
});

console.log("Uploaded:", file.id);

// List all files in the environment
const files = await tusky.file.list("env_abc123");
console.log("Files in environment:", files.length);

// Download the file
const content = await tusky.file.arrayBuffer(file.id);
writeFileSync("./downloaded-photo.jpg", Buffer.from(content));
console.log("Downloaded successfully");

// Clean up
await tusky.file.delete(file.id);

What’s Next