Skip to content

Storage Costs

Understanding storage costs helps you budget effectively and avoid service interruptions. This guide explains how to calculate costs and fund your account for Filecoin storage.

Storage operates on a pay-per-epoch model where you deposit USDFC tokens and set allowances that control how much the storage service can spend.

ComponentCostNotes
Storage$2.50/TiB/monthMinimum $0.06/month per data set (~24.567 GiB threshold)
Sybil Fee0.1 USDFC (one-time)Per new data set creation; prevents state-growth spam
CDN Egress$14/TiB downloaded1 USDFC top-up ≈ 71.5 GiB of downloads
CDN Setup1 USDFC (one-time)Per data set; reusing existing data sets incurs no cost

Pricing Logic:

  • Storage < 24.567 GiB: Minimum $0.06/month applies
  • Storage ≥ 24.567 GiB: Actual cost (bytes / TiB) × $2.50/month
  • CDN data sets require 1 USDFC setup on first creation only
  • CDN egress credits can be topped up anytime

Example 1: NFT Collection (10,000 × 5 KiB ≈ 48.82 MiB)

Section titled “Example 1: NFT Collection (10,000 × 5 KiB ≈ 48.82 MiB)”
// 48.82 MiB less than 24.567 GiB threshold
// Price is $0.06/month
const
const PRICE_PER_MONTH: 0.06
PRICE_PER_MONTH
= 0.06;
const
const months: 24
months
= 24;
const
const PRICE_FOR_24_MONTHS: number
PRICE_FOR_24_MONTHS
=
const PRICE_PER_MONTH: 0.06
PRICE_PER_MONTH
* 24; // 1.44 USDFC
DurationTotal Cost
1 month0.06 USDFC
24 months1.44 USDFC

  • Storage: 1,000 users × 100 MiB ≈ 100,000 MiB
  • Traffic: 1,000 users × 100 MiB/month ≈ 100,000 MiB/month egress
const
const STORAGE_PRICE_PER_TIB_PER_MONTH: 2.5
STORAGE_PRICE_PER_TIB_PER_MONTH
= 2.5; // $2.50/TiB/month
const
const CDN_EGRESS_PRICE_PER_TIB: 14
CDN_EGRESS_PRICE_PER_TIB
= 14; // $14/TiB downloaded
const
const storageMiB: 100000
storageMiB
= 100_000;
const
const egressMiB: 100000
egressMiB
= 100_000;
// Storage: 100,000 MiB ≈ 0.0953 TiB
const
const storageTiB: number
storageTiB
=
const storageMiB: 100000
storageMiB
/ 1024 / 1024;
// Egress: 100,000 MiB ≈ 0.0953 TiB
const
const egressTiB: number
egressTiB
=
const egressMiB: 100000
egressMiB
/ 1024 / 1024;
// Storage cost per month: 0.0953 TiB × $2.50 ≈ $0.238/month
const
const storageCostPerMonth: number
storageCostPerMonth
=
const storageTiB: number
storageTiB
*
const STORAGE_PRICE_PER_TIB_PER_MONTH: 2.5
STORAGE_PRICE_PER_TIB_PER_MONTH
;
// Egress cost per month: 0.0953 TiB × $14 ≈ $1.334/month
const
const egressCostPerMonth: number
egressCostPerMonth
=
const egressTiB: number
egressTiB
*
const CDN_EGRESS_PRICE_PER_TIB: 14
CDN_EGRESS_PRICE_PER_TIB
;
// Total cost per month: $0.238/month + $1.334/month ≈ $1.572/month
const
const totalCostPerMonth: number
totalCostPerMonth
=
const storageCostPerMonth: number
storageCostPerMonth
+
const egressCostPerMonth: number
egressCostPerMonth
;
// Total cost for 24 months: $1.572/month × 24 ≈ $37.728
const
const totalCostFor24Months: number
totalCostFor24Months
=
const totalCostPerMonth: number
totalCostPerMonth
* 24;
Cost ComponentPer Month24 Months
Storage≈ 0.238 USDFC≈ 5.71 USDFC
CDN Egress≈ 1.334 USDFC≈ 32.016 USDFC
Total≈ 1.572 USDFC≈ 37.728 USDFC

Before uploading, the WarmStorage operator must be approved and your account must be funded. FWSS requires a 30-day prepayment buffer — when your balance drops below 30 days, the provider may remove your data.

The SDK’s prepare() method handles all of this automatically. It computes the exact deposit needed, checks whether the FWSS operator is approved, and returns a single transaction that handles both.


Use getUploadCosts() to preview costs without executing any transaction. This is useful for displaying pricing in a UI or letting users confirm before proceeding.

const
const costs: getUploadCosts.OutputType
costs
= await
const synapse: Synapse
synapse
.
Synapse.storage: StorageManager
storage
.
StorageManager.getUploadCosts(options: Omit<GetUploadCostsOptions, "clientAddress">): Promise<UploadCosts>
getUploadCosts
({
dataSize: bigint
dataSize
: 1073741824n, // 1 GiB in bytes
})

The returned UploadCosts object contains:

FieldTypeDescription
rate.perEpochbigintStorage rate per epoch (30 seconds)
rate.perMonthbigintStorage rate per month (for display)
depositNeededbigintUSDFC to deposit (0n if sufficient funds)
needsFwssMaxApprovalbooleanWhether FWSS operator approval is needed
readybooleantrue when no deposit or approval is needed

Use prepare() to compute costs and get a ready-to-execute transaction. This is the recommended approach for most use cases — it replaces the previous manual flow of calculating allowances, checking approvals, and branching between deposit/approve methods.

// Compute costs and get a transaction (if needed)
const
const prep: PrepareResult
prep
= await
const synapse: Synapse
synapse
.
Synapse.storage: StorageManager
storage
.
StorageManager.prepare(options: PrepareOptions): Promise<PrepareResult>
prepare
({
PrepareOptions.dataSize: bigint
dataSize
: 1073741824n, // 1 GiB
})
// Inspect costs
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Rate per month:",
function formatUnits(value: bigint, options?: FormatUnitsOptions): string
formatUnits
(
const prep: PrepareResult
prep
.
PrepareResult.costs: getUploadCosts.OutputType
costs
.
rate: {
perEpoch: bigint;
perMonth: bigint;
}
rate
.
perMonth: bigint
perMonth
))
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Deposit needed:",
function formatUnits(value: bigint, options?: FormatUnitsOptions): string
formatUnits
(
const prep: PrepareResult
prep
.
PrepareResult.costs: getUploadCosts.OutputType
costs
.
depositNeeded: bigint
depositNeeded
))
// Execute if the account isn't ready
if (
const prep: PrepareResult
prep
.
PrepareResult.transaction: {
depositAmount: bigint;
includesApproval: boolean;
execute: (options?: {
onHash?: (hash: Hash) => void;
}) => Promise<{
hash: Hash;
receipt: TransactionReceipt<bigint, number, "success" | "reverted", TransactionType> | null;
}>;
} | null
transaction
) {
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Deposit amount:",
function formatUnits(value: bigint, options?: FormatUnitsOptions): string
formatUnits
(
const prep: PrepareResult
prep
.
PrepareResult.transaction: {
depositAmount: bigint;
includesApproval: boolean;
execute: (options?: {
onHash?: (hash: Hash) => void;
}) => Promise<{
hash: Hash;
receipt: TransactionReceipt<bigint, number, "success" | "reverted", TransactionType> | null;
}>;
}
transaction
.
depositAmount: bigint
depositAmount
))
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Includes approval:",
const prep: PrepareResult
prep
.
PrepareResult.transaction: {
depositAmount: bigint;
includesApproval: boolean;
execute: (options?: {
onHash?: (hash: Hash) => void;
}) => Promise<{
hash: Hash;
receipt: TransactionReceipt<bigint, number, "success" | "reverted", TransactionType> | null;
}>;
}
transaction
.
includesApproval: boolean
includesApproval
)
const {
const hash: `0x${string}`
hash
} = await
const prep: PrepareResult
prep
.
PrepareResult.transaction: {
depositAmount: bigint;
includesApproval: boolean;
execute: (options?: {
onHash?: (hash: Hash) => void;
}) => Promise<{
hash: Hash;
receipt: TransactionReceipt<bigint, number, "success" | "reverted", TransactionType> | null;
}>;
}
transaction
.
execute: (options?: {
onHash?: (hash: Hash) => void;
}) => Promise<{
hash: Hash;
receipt: TransactionReceipt<bigint, number, "success" | "reverted", TransactionType> | null;
}>
execute
()
var console: Console
console
.
Console.log(...data: any[]): void

The console.log() static method outputs a message to the console.

MDN Reference

log
("Transaction confirmed:",
const hash: `0x${string}`
hash
)
}
// Now safe to upload

prepare() returns:

  • costs: The full UploadCosts breakdown
  • transaction: A transaction object with execute(), or null if the account is already ready

The transaction automatically picks the right contract call:

  • Needs deposit + approval: calls depositWithPermitAndApproveOperator
  • Needs approval only: calls approveService
  • Needs deposit only: calls depositWithPermit
  • Already ready: returns transaction: null