Skip to content

Upload Pipeline

Upload data with a single call. The SDK selects providers and handles multi-copy replication automatically:

import { class SynapseSynapse } from "@filoz/synapse-sdk";
import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
} from 'viem/accounts'
const const synapse: Synapsesynapse = class SynapseSynapse.Synapse.create(options: SynapseOptions): Synapsecreate({ SynapseOptions.account: `0x${string}` | Accountaccount: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
('0x...'), SynapseOptions.source: string | nullsource: 'my-app' });
const const data: Uint8Array<ArrayBuffer>data = new
var Uint8Array: Uint8ArrayConstructor
new (elements: Iterable<number>) => Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array
([1, 2, 3, 4, 5])
const { const pieceCid: PieceCIDpieceCid, const size: numbersize, const complete: booleancomplete, const copies: CopyResult[]copies, const failedAttempts: FailedAttempt[]failedAttempts } = await const synapse: Synapsesynapse.Synapse.storage: StorageManagerstorage.StorageManager.upload(data: UploadPieceStreamingData, options?: StorageManagerUploadOptions): Promise<UploadResult>upload(const data: Uint8Array<ArrayBuffer>data) var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("PieceCID:", const pieceCid: PieceCIDpieceCid.CID<unknown, 85, 4113, 1>.toString(base?: MultibaseEncoder<string>): string
Returns a string representation of an object.
toString
())
var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("Size:", const size: numbersize, "bytes")
var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("Stored on", const copies: CopyResult[]copies.Array<CopyResult>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
, "providers")
for (const const copy: CopyResultcopy of const copies: CopyResult[]copies) { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(` Provider ${const copy: CopyResultcopy.CopyResult.providerId: bigintproviderId}: role=${const copy: CopyResultcopy.CopyResult.role: CopyRolerole}, dataSet=${const copy: CopyResultcopy.CopyResult.dataSetId: bigintdataSetId}`)
} if (!const complete: booleancomplete) { var console: Consoleconsole.Console.warn(...data: any[]): void
The **`console.warn()`** static method outputs a warning message to the console at the "warning" log level. The message is only displayed to the user if the console is configured to display warning output. In most cases, the log level is configured within the console UI. The message may receive special formatting, such as yellow colors and a warning icon. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static)
warn
("Some copies failed:", const failedAttempts: FailedAttempt[]failedAttempts)
}

The result contains:

  • complete - true when all requested copies were stored and committed on-chain. This is the primary field to check.
  • requestedCopies - the number of copies that were requested (default: 2)
  • pieceCid - content address of your data, used for downloads
  • size - size of the uploaded data in bytes
  • copies - array of successful copies, each with providerId, dataSetId, pieceId, role ('primary' or 'secondary'), retrievalUrl, and isNewDataSet
  • failedAttempts - providers that were tried but did not produce a copy. The SDK retries failed secondaries with alternate providers, so a non-empty array often just means a provider was swapped out. These are diagnostic, check complete for the actual outcome.

Piece batching is enabled by default. Compatible uploads that run concurrently can share an on-chain transaction when they use the same provider and data set. Each provider maintains its own batch.

The SDK automatically splits compatible concurrent uploads according to the encoded Filecoin message-size budget. Legacy data sets additionally have an 80-piece safety cap. Start uploads together without manually grouping them or waiting between groups. See Larger, Cheaper Storage Batches for details.

For browser File objects, start the uploads together to give them an opportunity to join the same batch:

const results = await Promise.all(
  files.map((file) => synapse.storage.upload(file.stream()))
)

Sequential uploads cannot share a batch because each call waits for its own on-chain confirmation before the next call starts:

for (const file of files) {
  await synapse.storage.upload(file.stream())
}

By default, the SDK submits a batch after a zero-delay window once its uploads and pulls finish parking. You can instead hold compatible pieces until the next piece would exceed a piece-count cap or encoded message-size budget, or until you explicitly flush them:

const synapse = Synapse.create({
  account: privateKeyToAccount("0x..."),
  source: 'my-app',
  pieceBatching: { wait: { kind: "limiter" } },
})

const resultsPromise = Promise.allSettled(
  files.map((file) => synapse.storage.upload(file.stream()))
)
await synapse.storage.flush()
const results = await resultsPromise

flush() waits for accepted uploads and pulls to finish parking, then submits their pending batch windows. It does not report whether every upload was submitted or confirmed successfully. Inspect the settled results for rejections and check complete on fulfilled upload results. Start uploads before flushing; awaiting an upload first in limiter mode can leave it waiting indefinitely.

Compatible uploads can report the same transaction hash in their callbacks. Batched secondary pulls sign their per-piece authorization separately from the eventual commit batch, so interactive wallets can prompt again at commit time. To reuse one signature for pull and commit, disable batching or use the split operations with the same presigned extraData.

Set pieceBatching: false when creating Synapse to disable batching. Use the split operations when you need manual control over provider selection, signing, or each store, pull, and commit phase.

Attach metadata to organize uploads. The SDK reuses existing data sets when metadata matches, avoiding duplicate payment rails:

import { class SynapseSynapse } from "@filoz/synapse-sdk";
import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
} from 'viem/accounts'
const const synapse: Synapsesynapse = class SynapseSynapse.Synapse.create(options: SynapseOptions): Synapsecreate({ SynapseOptions.account: `0x${string}` | Accountaccount: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
('0x...'), SynapseOptions.source: string | nullsource: 'my-app' });
const const data: Uint8Array<ArrayBuffer>data = new var TextEncoder: new () => TextEncoder
The **`TextEncoder`** interface enables you to encode a JavaScript string using UTF-8. [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder)
TextEncoder
().TextEncoder.encode(input?: string): Uint8Array<ArrayBuffer>
The **`TextEncoder.encode()`** method takes a string as input, and returns a Uint8Array containing the string encoded using UTF-8. [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode)
encode
("Hello, Filecoin!")
const const result: UploadResultresult = await const synapse: Synapsesynapse.Synapse.storage: StorageManagerstorage.StorageManager.upload(data: UploadPieceStreamingData, options?: StorageManagerUploadOptions): Promise<UploadResult>upload(const data: Uint8Array<ArrayBuffer>data, { BaseContextOptions.metadata?: Record<string, string> | undefinedmetadata: { type Application: stringApplication: "My DApp", type Version: stringVersion: "1.0.0", type Category: stringCategory: "Documents", }, StorageManagerUploadOptions.pieceMetadata?: Record<string, string> | undefinedpieceMetadata: { filename: stringfilename: "hello.txt", contentType: stringcontentType: "text/plain", }, }) var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("Uploaded:", const result: UploadResultresult.UploadResult.pieceCid: PieceCIDpieceCid.CID<unknown, 85, 4113, 1>.toString(base?: MultibaseEncoder<string>): string
Returns a string representation of an object.
toString
())

Subsequent uploads with the same metadata reuse the same data sets and payment rails.

Adjust the number of copies for your durability requirements:

import { class SynapseSynapse } from "@filoz/synapse-sdk"
import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
} from "viem/accounts"
const const synapse: Synapsesynapse = class SynapseSynapse.Synapse.create(options: SynapseOptions): Synapsecreate({ SynapseOptions.account: `0x${string}` | Accountaccount: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
("0x..."), SynapseOptions.source: string | nullsource: 'my-app' })
const const data: Uint8Array<ArrayBuffer>data = new
var Uint8Array: Uint8ArrayConstructor
new (length: number) => Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array
(256)
// Store 3 copies for higher redundancy const const result3: UploadResultresult3 = await const synapse: Synapsesynapse.Synapse.storage: StorageManagerstorage.StorageManager.upload(data: UploadPieceStreamingData, options?: StorageManagerUploadOptions): Promise<UploadResult>upload(const data: Uint8Array<ArrayBuffer>data, { CreateContextsOptions.copies?: number | undefinedcopies: 3 }) var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("3 copies:", const result3: UploadResultresult3.UploadResult.copies: CopyResult[]copies.Array<CopyResult>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
)
// Store a single copy when redundancy isn't needed const const result1: UploadResultresult1 = await const synapse: Synapsesynapse.Synapse.storage: StorageManagerstorage.StorageManager.upload(data: UploadPieceStreamingData, options?: StorageManagerUploadOptions): Promise<UploadResult>upload(const data: Uint8Array<ArrayBuffer>data, { CreateContextsOptions.copies?: number | undefinedcopies: 1 }) var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
("1 copy:", const result1: UploadResultresult1.UploadResult.copies: CopyResult[]copies.Array<CopyResult>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
)

The default is 2 copies. The first copy is stored on an endorsed provider (high trust, curated), and secondary copies are stored with approved providers, which pull the data from the primary via SP-to-SP transfer.

Track the lifecycle of a multi-copy upload with callbacks:

import { class SynapseSynapse } from "@filoz/synapse-sdk"
import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
} from "viem/accounts"
const const synapse: Synapsesynapse = class SynapseSynapse.Synapse.create(options: SynapseOptions): Synapsecreate({ SynapseOptions.account: `0x${string}` | Accountaccount: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
("0x..."), SynapseOptions.source: string | nullsource: 'my-app' })
const const data: Uint8Array<ArrayBuffer>data = new
var Uint8Array: Uint8ArrayConstructor
new (length: number) => Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array
(1024) // 1KB of data
const const result: UploadResultresult = await const synapse: Synapsesynapse.Synapse.storage: StorageManagerstorage.StorageManager.upload(data: UploadPieceStreamingData, options?: StorageManagerUploadOptions): Promise<UploadResult>upload(const data: Uint8Array<ArrayBuffer>data, { StorageManagerUploadOptions.callbacks?: Partial<CombinedCallbacks> | undefinedcallbacks: { onStored?: ((providerId: bigint, pieceCid: PieceCID) => void) | undefinedonStored: (providerId: bigintproviderId, pieceCid: PieceCIDpieceCid) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Data stored on provider ${providerId: bigintproviderId}`)
}, onCopyComplete?: ((providerId: bigint, pieceCid: PieceCID) => void) | undefinedonCopyComplete: (providerId: bigintproviderId, pieceCid: PieceCIDpieceCid) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Secondary copy complete on provider ${providerId: bigintproviderId}`)
}, onCopyFailed?: ((providerId: bigint, pieceCid: PieceCID, error: Error) => void) | undefinedonCopyFailed: (providerId: bigintproviderId, pieceCid: PieceCIDpieceCid, error: Errorerror) => { var console: Consoleconsole.Console.warn(...data: any[]): void
The **`console.warn()`** static method outputs a warning message to the console at the "warning" log level. The message is only displayed to the user if the console is configured to display warning output. In most cases, the log level is configured within the console UI. The message may receive special formatting, such as yellow colors and a warning icon. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static)
warn
(`Copy failed on provider ${providerId: bigintproviderId}:`, error: Errorerror.Error.message: stringmessage)
}, onPullProgress?: ((providerId: bigint, pieceCid: PieceCID, status: PullStatus) => void) | undefinedonPullProgress: (providerId: bigintproviderId, pieceCid: PieceCIDpieceCid, status: pullPiecesApiRequest.PullStatusstatus) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Pull to provider ${providerId: bigintproviderId}: ${status: pullPiecesApiRequest.PullStatusstatus}`)
},
onPiecesAdded?: ((transaction: Hex, providerId: bigint, pieces: {
    pieceCid: PieceCID;
}[]) => void) | undefined
onPiecesAdded
: (txHash: `0x${string}`txHash, providerId: bigintproviderId,
pieces: {
    pieceCid: PieceCID;
}[]
pieces
) => {
var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`On-chain commit submitted: ${txHash: `0x${string}`txHash}`)
}, onPiecesConfirmed?: ((dataSetId: bigint, providerId: bigint, pieces: PieceRecord[]) => void) | undefinedonPiecesConfirmed: (dataSetId: bigintdataSetId, providerId: bigintproviderId, pieces: PieceRecord[]pieces) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Confirmed on-chain: dataSet=${dataSetId: bigintdataSetId}, provider=${providerId: bigintproviderId}`)
}, onProgress?: ((bytesUploaded: number) => void) | undefinedonProgress: (bytesUploaded: numberbytesUploaded) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Uploaded ${bytesUploaded: numberbytesUploaded} bytes`)
}, }, })

Callback lifecycle:

  1. onProgress - fires during upload to primary provider
  2. onStored - primary upload complete, piece parked on SP
  3. onPullProgress - SP-to-SP transfer status for secondaries
  4. onCopyComplete / onCopyFailed - secondary pull result
  5. onPiecesAdded - commit transaction submitted
  6. onPiecesConfirmed - commit confirmed on-chain

upload() is designed around partial success over atomicity: it commits whatever succeeded rather than throwing away successful work. This means the return value is the primary interface for understanding what happened.

upload() only throws in these cases:

Error What happened What to do
StoreError Primary upload failed Retry the upload
CommitError Data is stored on providers but all on-chain commits failed Use split operations to retry commit() without re-uploading
Selection error No endorsed provider available or reachable Check provider health / network

If upload() returns (no throw), at least one copy is committed on-chain. But the result may contain fewer copies than requested. Every copy in copies[] represents a committed on-chain data set that the user is now paying for.

import { class SynapseSynapse } from "@filoz/synapse-sdk"
import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
} from "viem/accounts"
const const synapse: Synapsesynapse = class SynapseSynapse.Synapse.create(options: SynapseOptions): Synapsecreate({ SynapseOptions.account: `0x${string}` | Accountaccount: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
("0x..."), SynapseOptions.source: string | nullsource: 'my-app' })
const const data: Uint8Array<ArrayBuffer>data = new
var Uint8Array: Uint8ArrayConstructor
new (length: number) => Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array
(256)
const const result: UploadResultresult = await const synapse: Synapsesynapse.Synapse.storage: StorageManagerstorage.StorageManager.upload(data: UploadPieceStreamingData, options?: StorageManagerUploadOptions): Promise<UploadResult>upload(const data: Uint8Array<ArrayBuffer>data, { CreateContextsOptions.copies?: number | undefinedcopies: 2 }) // Check overall success: complete === true means all requested copies succeeded if (!const result: UploadResultresult.UploadResult.complete: booleancomplete) { var console: Consoleconsole.Console.warn(...data: any[]): void
The **`console.warn()`** static method outputs a warning message to the console at the "warning" log level. The message is only displayed to the user if the console is configured to display warning output. In most cases, the log level is configured within the console UI. The message may receive special formatting, such as yellow colors and a warning icon. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static)
warn
(`Only ${const result: UploadResultresult.UploadResult.copies: CopyResult[]copies.Array<CopyResult>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length
}/${const result: UploadResultresult.UploadResult.requestedCopies: numberrequestedCopies} copies succeeded`)
for (const const attempt: FailedAttemptattempt of const result: UploadResultresult.UploadResult.failedAttempts: FailedAttempt[]failedAttempts) { var console: Consoleconsole.Console.warn(...data: any[]): void
The **`console.warn()`** static method outputs a warning message to the console at the "warning" log level. The message is only displayed to the user if the console is configured to display warning output. In most cases, the log level is configured within the console UI. The message may receive special formatting, such as yellow colors and a warning icon. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/warn_static)
warn
(` Provider ${const attempt: FailedAttemptattempt.FailedAttempt.providerId: bigintproviderId} (${const attempt: FailedAttemptattempt.FailedAttempt.role: CopyRolerole}): ${const attempt: FailedAttemptattempt.FailedAttempt.error: stringerror}`)
} } // Every copy is committed and being paid for for (const const copy: CopyResultcopy of const result: UploadResultresult.UploadResult.copies: CopyResult[]copies) { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Provider ${const copy: CopyResultcopy.CopyResult.providerId: bigintproviderId}, dataset ${const copy: CopyResultcopy.CopyResult.dataSetId: bigintdataSetId}, piece ${const copy: CopyResultcopy.CopyResult.pieceId: bigintpieceId}`)
}

For auto-selected providers (no explicit providerIds or dataSetIds), the SDK automatically retries failed secondaries with alternate providers up to 5 times. If you explicitly specify providers, the SDK respects your choice and does not retry.

upload() Split Operations
Control Automatic Manual per-phase
Error recovery Re-upload on commit failure Retry commit without re-upload
Batch files One call per file Store many, commit in batch
Wallet prompts Managed internally Control via presignForCommit()
Best for Most use cases Production pipelines, custom UX

Every upload goes through three phases:

store --> pull --> commit
  |         |         |
  |         |         +-- On-chain: create dataset, add piece, start payments
  |         +-- SP-to-SP: secondary provider fetches from primary
  +-- Upload: bytes sent to one provider (no on-chain state yet)
  • store: Upload bytes to a single SP. Returns { pieceCid, size }. The piece is “parked” on the SP but not yet on-chain and subject to garbage collection if not committed.
  • pull: SP-to-SP transfer. The destination SP fetches the piece from a source SP. No client bandwidth used.
  • commit: Submit an on-chain transaction to add the piece to a data set. Creates the data set and payment rail if needed.

Upload data to a provider without committing on-chain:

const const contexts: StorageContext[]contexts = await const synapse: Synapsesynapse.Synapse.storage: StorageManagerstorage.StorageManager.createContexts(options?: CreateContextsOptions): Promise<StorageContext[]>createContexts({
  CreateContextsOptions.copies?: number | undefinedcopies: 2,
})
const [const primary: StorageContextprimary, const secondary: StorageContextsecondary] = const contexts: StorageContext[]contexts

const { const pieceCid: PieceCIDpieceCid, const size: numbersize } = await const primary: StorageContextprimary.StorageContext.store(data: UploadPieceStreamingData, options?: StoreOptions): Promise<StoreResult>store(const data: Uint8Array<ArrayBuffer>data, {
  StoreOptions.pieceCid?: PieceCID | undefinedpieceCid: const preCalculatedCid: PieceCIDpreCalculatedCid,       // skip expensive PieceCID (hash digest) calculation (optional)
  StoreOptions.signal?: AbortSignal | undefinedsignal: const abortController: AbortControllerabortController.AbortController.signal: AbortSignal
The **`signal`** read-only property of the AbortController interface returns an AbortSignal object instance, which can be used to communicate with/abort an asynchronous operation as desired. [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/signal)
signal
, // cancellation (optional)
StoreOptions.onProgress?: ((bytesUploaded: number) => void) | undefinedonProgress: (bytes: numberbytes) => { // progress callback (optional) var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Uploaded ${bytes: numberbytes} bytes`)
}, }) var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Stored: ${const pieceCid: PieceCIDpieceCid}, ${const size: numbersize} bytes`)

store() accepts Uint8Array or ReadableStream<Uint8Array>. Use streaming for large files to minimize memory.

After store completes, the piece is parked on the SP and can be:

  • Retrieved via the context’s getPieceUrl(pieceCid)
  • Pulled to other providers via pull()
  • Committed on-chain via commit()

Request a secondary provider to fetch pieces from the primary:

// Pre-sign to avoid double wallet prompts during pull + commit
const const extraData: `0x${string}`extraData = await const secondary: StorageContextsecondary.
StorageContext.presignForCommit(pieces: Array<{
    pieceCid: PieceCID;
    pieceMetadata?: MetadataObject;
}>): Promise<Hex>
presignForCommit
([{ pieceCid: PieceCIDpieceCid }])
const const pullResult: PullResultpullResult = await const secondary: StorageContextsecondary.StorageContext.pull(options: PullOptions): Promise<PullResult>pull({ PullOptions.pieces: PieceCID[]pieces: [const pieceCid: PieceCIDpieceCid], PullOptions.from: PullSourcefrom: (cid: PieceCIDcid) => const primary: StorageContextprimary.StorageContext.getPieceUrl(pieceCid: PieceCID): stringgetPieceUrl(cid: PieceCIDcid), // source URL builder (or URL string) PullOptions.extraData?: `0x${string}` | undefinedextraData, // pre-signed auth (optional, reused for commit) PullOptions.signal?: AbortSignal | undefinedsignal: const abortController: AbortControllerabortController.AbortController.signal: AbortSignal
The **`signal`** read-only property of the AbortController interface returns an AbortSignal object instance, which can be used to communicate with/abort an asynchronous operation as desired. [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/signal)
signal
, // cancellation (optional)
PullOptions.onProgress?: ((pieceCid: PieceCID, status: PullStatus) => void) | undefinedonProgress: (cid: PieceCIDcid, status: pullPiecesApiRequest.PullStatusstatus) => { // status callback (optional) var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`${cid: PieceCIDcid}: ${status: pullPiecesApiRequest.PullStatusstatus}`)
}, }) if (const pullResult: PullResultpullResult.PullResult.status: "complete" | "failed"status !== "complete") { for (const
const piece: {
    pieceCid: PieceCID;
    status: "complete" | "failed";
    index: number;
}
piece
of const pullResult: PullResultpullResult.
PullResult.pieces: {
    pieceCid: PieceCID;
    status: "complete" | "failed";
    index: number;
}[]
pieces
) {
if (
const piece: {
    pieceCid: PieceCID;
    status: "complete" | "failed";
    index: number;
}
piece
.status: "complete" | "failed"status === "failed") {
var console: Consoleconsole.Console.error(...data: any[]): void
The **`console.error()`** static method outputs a message to the console at the "error" log level. The message is only displayed to the user if the console is configured to display error output. In most cases, the log level is configured within the console UI. The message may be formatted as an error, with red colors and call stack information. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/error_static)
error
(`Failed to pull ${
const piece: {
    pieceCid: PieceCID;
    status: "complete" | "failed";
    index: number;
}
piece
.pieceCid: PieceCIDpieceCid}`)
} } }

The from parameter accepts either a URL string (base service URL) or a function that returns a piece URL for a given PieceCID.

pullResult.pieces has one entry per input piece, in input order, and each entry’s index is its position in pieces. Set dedupe: true to send each PieceCID only once: repeated inputs share the first one’s status and are listed in pullResult.dropped. When you pass a pre-signed extraData with dedupe, sign it over the deduped pieces.

Pre-signing: presignForCommit() creates an EIP-712 signature that can be reused for both pull() and commit(). This avoids prompting the wallet twice. Pass the same extraData to both calls.

Add pieces to an on-chain data set. Creates the data set and payment rail if one doesn’t exist:

// Commit on both providers
const [const primaryCommit: PromiseSettledResult<CommitResult>primaryCommit, const secondaryCommit: PromiseSettledResult<CommitResult>secondaryCommit] = await var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise
.PromiseConstructor.allSettled<[Promise<CommitResult>, Promise<CommitResult>]>(values: [Promise<CommitResult>, Promise<CommitResult>]): Promise<[PromiseSettledResult<CommitResult>, PromiseSettledResult<CommitResult>]> (+1 overload)
Creates a Promise that is resolved with an array of results when all of the provided Promises resolve or reject.
@paramvalues An array of Promises.@returnsA new Promise.
allSettled
([
const primary: StorageContextprimary.StorageContext.commit(options: CommitOptions): Promise<CommitResult>commit({
CommitOptions.pieces: {
    pieceCid: PieceCID;
    pieceMetadata?: MetadataObject;
}[]
pieces
: [{ pieceCid: PieceCIDpieceCid, pieceMetadata?: MetadataObject | undefinedpieceMetadata: { filename: stringfilename: "doc.pdf" } }],
CommitOptions.signal?: AbortSignal | undefinedsignal: const abortController: AbortControllerabortController.AbortController.signal: AbortSignal
The **`signal`** read-only property of the AbortController interface returns an AbortSignal object instance, which can be used to communicate with/abort an asynchronous operation as desired. [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/signal)
signal
, // cancellation (optional)
CommitOptions.onSubmitted?: ((txHash: Hex) => void) | undefinedonSubmitted: (txHash: `0x${string}`txHash) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Transaction submitted: ${txHash: `0x${string}`txHash}`)
}, }), const secondary: StorageContextsecondary.StorageContext.commit(options: CommitOptions): Promise<CommitResult>commit({
CommitOptions.pieces: {
    pieceCid: PieceCID;
    pieceMetadata?: MetadataObject;
}[]
pieces
: [{ pieceCid: PieceCIDpieceCid, pieceMetadata?: MetadataObject | undefinedpieceMetadata: { filename: stringfilename: "doc.pdf" } }],
CommitOptions.extraData?: `0x${string}` | undefinedextraData, // pre-signed auth from presignForCommit() (optional) CommitOptions.signal?: AbortSignal | undefinedsignal: const abortController: AbortControllerabortController.AbortController.signal: AbortSignal
The **`signal`** read-only property of the AbortController interface returns an AbortSignal object instance, which can be used to communicate with/abort an asynchronous operation as desired. [MDN Reference](https://developer.mozilla.org/docs/Web/API/AbortController/signal)
signal
, // cancellation (optional)
CommitOptions.onSubmitted?: ((txHash: Hex) => void) | undefinedonSubmitted: (txHash: `0x${string}`txHash) => { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Transaction submitted: ${txHash: `0x${string}`txHash}`)
}, }) ]) if (const primaryCommit: PromiseSettledResult<CommitResult>primaryCommit.status: "rejected" | "fulfilled"status === "fulfilled") { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Primary: dataSet=${const primaryCommit: PromiseFulfilledResult<CommitResult>primaryCommit.PromiseFulfilledResult<CommitResult>.value: CommitResultvalue.CommitResult.dataSetId: bigintdataSetId}`)
} if (const secondaryCommit: PromiseSettledResult<CommitResult>secondaryCommit.status: "rejected" | "fulfilled"status === "fulfilled") { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Secondary: dataSet=${const secondaryCommit: PromiseFulfilledResult<CommitResult>secondaryCommit.PromiseFulfilledResult<CommitResult>.value: CommitResultvalue.CommitResult.dataSetId: bigintdataSetId}`)
}

The result:

  • txHash - transaction hash
  • pieceIds - assigned piece IDs (one per input piece)
  • dataSetId - data set ID (may be newly created)
  • isNewDataSet - whether a new data set was created

Cancellation: aborting signal after onSubmitted only stops waiting for confirmation. The transaction can still land on chain. If the commit was creating a data set, the context does not learn the new data set ID, so calling commit() on it again creates another data set.

Upload multiple files to 2 providers with full error handling:

import { class SynapseSynapse, type class PieceCIDPieceCID } from "@filoz/synapse-sdk"
import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
} from "viem/accounts"
const const synapse: Synapsesynapse = class SynapseSynapse.Synapse.create(options: SynapseOptions): Synapsecreate({ SynapseOptions.account: `0x${string}` | Accountaccount: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
@descriptionCreates an Account from a private key.@returnsA Private Key Account.
privateKeyToAccount
("0x.."), SynapseOptions.source: string | nullsource: "my-app" })
const const files: Uint8Array<ArrayBuffer>[]files = [ new var TextEncoder: new () => TextEncoder
The **`TextEncoder`** interface enables you to encode a JavaScript string using UTF-8. [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder)
TextEncoder
().TextEncoder.encode(input?: string): Uint8Array<ArrayBuffer>
The **`TextEncoder.encode()`** method takes a string as input, and returns a Uint8Array containing the string encoded using UTF-8. [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode)
encode
("File 1 content..."),
new var TextEncoder: new () => TextEncoder
The **`TextEncoder`** interface enables you to encode a JavaScript string using UTF-8. [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder)
TextEncoder
().TextEncoder.encode(input?: string): Uint8Array<ArrayBuffer>
The **`TextEncoder.encode()`** method takes a string as input, and returns a Uint8Array containing the string encoded using UTF-8. [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode)
encode
("File 2 content..."),
new var TextEncoder: new () => TextEncoder
The **`TextEncoder`** interface enables you to encode a JavaScript string using UTF-8. [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder)
TextEncoder
().TextEncoder.encode(input?: string): Uint8Array<ArrayBuffer>
The **`TextEncoder.encode()`** method takes a string as input, and returns a Uint8Array containing the string encoded using UTF-8. [MDN Reference](https://developer.mozilla.org/docs/Web/API/TextEncoder/encode)
encode
("File 3 content..."),
] // Create contexts for 2 providers const [const primary: StorageContextprimary, const secondary: StorageContextsecondary] = await const synapse: Synapsesynapse.Synapse.storage: StorageManagerstorage.StorageManager.createContexts(options?: CreateContextsOptions): Promise<StorageContext[]>createContexts({ CreateContextsOptions.copies?: number | undefinedcopies: 2, BaseContextOptions.metadata?: Record<string, string> | undefinedmetadata: { source: stringsource: "batch-upload" }, }) // Store all files on primary (note: these could be done in parallel w/ Promise.all) const
const stored: {
    pieceCid: PieceCID;
    size: number;
}[]
stored
: { pieceCid: PieceCIDpieceCid: class PieceCIDPieceCID; size: numbersize: number }[] = []
for (const const file: Uint8Array<ArrayBuffer>file of const files: Uint8Array<ArrayBuffer>[]files) { const const result: StoreResultresult = await const primary: StorageContextprimary.StorageContext.store(data: UploadPieceStreamingData, options?: StoreOptions): Promise<StoreResult>store(const file: Uint8Array<ArrayBuffer>file)
const stored: {
    pieceCid: PieceCID;
    size: number;
}[]
stored
.
Array<{ pieceCid: PieceCID; size: number; }>.push(...items: {
    pieceCid: PieceCID;
    size: number;
}[]): number
Appends new elements to the end of an array, and returns the new length of the array.
@paramitems New elements to add to the array.
push
(const result: StoreResultresult)
var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Stored ${const result: StoreResultresult.StoreResult.pieceCid: PieceCIDpieceCid}`)
} // Pre-sign for all pieces on secondary const const pieceCids: PieceCID[]pieceCids =
const stored: {
    pieceCid: PieceCID;
    size: number;
}[]
stored
.
Array<{ pieceCid: PieceCID; size: number; }>.map<PieceCID>(callbackfn: (value: {
    pieceCid: PieceCID;
    size: number;
}, index: number, array: {
    pieceCid: PieceCID;
    size: number;
}[]) => PieceCID, thisArg?: any): PieceCID[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
(
s: {
    pieceCid: PieceCID;
    size: number;
}
s
=>
s: {
    pieceCid: PieceCID;
    size: number;
}
s
.pieceCid: PieceCIDpieceCid)
const const extraData: `0x${string}`extraData = await const secondary: StorageContextsecondary.
StorageContext.presignForCommit(pieces: Array<{
    pieceCid: PieceCID;
    pieceMetadata?: MetadataObject;
}>): Promise<Hex>
presignForCommit
(
const pieceCids: PieceCID[]pieceCids.
Array<PieceCID>.map<{
    pieceCid: PieceCID;
}>(callbackfn: (value: PieceCID, index: number, array: PieceCID[]) => {
    pieceCid: PieceCID;
}, thisArg?: any): {
    pieceCid: PieceCID;
}[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
(cid: PieceCIDcid => ({ pieceCid: PieceCIDpieceCid: cid: PieceCIDcid }))
) // Pull all pieces to secondary const const pullResult: PullResultpullResult = await const secondary: StorageContextsecondary.StorageContext.pull(options: PullOptions): Promise<PullResult>pull({ PullOptions.pieces: PieceCID[]pieces: const pieceCids: PieceCID[]pieceCids, PullOptions.from: PullSourcefrom: (cid: PieceCIDcid) => const primary: StorageContextprimary.StorageContext.getPieceUrl(pieceCid: PieceCID): stringgetPieceUrl(cid: PieceCIDcid), PullOptions.extraData?: `0x${string}` | undefinedextraData, }) // Commit on both providers const [const primaryCommit: PromiseSettledResult<CommitResult>primaryCommit, const secondaryCommit: PromiseSettledResult<CommitResult>secondaryCommit] = await var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise
.PromiseConstructor.allSettled<[Promise<CommitResult>, Promise<CommitResult>]>(values: [Promise<CommitResult>, Promise<CommitResult>]): Promise<[PromiseSettledResult<CommitResult>, PromiseSettledResult<CommitResult>]> (+1 overload)
Creates a Promise that is resolved with an array of results when all of the provided Promises resolve or reject.
@paramvalues An array of Promises.@returnsA new Promise.
allSettled
([
const primary: StorageContextprimary.StorageContext.commit(options: CommitOptions): Promise<CommitResult>commit({
CommitOptions.pieces: {
    pieceCid: PieceCID;
    pieceMetadata?: MetadataObject;
}[]
pieces
: const pieceCids: PieceCID[]pieceCids.
Array<PieceCID>.map<{
    pieceCid: PieceCID;
}>(callbackfn: (value: PieceCID, index: number, array: PieceCID[]) => {
    pieceCid: PieceCID;
}, thisArg?: any): {
    pieceCid: PieceCID;
}[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
(cid: PieceCIDcid => ({ pieceCid: PieceCIDpieceCid: cid: PieceCIDcid })) }),
const pullResult: PullResultpullResult.PullResult.status: "complete" | "failed"status === "complete" ? const secondary: StorageContextsecondary.StorageContext.commit(options: CommitOptions): Promise<CommitResult>commit({
CommitOptions.pieces: {
    pieceCid: PieceCID;
    pieceMetadata?: MetadataObject;
}[]
pieces
: const pieceCids: PieceCID[]pieceCids.
Array<PieceCID>.map<{
    pieceCid: PieceCID;
}>(callbackfn: (value: PieceCID, index: number, array: PieceCID[]) => {
    pieceCid: PieceCID;
}, thisArg?: any): {
    pieceCid: PieceCID;
}[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
(cid: PieceCIDcid => ({ pieceCid: PieceCIDpieceCid: cid: PieceCIDcid })), CommitOptions.extraData?: `0x${string}` | undefinedextraData })
: var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise
.PromiseConstructor.reject<never>(reason?: any): Promise<never>
Creates a new rejected promise for the provided reason.
@paramreason The reason the promise was rejected.@returnsA new rejected Promise.
reject
(new
var Error: ErrorConstructor
new (message?: string, options?: ErrorOptions) => Error (+1 overload)
Error
("Pull failed, skipping secondary commit")), // not advised!
]) if (const primaryCommit: PromiseSettledResult<CommitResult>primaryCommit.status: "rejected" | "fulfilled"status === "fulfilled") { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Primary: dataSet=${const primaryCommit: PromiseFulfilledResult<CommitResult>primaryCommit.PromiseFulfilledResult<CommitResult>.value: CommitResultvalue.CommitResult.dataSetId: bigintdataSetId}`)
} if (const secondaryCommit: PromiseSettledResult<CommitResult>secondaryCommit.status: "rejected" | "fulfilled"status === "fulfilled") { var console: Consoleconsole.Console.log(...data: any[]): void
The **`console.log()`** static method outputs a message to the console. [MDN Reference](https://developer.mozilla.org/docs/Web/API/console/log_static)
log
(`Secondary: dataSet=${const secondaryCommit: PromiseFulfilledResult<CommitResult>secondaryCommit.PromiseFulfilledResult<CommitResult>.value: CommitResultvalue.CommitResult.dataSetId: bigintdataSetId}`)
}

Each phase’s errors are independent. Failures don’t cascade, and you can retry at any level:

Phase Failure Data state Recovery
store Upload/network error No data on SP Retry store() with same or different context
pull SP-to-SP transfer failed Data on primary only Retry pull(), try different secondary, or skip
commit On-chain transaction failed Data on SP but not on-chain Retry commit() (no re-upload needed)

The key advantage of split operations: if commit fails, data is already stored on the SP. You can retry commit() without re-uploading the data. With the high-level upload(), a CommitError would require re-uploading.

  • Storage Operations - Data set management, retrieval, downloads, and lifecycle operations.

  • Storage Costs - Calculate your monthly costs and understand funding requirements.

  • Synapse Core - Use the core library directly for maximum control over provider selection, uploads, and SP-to-SP transfers.