Storage Context
Storage Context Overview
Section titled “Storage Context Overview”A Storage Context represents a connection to a specific storage provider and data set. Unlike the auto-managed approach in the Storage Operations Guide, contexts give you explicit control over provider selection, data set management, batch operations, lifecycle, and download strategies.
Storage Contexts
Section titled “Storage Contexts”Create contexts via synapse.storage.createContext() or createContexts() for multi-copy scenarios.
Creating Contexts
Section titled “Creating Contexts”import { class Synapse
Synapse } from "@filoz/synapse-sdk"import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
privateKeyToAccount } from "viem/accounts"
const const synapse: Synapse
synapse = class Synapse
Synapse.Synapse.create(options: SynapseOptions): Synapse
create({ SynapseOptions.account: `0x${string}` | Account
account: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
privateKeyToAccount("0x..."), SynapseOptions.source: string | null
source: "my-app" })
// Single context — all options are optionalawait const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.createContext(options?: StorageServiceOptions): Promise<StorageContext>
createContext({ StorageServiceOptions.providerId?: bigint | undefined
providerId: 1n, // specific provider (optional) StorageServiceOptions.dataSetId?: bigint | undefined
dataSetId: 42n, // specific data set (optional) BaseContextOptions.metadata?: Record<string, string> | undefined
metadata: { source: string
source: "my-app" }, // data set metadata for matching/creation BaseContextOptions.withCDN?: boolean | undefined
withCDN: true, // enable fast-retrieval (paid, optional) StorageServiceOptions.excludeProviderIds?: bigint[] | undefined
excludeProviderIds: [3n], // skip specific providers (optional)})For multi-copy replication, use createContexts():
// Multiple contexts for multi-copyconst const contexts: StorageContext[]
contexts = await const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.createContexts(options?: CreateContextsOptions): Promise<StorageContext[]>
createContexts({ CreateContextsOptions.copies?: number | undefined
copies: 3, // number of contexts (default: 2) CreateContextsOptions.providerIds?: bigint[] | undefined
providerIds: [1n, 2n, 3n], // specific providers (mutually exclusive with dataSetIds) CreateContextsOptions.dataSetIds?: bigint[] | undefined
dataSetIds: [10n, 20n, 30n], // specific data sets (mutually exclusive with providerIds)})const [const primary: StorageContext
primary, const secondary: StorageContext
secondary] = const contexts: StorageContext[]
contextsView creation options for createContext()
View creation options for createContexts()
Data Set Selection and Matching
Section titled “Data Set Selection and Matching”The SDK intelligently manages data sets to minimize on-chain transactions. The selection behavior depends on the parameters you provide:
Selection Scenarios:
- Explicit data set ID: If you specify
dataSetId, that exact data set is used (must exist and be accessible) - Specific provider: If you specify
providerId, the SDK searches for matching data sets only within that provider’s existing data sets - Automatic selection: Without specific parameters, the SDK searches across all your data sets with any approved provider
Exact Metadata Matching: In scenarios 2 and 3, the SDK will reuse an existing data set only if it has exactly the same metadata keys and values as requested. This ensures data sets remain organized according to your specific requirements.
Selection Priority: When multiple data sets match your criteria:
- Data sets with existing pieces are preferred over empty ones
- Within each group (with pieces vs. empty), the oldest data set (lowest ID) is selected
Provider Selection (when no matching data sets exist):
- If you specify a provider (via
providerId), that provider is used - Otherwise, the SDK selects from endorsed providers for the primary copy and any approved provider for secondaries
- Before finalizing selection, the SDK verifies the provider is reachable via a ping test
- If a provider fails the ping test, the SDK tries the next candidate
- A new data set will be created automatically during the first commit
Storage Context Methods
Section titled “Storage Context Methods”Uploading Data
Section titled “Uploading Data”Upload data to a provider and commit on-chain:
const const context: StorageContext
context = await const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.createContext(options?: StorageServiceOptions): Promise<StorageContext>
createContext()
const const result: UploadResult
result = await const context: StorageContext
context.StorageContext.upload(data: UploadPieceStreamingData, options?: UploadOptions): Promise<UploadResult>
upload(const data: Uint8Array<ArrayBuffer>
data, { UploadCallbacks.onStored?: ((providerId: bigint, pieceCid: PieceCID) => void) | undefined
onStored: (providerId: bigint
providerId, pieceCid: PieceLink
pieceCid) => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log(`Data stored on provider ${providerId: bigint
providerId}`) }, UploadCallbacks.onPiecesAdded?: ((transaction: Hex, providerId: bigint, pieces: { pieceCid: PieceCID;}[]) => void) | undefined
onPiecesAdded: (txHash: `0x${string}`
txHash, providerId: bigint
providerId, pieces: { pieceCid: PieceCID;}[]
pieces) => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log(`On-chain commit submitted: ${txHash: `0x${string}`
txHash}`) }, UploadCallbacks.onPiecesConfirmed?: ((dataSetId: bigint, providerId: bigint, pieces: PieceRecord[]) => void) | undefined
onPiecesConfirmed: (dataSetId: bigint
dataSetId, providerId: bigint
providerId, pieces: PieceRecord[]
pieces) => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log(`Confirmed on-chain: dataSet=${dataSetId: bigint
dataSetId}, provider=${providerId: bigint
providerId}`) }, StoreOptions.onProgress?: ((bytesUploaded: number) => void) | undefined
onProgress: (bytes: number
bytes) => { var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log(`Uploaded ${bytes: number
bytes} bytes`) },})
var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log(`Stored: ${const result: UploadResult
result.UploadResult.pieceCid: PieceLink
pieceCid}, ${const result: UploadResult
result.UploadResult.size: number
size} bytes`)Terminating a Data Set
Section titled “Terminating a Data Set”Irreversible Operation
Data set termination cannot be undone. Once initiated:
- The termination transaction is irreversible
- After the termination period, the provider may delete all data
- Payment rails associated with the data set will be terminated
- You cannot cancel the termination
Only terminate data sets when you’re certain you no longer need the data.
To delete an entire data set and discontinue payments for the service, call context.terminate().
This method submits an on-chain transaction to initiate the termination process. Following a defined termination period, payments will cease, and the service provider will be able to delete the data set.
You can also terminate a data set using synapse.storage.terminateDataSet({ dataSetId }), when the data set ID is known and creating a context is not necessary.
import { class Synapse
Synapse } from "@filoz/synapse-sdk"import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
privateKeyToAccount } from "viem/accounts"
const const synapse: Synapse
synapse = class Synapse
Synapse.Synapse.create(options: SynapseOptions): Synapse
create({ SynapseOptions.account: `0x${string}` | Account
account: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
privateKeyToAccount("0x..."), SynapseOptions.source: string | null
source: "my-app" })const const ctx: StorageContext
ctx = await const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.createContext(options?: StorageServiceOptions): Promise<StorageContext>
createContext({ BaseContextOptions.metadata?: Record<string, string> | undefined
metadata: { source: string
source: "my-app" },})// Via contextconst const hash: `0x${string}`
hash = await const ctx: StorageContext
ctx.StorageContext.terminate(): Promise<Hash>
terminate()await const synapse: Synapse
synapse.Synapse.client: Client<Transport, Chain, Account, PublicRpcSchema, PublicActions<Transport, Chain>>
client.waitForTransactionReceipt: (args: WaitForTransactionReceiptParameters<Chain>) => Promise<TransactionReceipt>
Waits for the Transaction to be included on a Block (one confirmation), and then returns the Transaction Receipt. If the Transaction reverts, then the action will throw an error.
- Docs: https://viem.sh/docs/actions/public/waitForTransactionReceipt
- Example: https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_sending-transactions
- JSON-RPC Methods:
- Polls
eth_getTransactionReceipt on each block until it has been processed.
- If a Transaction has been replaced:
- Calls
eth_getBlockByNumber and extracts the transactions
- Checks if one of the Transactions is a replacement
- If so, calls
eth_getTransactionReceipt.
waitForTransactionReceipt({ hash: `0x${string}`
The hash of the transaction.
hash })var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log("Dataset terminated successfully")
// Or directly by data set IDconst const hash2: `0x${string}`
hash2 = await const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.terminateDataSet(options: { dataSetId: bigint;}): Promise<Hash>
terminateDataSet({ dataSetId: bigint
dataSetId: 42n })await const synapse: Synapse
synapse.Synapse.client: Client<Transport, Chain, Account, PublicRpcSchema, PublicActions<Transport, Chain>>
client.waitForTransactionReceipt: (args: WaitForTransactionReceiptParameters<Chain>) => Promise<TransactionReceipt>
Waits for the Transaction to be included on a Block (one confirmation), and then returns the Transaction Receipt. If the Transaction reverts, then the action will throw an error.
- Docs: https://viem.sh/docs/actions/public/waitForTransactionReceipt
- Example: https://stackblitz.com/github/wevm/viem/tree/main/examples/transactions_sending-transactions
- JSON-RPC Methods:
- Polls
eth_getTransactionReceipt on each block until it has been processed.
- If a Transaction has been replaced:
- Calls
eth_getBlockByNumber and extracts the transactions
- Checks if one of the Transactions is a replacement
- If so, calls
eth_getTransactionReceipt.
waitForTransactionReceipt({ hash: `0x${string}`
The hash of the transaction.
hash: const hash2: `0x${string}`
hash2 })Deleting a Piece
Section titled “Deleting a Piece”To delete an individual piece from the data set, call context.deletePiece().
This method submits an on-chain transaction to initiate the deletion process.
Important: Piece deletion is irreversible and cannot be canceled once initiated.
import { class Synapse
Synapse } from "@filoz/synapse-sdk"import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
privateKeyToAccount } from "viem/accounts"
const const synapse: Synapse
synapse = class Synapse
Synapse.Synapse.create(options: SynapseOptions): Synapse
create({ SynapseOptions.account: `0x${string}` | Account
account: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
privateKeyToAccount("0x..."), SynapseOptions.source: string | null
source: "my-app" })const const ctx: StorageContext
ctx = await const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.createContext(options?: StorageServiceOptions): Promise<StorageContext>
createContext({ BaseContextOptions.metadata?: Record<string, string> | undefined
metadata: { source: string
source: "my-app" },})// List all pieces in the data setconst const pieces: any[]
pieces = []for await (const const piece: PieceRecord
piece of const ctx: StorageContext
ctx.StorageContext.getPieces(options?: { batchSize?: bigint;}): AsyncGenerator<PieceRecord>
getPieces()) { const pieces: any[]
pieces.Array<any>.push(...items: any[]): number
Appends new elements to the end of an array, and returns the new length of the array.
push(const piece: PieceRecord
piece)}
if (const pieces: any[]
pieces.Array<any>.length: number
Gets or sets the length of the array. This is a number one higher than the highest index in the array.
length > 0) { await const ctx: StorageContext
ctx.StorageContext.deletePiece(options: { piece: string | PieceCID | bigint;}): Promise<Hash>
deletePiece({ piece: string | bigint | PieceLink
piece: const pieces: PieceRecord[]
pieces[0].PieceRecord.pieceId: bigint
pieceId }) var console: Console
console.Console.log(...data: any[]): void
The console.log() static method outputs a message to the console.
log( `Piece ${const pieces: PieceRecord[]
pieces[0].PieceRecord.pieceCid: PieceLink
pieceCid} (ID: ${const pieces: PieceRecord[]
pieces[0].PieceRecord.pieceId: bigint
pieceId}) deleted successfully` )}
// Delete by PieceCIDawait const ctx: StorageContext
ctx.StorageContext.deletePiece(options: { piece: string | PieceCID | bigint;}): Promise<Hash>
deletePiece({ piece: string | bigint | PieceLink
piece: "bafkzcib..." })Downloading Options
Section titled “Downloading Options”The SDK provides flexible download options with clear semantics:
SP-Agnostic Download (from anywhere)
Section titled “SP-Agnostic Download (from anywhere)”Download pieces from any available provider using the StorageManager:
// Download from any provider that has the piececonst const data: Uint8Array<ArrayBufferLike>
data = await const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.download(options: StorageManagerDownloadOptions): Promise<Uint8Array>
download({ pieceCid: string | PieceLink
pieceCid })
// Download with CDN optimization (if available)const const dataWithCDN: Uint8Array<ArrayBufferLike>
dataWithCDN = await const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.download(options: StorageManagerDownloadOptions): Promise<Uint8Array>
download({ pieceCid: string | PieceLink
pieceCid, withCDN?: boolean | undefined
withCDN: true })Context-Specific Download (from this provider)
Section titled “Context-Specific Download (from this provider)”When using a StorageContext, downloads are automatically restricted to that specific provider:
import { class Synapse
Synapse, type type PieceCID = Link<MerkleTreeNode, RAW_CODE, MulticodecCode<4113, "fr32-sha2-256-trunc254-padded-binary-tree">, 1>
PieceCID } from "@filoz/synapse-sdk"import { function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
privateKeyToAccount } from "viem/accounts"
const const synapse: Synapse
synapse = class Synapse
Synapse.Synapse.create(options: SynapseOptions): Synapse
create({ SynapseOptions.account: `0x${string}` | Account
account: function privateKeyToAccount(privateKey: Hex, options?: PrivateKeyToAccountOptions): PrivateKeyAccount
privateKeyToAccount("0x..."), SynapseOptions.source: string | null
source: "my-app" })const const ctx: StorageContext
ctx = await const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.createContext(options?: StorageServiceOptions): Promise<StorageContext>
createContext({ BaseContextOptions.metadata?: Record<string, string> | undefined
metadata: { source: string
source: "my-app" },})const const pieceCid: PieceLink
pieceCid = null as unknown as type PieceCID = Link<MerkleTreeNode, RAW_CODE, MulticodecCode<4113, "fr32-sha2-256-trunc254-padded-binary-tree">, 1>
PieceCID;// Downloads from the provider associated with this contextconst const data: Uint8Array<ArrayBufferLike>
data = await const ctx: StorageContext
ctx.StorageContext.download(options: DownloadOptions): Promise<Uint8Array>
download({ pieceCid: string | PieceLink
pieceCid })CDN Option Inheritance
Section titled “CDN Option Inheritance”The withCDN option follows a clear inheritance hierarchy:
- Synapse level: Default setting for all operations
- StorageContext level: Can override Synapse’s default
- Method level: Can override instance settings
await const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.download(options: StorageManagerDownloadOptions): Promise<Uint8Array>
download({ pieceCid: string | PieceLink
pieceCid }) // Uses Synapse's withCDN: trueawait const ctx: StorageContext
ctx.StorageContext.download(options: DownloadOptions): Promise<Uint8Array>
download({ pieceCid: string | PieceLink
pieceCid }) // Uses context's withCDN: falseawait const synapse: Synapse
synapse.Synapse.storage: StorageManager
storage.StorageManager.download(options: StorageManagerDownloadOptions): Promise<Uint8Array>
download({ pieceCid: string | PieceLink
pieceCid, withCDN?: boolean | undefined
withCDN: false }) // Method override: CDN disabledNote: When withCDN: true is set, it adds { withCDN: '' } to the data set’s metadata, ensuring CDN-enabled and non-CDN data sets remain separate.
Next Steps
Section titled “Next Steps”-
Split Operations — Learn how to manually control the store, pull, and commit phases for advanced upload workflows.
-
Storage Operations — The high-level multi-copy upload API for most use cases. Start here if you haven’t used
synapse.storage.upload()yet. -
Calculate Storage Costs — Plan your budget and fund your storage account. Use the quick calculator to estimate monthly costs.
-
Payment Management — Manage deposits, approvals, and payment rails. Required before your first upload.