Advanced Uploading with Turbo
Learn how to upload data to Arweave using the Turbo SDK for a streamlined upload experience with multiple payment options and authentication methods.
What You'll Learn
- How to install and authenticate with the Turbo SDK
- Different authentication methods (Arweave, Ethereum, Solana, etc.)
- How to purchase Turbo Credits
- How to upload files, strings, binary data, and entire folders to Arweave
- Browser and Node.js implementation examples
- Using the versatile
upload
method for all data types
Prerequisites
- Node.js environment or modern web browser
- Wallet for authentication (Arweave, Ethereum, Solana, etc.)
- Basic understanding of JavaScript/TypeScript
Quick Start
Install the Turbo SDK
# For Node.js
npm install @ardrive/turbo-sdk
# For Yarn users
yarn add @ardrive/turbo-sdk
Authenticate with Your Wallet
Choose your preferred authentication method:
import { TurboFactory } from '@ardrive/turbo-sdk'
import fs from 'fs'
// Load your Arweave JWK file
const jwk = JSON.parse(fs.readFileSync('wallet.json', 'utf-8'))
const turbo = await TurboFactory.authenticated({
privateKey: jwk, // ArweaveJWK type
token: 'arweave', // Default token type
})
import { TurboFactory, EthereumSigner } from '@ardrive/turbo-sdk'
// Your Ethereum private key (with 0x prefix)
const privateKey = '0x1234...' // EthPrivateKey type
// Create an Ethereum signer instance
const signer = new EthereumSigner(privateKey)
const turbo = await TurboFactory.authenticated({
signer,
token: 'ethereum',
})
import { TurboFactory } from '@ardrive/turbo-sdk'
import bs58 from 'bs58'
// Your Solana secret key (as Uint8Array)
const secretKey = new Uint8Array([...]) // SolSecretKey type
const turbo = await TurboFactory.authenticated({
privateKey: bs58.encode(secretKey),
token: 'solana'
})
import { TurboFactory, EthereumSigner } from '@ardrive/turbo-sdk'
// Your Polygon private key (with 0x prefix)
const privateKey = '0x1234...' // EthPrivateKey type
// Create an Ethereum signer instance for Polygon
const signer = new EthereumSigner(privateKey)
const turbo = await TurboFactory.authenticated({
signer,
token: 'matic', // or 'pol'
})
import { TurboFactory } from '@ardrive/turbo-sdk'
// Your KYVE private key (hexadecimal)
const privateKey = '0x1234...' // KyvePrivateKey type
const turbo = await TurboFactory.authenticated({
privateKey,
token: 'kyve',
})
import { TurboFactory, ArConnectSigner } from '@ardrive/turbo-sdk/web'
async function initializeTurbo() {
await window.arweaveWallet.connect([
'ACCESS_ADDRESS',
'ACCESS_PUBLIC_KEY',
'SIGN_TRANSACTIONS',
'SIGN_MESSAGE',
'SIGNATURE',
])
const turbo = await TurboFactory.authenticated({
signer: new ArConnectSigner(window.arweaveWallet),
})
}
import { TurboFactory } from '@ardrive/turbo-sdk/web'
import { InjectedEthereumSigner } from '@dha-team/arbundles'
import { getAccount, signMessage } from 'wagmi/actions'
import { hashMessage, recoverPublicKey, toBytes } from 'viem'
// Global variables for Wagmi config and connector
let config = null
let connector = null
let turboInstance = null
// Function to set up Wagmi configuration
export function setWagmiConfig(wagmiConfig, wagmiConnector) {
config = wagmiConfig
connector = wagmiConnector
}
// Function to initialize Turbo with Wagmi
export async function initializeTurbo(userAddress) {
try {
if (!config || !connector) {
throw new Error(
'Wagmi config and connector not set. Call setWagmiConfig first.',
)
}
console.log('Initializing Turbo client...')
// Create a provider that uses wagmi's signMessage
const provider = {
getSigner: () => ({
signMessage: async (message) => {
const arg = message instanceof String ? message : { raw: message }
const ethAccount = getAccount(config)
return await signMessage(config, {
message: arg,
account: ethAccount.address,
connector: connector,
})
},
}),
}
// Create the Turbo signer
const signer = new InjectedEthereumSigner(provider)
// Set up the public key
signer.setPublicKey = async () => {
const message = 'Sign this message to connect to Turbo'
const ethAccount = getAccount(config)
const signature = await signMessage(config, {
message: message,
account: ethAccount.address,
connector: connector,
})
const hash = await hashMessage(message)
const recoveredKey = await recoverPublicKey({
hash,
signature,
})
signer.publicKey = Buffer.from(toBytes(recoveredKey))
}
// Initialize the signer
await signer.setPublicKey()
turboInstance = await TurboFactory.authenticated({
signer: signer,
token: 'base-eth', // Can be changed to 'ethereum' or 'matic', etc.
})
console.log('Turbo client initialized successfully')
return turboInstance
} catch (error) {
console.error('Error initializing Turbo client:', error)
turboInstance = null
throw error
}
}
import { BrowserProvider } from 'ethers'
import { TurboFactory } from '@ardrive/turbo-sdk/web'
import { InjectedEthereumSigner } from '@dha-team/arbundles'
export const connectToMetaMask = async () => {
if (!window.ethereum) {
throw new Error('Please install MetaMask to use this application')
}
try {
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts',
})
const metaMaskProvider = window.ethereum.providers?.find(
(p) => p.isMetaMask,
)
const provider = new BrowserProvider(metaMaskProvider ?? window.ethereum)
const signer = await provider.getSigner()
const turbo = TurboFactory.authenticated({
signer: new InjectedEthereumSigner({ getSigner: () => signer }),
token: 'ethereum',
})
return { turbo, address: accounts[0] }
} catch (error) {
console.error('Connection failed:', error)
throw error
}
}
import { TurboFactory, SolanaWalletAdapter } from '@ardrive/turbo-sdk/web'
import { PublicKey } from '@solana/web3.js'
export async function initializeSolanaTurbo() {
try {
// Check if Phantom is installed
if (window.solana) {
const provider = window.solana
const publicKey = new PublicKey((await provider.connect()).publicKey)
const wallet: SolanaWalletAdapter = {
publicKey,
signMessage: async (message: Uint8Array) => {
// Call Phantom's signMessage method
const { signature } = await provider.signMessage(message)
return signature
},
}
solanaTurboInstance = TurboFactory.authenticated({
token: 'solana',
walletAdapter: wallet,
})
}
} catch (err) {
console.error(err)
}
}
Purchase Turbo Credits
Turbo Credits are the payment medium used by the Turbo Upload Service. Each Credit represents a 1:1 conversion from the upload power of the Arweave native token (AR).
- Fiat Currency: Credit/debit cards via the Turbo Top Up App
- Cryptocurrencies: AR, ETH, SOL, MATIC, ARIO, USDC, KYVE, ETH (BASE)
- Multiple Wallets: Ethereum, Solana, and Arweave wallets supported
import { TurboFactory, WinstonToTokenAmount } from '@ardrive/turbo-sdk'
// Initialize authenticated client
const turbo = await TurboFactory.authenticated({
privateKey: jwk
})
// Top up with AR tokens
const topUpResult = await turbo.topUpWithTokens({
tokenAmount: WinstonToTokenAmount(100_000_000), // 0.0001 AR
})
import { TurboFactory, EthereumSigner } from '@ardrive/turbo-sdk'
// Initialize authenticated client
const turbo = await TurboFactory.authenticated({
signer: new EthereumSigner(privateKey),
token: 'ethereum',
})
// Top up with ETH tokens
const topUpResult = await turbo.topUpWithTokens({
tokenAmount: 0.001, // 0.001 ETH
})
import { TurboFactory } from '@ardrive/turbo-sdk'
// Initialize authenticated client
const turbo = await TurboFactory.authenticated({
privateKey: bs58.encode(secretKey),
token: 'solana'
})
// Top up with SOL tokens
const topUpResult = await turbo.topUpWithTokens({
tokenAmount: 0.1, // 0.1 SOL
})
import { TurboFactory, EthereumSigner } from '@ardrive/turbo-sdk'
// Initialize authenticated client
const turbo = await TurboFactory.authenticated({
signer: new EthereumSigner(privateKey),
token: 'matic',
})
// Top up with MATIC tokens
const topUpResult = await turbo.topUpWithTokens({
tokenAmount: 1.0, // 1.0 MATIC
})
import { TurboFactory } from '@ardrive/turbo-sdk'
// Initialize authenticated client
const turbo = await TurboFactory.authenticated({
privateKey,
token: 'kyve',
})
// Top up with KYVE tokens
const topUpResult = await turbo.topUpWithTokens({
tokenAmount: 100, // 100 KYVE
})
Upload Your First File
// Upload a single file using the versatile upload method
const result = await turbo.upload({
data: file, // Can be File, Blob, Buffer, Uint8Array, ArrayBuffer, or string
dataItemOpts: {
tags: [
{ name: "Content-Type", value: file.type || "application/octet-stream" },
{ name: "App-Name", value: "MyApp-v1.0" },
],
},
});
console.log("File uploaded!", {
id: result.id,
url: `https://arweave.net/${result.id}`,
owner: result.owner,
dataCaches: result.dataCaches,
});
Uploading Files
Basic File Upload
// Upload a single file using the versatile upload method
const result = await turbo.upload({
data: file, // Can be File, Blob, Buffer, Uint8Array, ArrayBuffer, or string
dataItemOpts: {
tags: [
{ name: "Content-Type", value: file.type || "application/octet-stream" },
{ name: "App-Name", value: "MyApp-v1.0" },
],
},
});
console.log("File uploaded!", {
id: result.id,
url: `https://arweave.net/${result.id}`,
owner: result.owner,
dataCaches: result.dataCaches,
});
Upload with Custom Tags
const result = await turbo.upload({
data: file,
dataItemOpts: {
tags: [
{ name: "Content-Type", value: "application/json" },
{ name: "App-Name", value: "MyApp-v1.0" },
{ name: "App-Version", value: "1.0.0" },
{ name: "Description", value: "My application data" },
],
},
});
Upload Strings
// Upload a string
const stringResult = await turbo.upload({
data: "Hello, Arweave!",
dataItemOpts: {
tags: [
{ name: "Content-Type", value: "text/plain" },
{ name: "App-Name", value: "MyApp-v1.0" },
],
},
});
Upload JSON Data
// Upload a JSON object
const jsonData = { message: "Hello", timestamp: Date.now() };
const jsonResult = await turbo.upload({
data: JSON.stringify(jsonData),
dataItemOpts: {
tags: [
{ name: "Content-Type", value: "application/json" },
{ name: "App-Name", value: "MyApp-v1.0" },
],
},
});
Upload Binary Data
// Upload binary data
const binaryData = new Uint8Array([1, 2, 3, 4, 5]);
const binaryResult = await turbo.upload({
data: binaryData,
dataItemOpts: {
tags: [
{ name: "Content-Type", value: "application/octet-stream" },
{ name: "App-Name", value: "MyApp-v1.0" },
],
},
});
Upload Multiple Files
const files = [file1, file2, file3];
const uploadPromises = files.map((file) =>
turbo.upload({
data: file,
dataItemOpts: {
tags: [
{
name: "Content-Type",
value: file.type || "application/octet-stream",
},
{ name: "App-Name", value: "MyApp-v1.0" },
],
},
})
);
const results = await Promise.all(uploadPromises);
console.log("All files uploaded!", results);
Upload an Entire Folder (Node.js)
const folderResult = await turbo.uploadFolder({
folderPath: "./my-website",
dataItemOpts: {
tags: [
{ name: "App-Name", value: "MyWebsite-v1.0" },
{ name: "Content-Type", value: "application/x.arweave-manifest+json" },
],
},
manifestOptions: {
indexFile: "index.html",
fallbackFile: "404.html",
},
});
console.log("Folder uploaded!", {
manifestId: folderResult.manifestResponse?.id,
fileCount: folderResult.fileResponses.length,
manifest: folderResult.manifest,
});
Upload Multiple Files as a Folder (Browser)
const files = [file1, file2, file3];
const webFolderResult = await turbo.uploadFolder({
files: files,
dataItemOpts: {
tags: [{ name: "App-Name", value: "MyWebsite-v1.0" }],
},
manifestOptions: {
indexFile: "index.html",
},
});
Browser Implementation Examples
File Input with Drag & Drop
<!DOCTYPE html>
<html>
<head>
<title>Turbo Upload Example</title>
<style>
.drop-zone {
border: 2px dashed #ccc;
border-radius: 10px;
padding: 20px;
text-align: center;
margin: 20px 0;
}
.drag-over {
border-color: #007bff;
background-color: #f8f9fa;
}
</style>
</head>
<body>
<input type="file" id="file-input" multiple />
<div class="drop-zone" id="drop-zone">
<p>Drag and drop files here or click to select</p>
</div>
<script type="module">
// Your Turbo initialization code here
// ... (authentication code from above)
const fileInput = document.getElementById("file-input");
const dropZone = document.getElementById("drop-zone");
// File input handler
fileInput.addEventListener("change", async (event) => {
const files = Array.from(event.target.files);
for (const file of files) {
await uploadFile(file);
}
});
// Drag and drop handlers
dropZone.addEventListener("dragover", (e) => {
e.preventDefault();
e.stopPropagation();
dropZone.classList.add("drag-over");
});
dropZone.addEventListener("dragleave", (e) => {
e.preventDefault();
e.stopPropagation();
dropZone.classList.remove("drag-over");
});
dropZone.addEventListener("drop", async (e) => {
e.preventDefault();
e.stopPropagation();
dropZone.classList.remove("drag-over");
const files = Array.from(e.dataTransfer.files);
for (const file of files) {
await uploadFile(file);
}
});
async function uploadFile(file) {
try {
const result = await turbo.upload({
data: file,
dataItemOpts: {
tags: [
{
name: "Content-Type",
value: file.type || "application/octet-stream",
},
{ name: "App-Name", value: "MyApp-v1.0" },
],
},
});
console.log("File uploaded!", {
id: result.id,
url: `https://arweave.net/${result.id}`,
name: file.name,
size: file.size,
});
} catch (error) {
console.error("Upload failed:", error);
}
}
</script>
</body>
</html>
Advanced Features
Check Upload Costs
// Get upload cost for specific file size
const costs = await turbo.getUploadCosts({
bytes: [file.size],
});
console.log(`Upload cost: ${costs[0].winc} Winston Credits`);
console.log(`USD cost: $${costs[0].usd}`);
Check Balance
// Get current balance
const balance = await turbo.getBalance();
console.log(`Available credits: ${balance.controlledWinc} Winston Credits`);
Upload with Progress Tracking
const result = await turbo.upload({
data: file,
dataItemOpts: {
tags: [
{ name: "Content-Type", value: file.type || "application/octet-stream" },
{ name: "App-Name", value: "MyApp-v1.0" },
],
},
events: {
onUploadProgress: (progress) => {
console.log(
`Upload progress: ${Math.round((progress.processedBytes / progress.totalBytes) * 100)}%`
);
},
onSigningProgress: (progress) => {
console.log(
`Signing progress: ${Math.round((progress.processedBytes / progress.totalBytes) * 100)}%`
);
},
},
});
Upload with Error Handling
try {
const result = await turbo.upload({
data: file,
dataItemOpts: {
tags: [
{ name: "Content-Type", value: file.type || "application/octet-stream" },
{ name: "App-Name", value: "MyApp-v1.0" },
],
},
events: {
onUploadError: (error) => {
console.error("Upload failed:", error);
},
onSigningError: (error) => {
console.error("Signing failed:", error);
},
},
});
console.log("Upload successful:", result);
} catch (error) {
console.error("Upload error:", error);
// Handle error appropriately
}
Benefits of Using Turbo
- Versatile upload method - Upload files, strings, binary data, or entire folders with a single method
- Multiple payment options - Pay with fiat, crypto, or AR tokens
- Easy integration - Simple SDK for both Node.js and browsers
- Automatic retry - Built-in retry logic for failed uploads
- Cost transparency - See upload costs before confirming
- Fast uploads - Optimized for speed and reliability
- Folder support - Upload entire directories with automatic manifest generation
Ready to Upload?
Purchase Credits
Buy Turbo Credits with fiat or crypto
Learn About Tagging
Discover best practices for organizing your data
Create Manifests
Learn how to organize files with manifests
How is this guide?