Skip to content

Upload Files to Arweave

For Feria Nounish Artists: This documentation is inspired by Gabriel Lago from Cali, Colombia, who is building a Feria Nounish MiniApp for the artists participating in this year's fair. The clientUploadToArweave function enables artists to upload their artwork and metadata to decentralized storage, creating permanent, onchain records of their contributions to the collective timeline.

Upload files to Arweave decentralized storage for use in your NFT collections and moments. This function is perfect for artists participating in events like Feria Nounish who need to store metadata and assets onchain.

Note: This function uploads files to Arweave and returns a URI that can be used in collection creation or moment creation.

Installation

First, install the required Arweave package:

npm install arweave

Function Implementation

import Arweave from "arweave";
 
const arweave = Arweave.init({
  host: "arweave.net",
  port: 443,
  protocol: "https",
  timeout: 20000,
  logging: false,
});
 
const clientUploadToArweave = async (
  file: File,
  getProgress: (progress: number) => void = () => {}
): Promise<string> => {
  const ARWEAVE_KEY = JSON.parse(
    Buffer.from(
      process.env.NEXT_PUBLIC_ARWEAVE_KEY as string,
      "base64"
    ).toString()
  );
  const buffer = await file.arrayBuffer();
 
  const transaction = await arweave.createTransaction(
    {
      data: buffer,
    },
    ARWEAVE_KEY
  );
  transaction.addTag("Content-Type", file.type);
  await arweave.transactions.sign(transaction, ARWEAVE_KEY);
  const uploader = await arweave.transactions.getUploader(transaction);
 
  while (!uploader.isComplete) {
    console.log(
      `${uploader.pctComplete}% complete, ${uploader.uploadedChunks}/${uploader.totalChunks}`
    );
    getProgress(uploader.pctComplete);
    await uploader.uploadChunk();
  }
 
  return `ar://${transaction.id}`;
};
 
export default clientUploadToArweave;

Parameters

ParameterTypeRequiredDescription
fileFileYesThe file to upload to Arweave
getProgress(progress: number) => voidNoOptional callback function to track upload progress (0-100)

Return Value

Returns a Promise that resolves to a string containing the Arweave URI in the format: ar://{transaction_id}

Environment Setup

You'll need to set up your Arweave wallet key as an environment variable:

# Your Arweave wallet key (base64 encoded)
NEXT_PUBLIC_ARWEAVE_KEY=your_base64_encoded_arweave_key_here

Usage Examples

Basic Upload

import clientUploadToArweave from "./clientUploadToArweave";
 
// Upload a file
const file = document.getElementById("fileInput").files[0];
const arweaveUri = await clientUploadToArweave(file);
console.log("File uploaded to:", arweaveUri);
// Output: ar://abc123...

Upload with Progress Tracking

import clientUploadToArweave from "./clientUploadToArweave";
 
const file = document.getElementById("fileInput").files[0];
 
// Track upload progress
const handleProgress = (progress: number) => {
  console.log(`Upload progress: ${progress}%`);
  // Update your UI progress bar
  document.getElementById("progressBar").style.width = `${progress}%`;
};
 
try {
  const arweaveUri = await clientUploadToArweave(file, handleProgress);
  console.log("Upload complete:", arweaveUri);
} catch (error) {
  console.error("Upload failed:", error);
}

Upload for Collection Metadata

import clientUploadToArweave from "./clientUploadToArweave";
 
// Upload collection metadata JSON
const metadata = {
  name: "Feria Nounish Collection",
  description: "Artwork from the Feria Nounish fair",
  image: "https://example.com/collection-image.jpg",
  external_link: "https://ferianounish.com",
};
 
// Convert metadata to file
const metadataBlob = new Blob([JSON.stringify(metadata, null, 2)], {
  type: "application/json",
});
const metadataFile = new File([metadataBlob], "metadata.json", {
  type: "application/json",
});
 
// Upload to Arweave
const contractUri = await clientUploadToArweave(metadataFile);
console.log("Contract URI:", contractUri);
// Use this URI in your collection creation

Upload for Moment Content

import clientUploadToArweave from "./clientUploadToArweave";
 
// Upload moment content (text, image, etc.)
const momentContent = {
  title: "My Feria Moment",
  content: "This is my contribution to the collective timeline",
  media: "https://example.com/my-artwork.jpg",
  timestamp: new Date().toISOString(),
};
 
const contentBlob = new Blob([JSON.stringify(momentContent, null, 2)], {
  type: "application/json",
});
const contentFile = new File([contentBlob], "moment.json", {
  type: "application/json",
});
 
const momentUri = await clientUploadToArweave(contentFile);
console.log("Moment URI:", momentUri);
// Use this URI when creating your moment

React Hook Example

For React applications, here's a custom hook for file uploads:

import { useState } from "react";
import clientUploadToArweave from "./clientUploadToArweave";
 
export const useArweaveUpload = () => {
  const [isUploading, setIsUploading] = useState(false);
  const [progress, setProgress] = useState(0);
  const [error, setError] = useState<string | null>(null);
 
  const uploadFile = async (file: File): Promise<string> => {
    setIsUploading(true);
    setProgress(0);
    setError(null);
 
    try {
      const uri = await clientUploadToArweave(file, setProgress);
      setIsUploading(false);
      return uri;
    } catch (err) {
      setError(err instanceof Error ? err.message : "Upload failed");
      setIsUploading(false);
      throw err;
    }
  };
 
  return {
    uploadFile,
    isUploading,
    progress,
    error,
  };
};
 
// Usage in component
const MyComponent = () => {
  const { uploadFile, isUploading, progress, error } = useArweaveUpload();
 
  const handleFileUpload = async (
    event: React.ChangeEvent<HTMLInputElement>
  ) => {
    const file = event.target.files?.[0];
    if (file) {
      try {
        const uri = await uploadFile(file);
        console.log("Uploaded to:", uri);
      } catch (err) {
        console.error("Upload failed:", err);
      }
    }
  };
 
  return (
    <div>
      <input type="file" onChange={handleFileUpload} />
      {isUploading && (
        <div>
          <p>Uploading... {progress}%</p>
          <progress value={progress} max={100} />
        </div>
      )}
      {error && <p style={{ color: "red" }}>Error: {error}</p>}
    </div>
  );
};

File Types Supported

The function supports any file type that can be stored on Arweave:

  • Images: PNG, JPEG, GIF, SVG, WebP
  • Documents: PDF, TXT, MD
  • Data: JSON, CSV, XML
  • Media: MP4, MP3, WebM
  • Archives: ZIP, TAR

Best Practices

  1. File Size: Arweave has no strict size limits, but larger files take longer to upload and cost more AR tokens.

  2. Content-Type Tagging: The function automatically tags files with their MIME type for proper handling.

  3. Progress Tracking: Always implement progress tracking for better user experience, especially for larger files.

  4. Error Handling: Wrap upload calls in try-catch blocks to handle network issues or insufficient AR tokens.

  5. Metadata Structure: When uploading JSON metadata, follow standard NFT metadata schemas for compatibility with marketplaces.

Integration with Collection Creation

After uploading your metadata to Arweave, use the returned URI in your collection creation:

// Upload collection metadata
const contractUri = await clientUploadToArweave(metadataFile);
 
// Use in collection creation
const createContractData = encodeFunctionData({
  abi: tokenAbi,
  functionName: "createContract",
  args: [
    contractUri, // Use the Arweave URI here
    collectionName,
    royaltyConfig,
    smartAccount.address,
    [],
  ],
});

Error Handling

Common errors and solutions:

  • Insufficient AR tokens: Ensure your Arweave wallet has enough AR tokens for the upload
  • Invalid wallet key: Verify your NEXT_PUBLIC_ARWEAVE_KEY is correctly base64 encoded
  • Network timeout: Increase the timeout value in the Arweave configuration
  • File too large: Consider compressing or optimizing your files before upload

Next Steps

After uploading files to Arweave: