SiaSia Developer Portal

Upload an Object

Uploading data is the core action your app will perform on the Sia network. When you upload a file through the SDK, the process is made secure by design:

  • All data is encrypted client-side before it leaves the device.
  • Data is erasure-coded into multiple redundant shards.
  • Each shard is uploaded to independent storage providers located across the globe.
  • The indexer stores encrypted object records and coordinates uploads, downloads, and object management. It never sees plaintext data.

Encryption keeps data private even if intercepted. Erasure coding keeps it recoverable even if some hosts go offline.

Prerequisites

Before continuing, make sure you have:

  • An App Key returned from a successful connection to an indexer.

Once you have established a successful connection, you’re ready to upload your first object.

Example

rust
use sia_storage::{app_id, AppKey, AppMetadata, Builder, Object, UploadOptions}; use std::io::{self, Write}; const INDEXER_URL: &str = "https://sia.storage"; const APP_META: AppMetadata = AppMetadata { // Replace `app_id` with your real 32-byte App ID (hex-encoded, 64 chars). // Generate this ONCE and keep it stable forever for your app. id: app_id!("0000000000000000000000000000000000000000000000000000000000000000"), name: "My App", description: "Demo application", service_url: "https://example.com", logo_url: None, callback_url: None, }; #[tokio::main(flavor = "multi_thread")] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Create a builder that can reconnect using an existing App Key let builder = Builder::new(INDEXER_URL, APP_META)?; // Ask the user for their App Key print!("Enter your App Key (hex): "); io::stdout().flush()?; let mut app_key_hex = String::new(); io::stdin().read_line(&mut app_key_hex)?; let app_key_hex = app_key_hex.trim(); let mut seed = [0u8; 32]; hex::decode_to_slice(app_key_hex, &mut seed)?; let app_key = AppKey::import(seed); // Reconnect using the App Key let sdk = match builder.connected(&app_key).await? { Some(sdk) => sdk, None => { return Err(io::Error::new( io::ErrorKind::PermissionDenied, "invalid App Key", ) .into()) } }; println!("\nApp Connected!"); // Upload "Hello world!" from an in-memory reader let reader = std::io::Cursor::new(b"Hello world!"); println!("\nStarting upload..."); let obj = Object::default(); let obj = sdk.upload(obj, reader, UploadOptions::default()).await?; // Pin the object — without this, the upload is not persisted sdk.pin_object(&obj).await?; println!("\nUpload complete:"); println!(" - Size: {} bytes", obj.size()); println!(" - Object ID: {}", obj.id()); Ok(()) }

Deep Dive

Objects & Metadata

Uploading returns an object handle you can work with immediately (for example, to pin it, share it, or download it later).

In this quickstart flow, upload and pin are separate steps:

  • Upload sends shards to storage providers and builds the object’s layout.
  • Pinning persists the sealed object record in the indexer and pins the underlying slabs so the object becomes listable, syncable, and eligible for repair.

The Object ID comes from the object’s slab layout, so you can read it directly after upload. Pinning encrypts and signs the object (a process called sealing) before sending it to the indexer — you don’t need to seal manually. See Pinning and Objects for more.

Metadata is application-defined and encrypted. See the Object Metadata recipe for details.