How to Use Thirdweb SDK Workflow (2026)
Claude Code for Thirdweb SDK Workflow Tutorial
Thirdweb simplifies blockchain development by providing powerful SDKs that abstract away the complexity of smart contract interactions. When combined with Claude Code, you can create efficient workflows for deploying contracts, managing NFTs, and interacting with blockchain applications. This tutorial shows you how to use Claude Code to accelerate your Thirdweb development across the entire lifecycle, from initial project setup through production monitoring.
Setting Up Your Thirdweb Project
Before integrating with Claude Code, ensure you have a Thirdweb project initialized. The SDK supports multiple chains including Ethereum, Polygon, Arbitrum, Base, Avalanche, and BNB Chain, giving you flexibility to target any major ecosystem.
Initialize your project with the Thirdweb CLI:
npx thirdweb create my-nft-project
cd my-nft-project
The CLI will prompt you to choose a template. For NFT projects, select the ERC-721 or ERC-1155 template. For token projects, choose the ERC-20 template. For marketplace applications, select the marketplace template.
Configure your environment variables in a .env file:
THIRDWEB_SECRET_KEY=your_secret_key_here
PRIVATE_KEY=your_wallet_private_key
NEXT_PUBLIC_THIRDWEB_CLIENT_ID=your_client_id_here
The THIRDWEB_SECRET_KEY is used server-side only and must never be exposed to clients. The NEXT_PUBLIC_THIRDWEB_CLIENT_ID is safe to use in browser environments.
Claude Code can help you audit these configurations. A useful prompt is: “Review my environment variable setup and flag any keys that is accidentally exposed to the client bundle.”
Installing SDK Dependencies
Install the core SDK packages depending on your use case:
Core SDK (server-side and Node.js scripts)
npm install @thirdweb-dev/sdk ethers
React hooks for frontend applications
npm install @thirdweb-dev/react @thirdweb-dev/sdk ethers
Wallet connection support
npm install @thirdweb-dev/wallets
Claude Code can generate the appropriate package.json additions automatically. Just describe your project type and intended chains, and Claude will output the correct dependency list.
Connecting to Blockchain Networks
The Thirdweb SDK provides a unified interface for connecting to different blockchain networks. Here’s how to set up your client with proper TypeScript typing:
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
import { Ethereum, Polygon, Arbitrum, Base } from "@thirdweb-dev/chains";
// Initialize SDK for Polygon mainnet
const sdk = new ThirdwebSDK("polygon", {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
// Or use the chain object for more control
const sdkWithChain = new ThirdwebSDK(Polygon, {
secretKey: process.env.THIRDWEB_SECRET_KEY,
alchemyApiKey: process.env.ALCHEMY_API_KEY, // optional, for better RPC
});
For multi-chain applications, a factory pattern helps keep things organized:
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
import { ChainId } from "@thirdweb-dev/sdk";
type SupportedChain = "ethereum" | "polygon" | "arbitrum" | "base";
const SDK_INSTANCES: Partial<Record<SupportedChain, ThirdwebSDK>> = {};
export function getSDK(chain: SupportedChain): ThirdwebSDK {
if (!SDK_INSTANCES[chain]) {
SDK_INSTANCES[chain] = new ThirdwebSDK(chain, {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
}
return SDK_INSTANCES[chain]!;
}
Ask Claude Code to generate this factory pattern for your specific chains: “Create a singleton SDK factory that supports Polygon, Arbitrum, and Base with lazy initialization and connection pooling.”
Network Comparison for Thirdweb Projects
| Network | TPS | Avg Gas Fee | Best For |
|---|---|---|---|
| Ethereum | ~15 | $2–$20 | High-value NFTs, DeFi |
| Polygon | ~7000 | <$0.01 | Gaming, mass-market NFTs |
| Arbitrum | ~4500 | $0.05–$0.50 | DeFi, complex contracts |
| Base | ~2000 | <$0.01 | Consumer apps, L2 NFTs |
Deploying Smart Contracts with Claude Code
Thirdweb’s prebuilt contracts cover most use cases, NFTs, tokens, marketplaces, staking, and more. Here’s how to deploy an NFT collection using the SDK:
import { NFTCollection } from "@thirdweb-dev/sdk";
async function deployNFTCollection() {
const sdk = new ThirdwebSDK("polygon", {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
const address = await sdk.deployer.deployNFTCollection({
name: "My NFT Collection",
description: "A sample NFT collection built with Thirdweb",
image: "ipfs://QmYourImageHash",
primary_sale_recipient: process.env.WALLET_ADDRESS!,
seller_fee_basis_points: 500, // 5% royalty
fee_recipient: process.env.WALLET_ADDRESS!,
platform_fee_basis_points: 0,
platform_fee_recipient: process.env.WALLET_ADDRESS!,
});
console.log("Contract deployed at:", address);
return address;
}
Automating Contract Deployment
Claude Code can help you create reusable deployment scripts with solid error handling. Describe your requirements: “Create a TypeScript script that deploys an NFT collection with custom royalty settings, saves the contract address to a deployed-contracts.json config file, and verifies the contract on Polygonscan.”
Claude will generate the appropriate code and typically suggests improvements like:
import * as fs from "fs";
import * as path from "path";
async function deployAndSave() {
const configPath = path.join(process.cwd(), "deployed-contracts.json");
let deployedContracts: Record<string, string> = {};
if (fs.existsSync(configPath)) {
deployedContracts = JSON.parse(fs.readFileSync(configPath, "utf-8"));
}
try {
const address = await deployNFTCollection();
deployedContracts[`nft-collection-${Date.now()}`] = address;
fs.writeFileSync(configPath, JSON.stringify(deployedContracts, null, 2));
console.log("Contract addresses saved to deployed-contracts.json");
} catch (error) {
console.error("Deployment failed:", error);
process.exit(1);
}
}
deployAndSave();
Prebuilt Contract Types
Thirdweb offers multiple prebuilt contract types that you can deploy without writing Solidity:
| Contract Type | Use Case | Deployer Method |
|---|---|---|
| NFTCollection (ERC-721) | Unique digital collectibles | deployNFTCollection |
| Edition (ERC-1155) | Semi-fungible tokens / multiple copies | deployEdition |
| Token (ERC-20) | Fungible tokens / currencies | deployToken |
| Marketplace | Peer-to-peer NFT trading | deployMarketplace |
| NFT Drop | Public minting with claim conditions | deployNFTDrop |
| Multiwrap | Bundle multiple tokens into one | deployMultiwrap |
| Split | Revenue sharing contracts | deploySplit |
Minting NFTs Programmatically
Once your contract is deployed, minting NFTs becomes straightforward. Here’s a typed example with proper error handling:
interface NFTMetadata {
name: string;
description: string;
image: string;
attributes?: Array<{ trait_type: string; value: string | number }>;
}
async function mintNFT(
contractAddress: string,
toAddress: string,
metadata: NFTMetadata
): Promise<string> {
const sdk = new ThirdwebSDK("polygon", {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
const contract = await sdk.getContract(contractAddress);
const tx = await contract.nft.mint.to(toAddress, {
name: metadata.name,
description: metadata.description,
image: metadata.image,
attributes: metadata.attributes,
});
const receipt = tx.receipt;
const tokenId = tx.id;
console.log(`Minted token ${tokenId} in tx ${receipt.transactionHash}`);
return tokenId.toString();
}
Batch Minting Patterns
For larger collections, batch minting dramatically reduces gas costs and transaction overhead:
async function batchMint(
contractAddress: string,
recipients: string[],
metadataList: NFTMetadata[]
): Promise<string[]> {
if (recipients.length !== metadataList.length) {
throw new Error("Recipients and metadata arrays must have the same length");
}
const sdk = new ThirdwebSDK("polygon", {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
const contract = await sdk.getContract(contractAddress);
const mintData = metadataList.map((meta, index) => ({
to: recipients[index],
metadata: meta,
}));
const txResults = await contract.nft.mintBatch(mintData);
return txResults.map((tx) => tx.id.toString());
}
For very large batches (100+ tokens), chunk the operations to avoid RPC timeouts:
async function batchMintChunked(
contractAddress: string,
recipients: string[],
metadataList: NFTMetadata[],
chunkSize = 50
): Promise<string[]> {
const allTokenIds: string[] = [];
for (let i = 0; i < recipients.length; i += chunkSize) {
const recipientChunk = recipients.slice(i, i + chunkSize);
const metadataChunk = metadataList.slice(i, i + chunkSize);
console.log(`Processing chunk ${Math.floor(i / chunkSize) + 1} of ${Math.ceil(recipients.length / chunkSize)}`);
const tokenIds = await batchMint(contractAddress, recipientChunk, metadataChunk);
allTokenIds.push(...tokenIds);
// Brief pause between chunks to avoid rate limiting
if (i + chunkSize < recipients.length) {
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
return allTokenIds;
}
Ask Claude Code to optimize chunking logic for your RPC provider’s specific rate limits: “Analyze our minting script and add adaptive chunking that backs off when it detects rate limiting from Alchemy.”
Uploading Metadata to IPFS
Thirdweb provides built-in IPFS storage through its SDK. Claude Code can generate upload pipelines for your metadata:
import { ThirdwebStorage } from "@thirdweb-dev/storage";
const storage = new ThirdwebStorage({
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
async function uploadNFTAssets(
imagePaths: string[],
metadataList: NFTMetadata[]
): Promise<NFTMetadata[]> {
// Upload images first
const imageUris = await storage.uploadBatch(
imagePaths.map((p) => require("fs").readFileSync(p))
);
// Attach IPFS URIs to metadata
const enrichedMetadata = metadataList.map((meta, index) => ({
...meta,
image: imageUris[index],
}));
return enrichedMetadata;
}
Building NFT Marketplace Features
Thirdweb’s marketplace contracts enable listing, buying, and bidding on NFTs without building your own auction infrastructure. Here’s a complete listing workflow:
import { DirectListingV3 } from "@thirdweb-dev/sdk";
async function createDirectListing(
marketplaceAddress: string,
nftContractAddress: string,
tokenId: string,
priceInMatic: string,
durationDays = 7
): Promise<string> {
const sdk = new ThirdwebSDK("polygon", {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
const marketplace = await sdk.getContract(marketplaceAddress, "marketplace-v3");
const startTime = new Date();
const endTime = new Date(Date.now() + durationDays * 24 * 60 * 60 * 1000);
const listingId = await marketplace.directListings.createListing({
assetContractAddress: nftContractAddress,
tokenId,
pricePerToken: priceInMatic,
currencyContractAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // native token
startTimestamp: startTime,
endTimestamp: endTime,
isReservedListing: false,
});
console.log(`Created listing ID: ${listingId}`);
return listingId.toString();
}
Buying from Marketplace Listings
async function buyListing(
marketplaceAddress: string,
listingId: string,
buyerAddress: string,
quantity = 1
): Promise<void> {
const sdk = new ThirdwebSDK("polygon", {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
const marketplace = await sdk.getContract(marketplaceAddress, "marketplace-v3");
await marketplace.directListings.buyFromListing(
listingId,
buyerAddress,
quantity,
"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // currency
pricePerToken
);
console.log(`Purchase complete for listing ${listingId}`);
}
Auction Support
For auction-style sales with bidding, Thirdweb’s English auction contract provides the full lifecycle:
async function createAuction(
marketplaceAddress: string,
nftContractAddress: string,
tokenId: string,
minimumBidInMatic: string,
buyoutPriceInMatic: string
): Promise<string> {
const sdk = new ThirdwebSDK("polygon", {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
const marketplace = await sdk.getContract(marketplaceAddress, "marketplace-v3");
const auctionId = await marketplace.englishAuctions.createAuction({
assetContractAddress: nftContractAddress,
tokenId,
minimumBidAmount: minimumBidInMatic,
buyoutBidAmount: buyoutPriceInMatic,
timeBufferInSeconds: 900, // extend auction by 15 min if bid near close
bidBufferBps: 500, // bids must be 5% higher than current
startTimestamp: new Date(),
endTimestamp: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000), // 3 days
});
return auctionId.toString();
}
Managing Wallets and Transactions
Thirdweb supports multiple wallet types, EOAs, smart wallets, and in-app wallets. Understanding when to use each is critical for production applications:
| Wallet Type | Best For | Key Advantage |
|---|---|---|
| EOA (MetaMask, etc.) | DeFi power users | Full user control |
| Smart Wallet (ERC-4337) | Gasless UX, session keys | Sponsored transactions |
| In-App Wallet | Social login, Web2 onboarding | Email/OAuth login |
| Local Wallet | Server-side scripts, testing | No external deps |
Here’s how to work with smart wallets for gasless user experiences:
import { SmartWallet, LocalWallet } from "@thirdweb-dev/wallets";
async function setupSmartWallet(userPrivateKey: string) {
// Load the personal wallet (the "owner")
const personalWallet = new LocalWallet();
await personalWallet.import({ privateKey: userPrivateKey, encryption: false });
// Configure the smart wallet with Account Abstraction
const smartWallet = new SmartWallet({
chain: "polygon",
factoryAddress: process.env.SMART_WALLET_FACTORY_ADDRESS!,
gasless: true, // sponsor gas fees
personalWallet,
});
await smartWallet.connect({ personalWallet });
const address = await smartWallet.getAddress();
console.log("Smart wallet address:", address);
return smartWallet;
}
Transaction Retry Logic
Network congestion can cause transactions to fail or stall. Claude Code can generate solid retry wrappers:
async function sendTransactionWithRetry<T>(
txFn: () => Promise<T>,
maxRetries = 3,
delayMs = 2000
): Promise<T> {
let lastError: Error | undefined;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await txFn();
} catch (error: any) {
lastError = error;
const isRetryable =
error.message?.includes("nonce too low") ||
error.message?.includes("replacement fee too low") ||
error.message?.includes("network timeout");
if (!isRetryable || attempt === maxRetries) {
throw error;
}
console.log(`Attempt ${attempt} failed, retrying in ${delayMs}ms...`);
await new Promise((resolve) => setTimeout(resolve, delayMs * attempt));
}
}
throw lastError;
}
// Usage
const tokenId = await sendTransactionWithRetry(() =>
mintNFT(contractAddress, recipientAddress, metadata)
);
Event Listening and Contract Monitoring
One of the most powerful patterns in Thirdweb development is real-time event listening. Claude Code is excellent at generating event monitoring scripts:
import { ThirdwebSDK } from "@thirdweb-dev/sdk";
async function monitorNFTTransfers(contractAddress: string) {
const sdk = new ThirdwebSDK("polygon", {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
const contract = await sdk.getContract(contractAddress);
// Listen for Transfer events
contract.events.listenToAllEvents((event) => {
if (event.eventName === "Transfer") {
const { from, to, tokenId } = event.data;
console.log(`Token ${tokenId} transferred from ${from} to ${to}`);
// Trigger downstream logic: update database, send notifications, etc.
handleTransferEvent({ from, to, tokenId: tokenId.toString() });
}
});
console.log(`Monitoring transfers on contract ${contractAddress}`);
}
interface TransferEvent {
from: string;
to: string;
tokenId: string;
}
async function handleTransferEvent(event: TransferEvent) {
// Update your database, send webhook, trigger Discord notification, etc.
console.log("Processing transfer:", event);
}
For historical event queries, use the getEvents method with block range filtering:
async function getRecentMints(contractAddress: string, blocksBack = 1000) {
const sdk = new ThirdwebSDK("polygon", {
secretKey: process.env.THIRDWEB_SECRET_KEY,
});
const contract = await sdk.getContract(contractAddress);
const provider = sdk.getProvider();
const currentBlock = await provider.getBlockNumber();
const fromBlock = currentBlock - blocksBack;
const mintEvents = await contract.events.getEvents("Transfer", {
fromBlock,
toBlock: currentBlock,
filters: {
from: "0x0000000000000000000000000000000000000000", // mints come from zero address
},
});
return mintEvents.map((event) => ({
to: event.data.to,
tokenId: event.data.tokenId.toString(),
blockNumber: event.transaction.blockNumber,
txHash: event.transaction.transactionHash,
}));
}
Best Practices for Thirdweb Development
When working with Thirdweb and Claude Code, follow these practices to avoid the most common pitfalls:
Environment Isolation: Use separate secret keys for development, staging, and production. Claude can help you set up environment-specific configurations with dotenv-flow or similar tools.
// Load environment-specific .env files
// .env.development, .env.staging, .env.production
require("dotenv-flow").config();
const isProduction = process.env.NODE_ENV === "production";
const chain = isProduction ? "polygon" : "mumbai";
Gas Optimization: For high-volume operations, batch transactions when possible. Compare strategies:
| Operation | Single Tx Cost | Batch (50x) Cost | Savings |
|---|---|---|---|
| NFT Mint | ~$0.05 | ~$1.00 total | ~58% |
| Transfer | ~$0.03 | ~$0.60 total | ~60% |
| Approve | ~$0.02 | N/A (per-user) | . |
Error Handling: Implement typed error handling for common Thirdweb failure modes:
import { TransactionError } from "@thirdweb-dev/sdk";
async function safeMint(contractAddress: string, toAddress: string, metadata: NFTMetadata) {
try {
return await mintNFT(contractAddress, toAddress, metadata);
} catch (error: unknown) {
if (error instanceof TransactionError) {
if (error.reason?.includes("insufficient funds")) {
throw new Error("Wallet does not have enough gas to complete the transaction");
}
if (error.reason?.includes("execution reverted")) {
throw new Error(`Contract rejected the transaction: ${error.reason}`);
}
}
throw error;
}
}
Type Safety: Always use Thirdweb’s exported TypeScript types rather than any. Ask Claude: “Replace all any types in my Thirdweb code with the correct types from @thirdweb-dev/sdk.”
Testing on Testnets: Thirdweb supports Mumbai (Polygon testnet), Sepolia (Ethereum testnet), and Base Sepolia. Configure a test-environment factory:
const TEST_CHAINS: Record<string, string> = {
polygon: "mumbai",
ethereum: "sepolia",
base: "base-sepolia",
};
function getTestChain(productionChain: string): string {
return TEST_CHAINS[productionChain] ?? productionChain;
}
Integrating with Claude Code Workflows
Claude Code excels at automating repetitive Thirdweb tasks throughout the development lifecycle. Here are the most productive workflow patterns:
Contract Scaffolding: Ask Claude to generate complete deployment scripts for new contract types. Prompt: “Generate a full deployment and configuration script for a Thirdweb NFT Drop contract with allow-list claim phases.”
Contract Monitoring: Ask Claude to create a background worker that monitors your deployed contracts for events and logs significant occurrences to a database or webhook endpoint.
Gas Analysis: Prompt Claude to analyze your transaction history and identify operations that is batched or optimized: “Review this minting script and identify every operation that makes a separate on-chain transaction that is combined.”
Test Generation: Use Claude to generate integration tests against testnet contracts: “Write a test suite using Jest that deploys a test NFTCollection to Mumbai and verifies mint, transfer, and burn operations.”
Documentation Generation: Have Claude generate Markdown API docs directly from your Thirdweb integration code: “Generate developer documentation for all exported functions in my thirdweb-helpers.ts file.”
Conclusion
Combining Claude Code with Thirdweb SDK creates a powerful development environment for blockchain applications. The SDK handles the complexity of blockchain interactions, IPFS storage, wallet management, gas estimation, ABI encoding, while Claude Code automates repetitive tasks, generates boilerplate, optimizes for gas efficiency, and helps you debug production issues.
The most effective workflow is iterative: start with simple single-chain deployments using prebuilt contracts, add proper TypeScript typing and error handling, then build toward multi-chain support, smart wallet integration, and real-time event monitoring. Use Claude Code at each stage not just to write code but to audit what you have, suggest optimizations, and generate tests.
Always test thoroughly on testnets before deploying to mainnet, keep your private keys in environment variables (never in source control), and use Thirdweb’s dashboard to monitor your deployed contracts in production.
Try it: Paste your error into our Error Diagnostic for an instant fix.
Related Reading
- Claude Code for Alchemy SDK Workflow Tutorial
- Claude Code Algolia GeoSearch Filtering Workflow Tutorial
- Claude Code CloudFormation Template Generation Workflow Guid
Built by theluckystrike. More at zovo.one
Know your costs → Use our Claude Code Cost Calculator to estimate your monthly spend.
Quick setup → Launch your project with our Project Starter.