Web3 Icons is a monorepo providing comprehensive cryptocurrency, blockchain, and Web3-related icons as SVGs and React components. The project uses Bun as the package manager and Turbo for build orchestration.
# Build all packages and apps (runs turbo build + post-build)
bun build
# Build only packages (common, core, react)
bun build:packages
# Build individual packages
bun build:common # Generates metadata TypeScript files from JSON
bun build:core # Optimizes SVGs, generates index and svg-module
bun build:react # Generates React components from SVGs
# Build apps
bun build:apps
bun build:website # Next.js website
bun build:figma # Figma plugin
# Post-build step (runs after main build)
bun post-build # Runs generate-icons-md + format# Start development mode (uses turbo dev)
bun dev
# Format code (Prettier)
bun format# Add new icons - detects git changes in raw-svgs/
bun add-icons
# Add metadata entry that references existing icons (e.g., testnets, wrapped tokens)
bun add-metadata
# Delete icons and their metadata
bun delete-icons
# Check for missing metadata
bun check-missing
# Validate SVG files
bun validate-svgs
bun validate-filenames# Generate icons documentation (docs/icons.md)
bun generate-icons-md# Sync to CDN (R2)
bun cdn:syncweb3icons/
├── packages/
│ ├── common/ # Shared metadata and types
│ ├── core/ # Optimized SVGs
│ └── react/ # React components
├── apps/
│ ├── website/ # Next.js website (web3icons.io)
│ └── figma-plugin/ # Figma plugin
├── scripts/ # Build scripts and CLI tools
└── raw-svgs/ # Source SVG files
@web3icons/common: Base package containing metadata (tokens.json, networks.json, wallets.json, exchanges.json) and TypeScript types@web3icons/core: Depends oncommon. Contains optimized SVGs insrc/svgs/@web3icons/react: Depends oncommon. Contains generated React components
Types: token, network, wallet, exchange
Variants: branded (color), mono (monochrome), background (tokens only)
- Runs
scripts/build-scripts/generate-metadata.ts - Converts JSON metadata files to TypeScript files with type annotations
- Located in
packages/common/src/metadata/
Pre-build steps (scripts/build-scripts/core/core.pre-build.ts):
- Order metadata: Alphabetically sorts all metadata JSON files
- Optimize SVGs: Processes raw-svgs/ → packages/core/src/svgs/
- Applies SVGO optimization
- Organizes by type and variant folders
- Generate svg-module.ts: Creates import mappings for all SVGs
- Generate index.ts: Exports all SVG assets
Pre-build steps (scripts/build-scripts/react/react.pre-build.ts):
- Generate components: Converts SVGs to React components using SVGR
- Creates
Token{Symbol},Network{Name},Wallet{Name},Exchange{Name}components - Located in
packages/react/src/icons/
- Creates
- Generate index.ts: Exports all React components
-
Add SVG files to
raw-svgs/{type}/{variant}/following naming conventions:- Tokens: UPPERCASE symbol (e.g.,
BTC.svg) - Networks/Wallets/Exchanges: kebab-case (e.g.,
binance-smart-chain.svg) - SVGs must be 24x24px frames (see CONTRIBUTING.md)
- Tokens: UPPERCASE symbol (e.g.,
-
Run
bun add-icons:- Detects git changes in raw-svgs/
- Prompts for metadata (name, id, CoinGecko ID, etc.)
- Adds entries to metadata JSON files
- Or use
bun add-metadatato reference existing icons
-
Build packages:
bun build:packagesprocesses everything- SVGs are optimized and copied to core package
- React components are auto-generated
Metadata files are the source of truth stored as JSON in packages/common/src/metadata/. They are converted to TypeScript files during the common package build.
{
"id": "bitcoin",
"filePath": "token:BTC",
"symbol": "BTC",
"name": "Bitcoin",
"marketCapRank": 1,
"addresses": {
"ethereum": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
"binance-smart-chain": "0x7130d2a12b9bcbfae4f2634d864a1ee1ce3ead9c"
},
"variants": ["branded", "mono", "background"]
}Fields:
id: Unique identifier (typically lowercase with hyphens)filePath: Icon reference in formattype:filename(e.g.,token:BTC)- Icon Sharing System: Multiple entries can reference the same SVG file
- Example: Wrapped tokens can use
filePath: "token:ETH"to share Ethereum's icon - Example: Testnets can use
filePath: "network:ethereum"to share mainnet's icon
symbol: Token ticker (uppercase, e.g.,BTC,ETH)name: Full token namemarketCapRank: Market cap ranking (null if not tracked)addresses: Object mapping network IDs to contract addressesvariants: Array of available icon variants (["branded", "mono", "background"])
{
"id": "ethereum",
"filePath": "network:ethereum",
"chainId": 1,
"caip2id": "eip155:1",
"name": "Ethereum",
"shortName": "ETH",
"nativeCoinId": "ethereum",
"variants": ["branded", "mono", "background"]
}Fields:
id: Network identifier (kebab-case)filePath: Icon reference (e.g.,network:ethereum)chainId: EVM chain ID (if applicable, can be number or string)caip2id: CAIP-2 chain ID format (e.g.,eip155:1)name: Full network nameshortName: Abbreviated namenativeCoinId: Token ID of the native coinvariants: Available icon variants
{
"id": "metamask",
"filePath": "wallet:metamask",
"name": "MetaMask",
"variants": ["branded", "mono"]
}Fields:
id: Wallet identifier (kebab-case)filePath: Icon referencename: Display namevariants: Available icon variants
{
"id": "uniswap",
"filePath": "exchange:uniswap",
"name": "Uniswap",
"type": "dex",
"variants": ["branded", "mono"]
}Fields:
id: Exchange identifier (kebab-case)filePath: Icon referencename: Display nametype: Either"cex"(centralized exchange) or"dex"(decentralized exchange)variants: Available icon variants
scripts/cli/add-icons.ts: Interactive CLI for adding new icons (detects git changes in raw-svgs/)scripts/cli/delete-icons.ts: Remove icons and metadatascripts/build-scripts/generate-metadata.ts: Converts JSON metadata → TypeScript with type annotationsscripts/build-scripts/core/core-optimize-svgs.ts: SVG optimization with SVGO + incremental build cachingscripts/build-scripts/core/core-generate-svgs-module.ts: Generates svg-module.ts with all icon importsscripts/build-scripts/react/react-generate-components.ts: Converts SVGs → React components using SVGRscripts/maintenance/generate-icons-md.ts: Generates docs/icons.md documentation tablescripts/utils/svg-optimization.ts: SVGO configuration and SVG processing utilitiesscripts/utils/build-cache.ts: Incremental build cache system for faster rebuilds
File paths (raw-svgs):
raw-svgs/tokens/{variant}/BTC.svgraw-svgs/networks/{variant}/ethereum.svgraw-svgs/wallets/{variant}/metamask.svg
React component names:
- Tokens:
Token{SYMBOL}→TokenBTC,TokenETH - Networks:
Network{PascalCase}→NetworkEthereum,NetworkBinanceSmartChain - Wallets:
Wallet{PascalCase}→WalletMetamask,WalletRainbow - Exchanges:
Exchange{PascalCase}→ExchangeCoinbase,ExchangeBybit
Core SVG exports:
svgs.tokens.brandedBTC(camelCase)svgs.networks.monoEthereum(camelCase)
After making changes:
- Run
bun build:packagesto rebuild affected packages - Check generated files:
packages/common/src/metadata/*.tspackages/core/src/svgs/packages/react/src/icons/
- Run
bun formatbefore committing
- Always add icons to
raw-svgs/first, never directly to package src folders - The build process is automated - manual edits to generated files will be overwritten
- Metadata JSON files in
packages/common/src/metadata/are the source of truth - Use
bun add-metadatafor entries that share icons with existing entries (e.g., testnets using mainnet icons, wrapped tokens) - SVG optimization happens during core package build, using SVGO with custom config
- Incremental builds are enabled by default - only changed SVGs are re-optimized
The React package provides dynamic components that automatically load the correct icon based on props. These are client-side only components ('use client' directive) and must be imported from the /dynamic entry point.
import { TokenIcon } from '@web3icons/react/dynamic'
// By symbol
<TokenIcon symbol="ETH" variant="branded" size={32} />
// By contract address + network
<TokenIcon
address="0xc944e90c64b2c07662a292be6244bdf05cda44a7"
network="ethereum"
variant="mono"
size={32}
/>
// With fallback
<TokenIcon
symbol="UNKNOWN"
fallback={<img src="/default.svg" />}
/>Lookup logic (packages/react/src/utils/find-metadata.ts):
- If
symbolprovided: Case-insensitive match on symbol field - If
address+network: Matches contract address in addresses object - Returns
ITokenMetadata | undefined
import { NetworkIcon } from '@web3icons/react/dynamic'
// By name (matches id, name, or shortName - case insensitive)
<NetworkIcon name="Ethereum" variant="branded" size={32} />
<NetworkIcon name="bsc" /> // Matches shortName
// By chainId
<NetworkIcon chainId={1} variant="mono" />
// By CAIP-2 ID
<NetworkIcon caip2id="eip155:1" />Lookup logic:
- If
name: Matches againstid(kebab-case),name, orshortName(case-insensitive) - If
chainId: Exact match on chainId field - If
caip2id: Exact match on caip2id field - If
id: Matches id or name
import { WalletIcon, ExchangeIcon } from '@web3icons/react/dynamic'
<WalletIcon name="MetaMask" variant="branded" />
<WalletIcon id="metamask" /> // kebab-case id
<ExchangeIcon name="Uniswap" variant="mono" />Lookup logic: Case-insensitive match on id (kebab-case) or name
SVG optimization is handled by scripts/build-scripts/core/core-optimize-svgs.ts using SVGO:
Configuration (scripts/utils/svg-optimization.ts):
removeViewBox: false- Preserves viewBox for proper scalingprefixIds: true- Prefixes IDs with icon name to prevent conflictsmultipass: true- Multiple optimization passes for better compressionjs2svg: { pretty: true }- Pretty-printed output
Optimizations applied:
- Remove unnecessary attributes and metadata
- Minify paths and transforms
- Merge paths where possible
- Prefix all IDs to avoid conflicts when multiple SVGs are on the same page
- Convert style strings to camelCase objects for JSX compatibility
Incremental Build Cache:
- Tracks file hashes to skip unchanged SVGs
- Dramatically speeds up rebuilds (only processes modified icons)
- Cache stored in
node_modules/.cache/web3icons/ - Enable with env var or automatically enabled by default
The filePath property enables multiple metadata entries to reference the same physical SVG files.
Use cases:
-
Testnets: Use mainnet icons
{ "id": "sepolia", "filePath": "network:ethereum", // References ethereum.svg "name": "Sepolia Testnet", "chainId": 11155111 } -
Wrapped tokens: Use underlying token's icon
{ "id": "wrapped-bitcoin", "filePath": "token:BTC", // References BTC.svg "symbol": "WBTC", "name": "Wrapped Bitcoin" } -
Token variants: Multiple listings share same icon
{ "id": "tether-bridged", "filePath": "token:USDT", // References USDT.svg "symbol": "USDT.e", "name": "Tether USD (Bridged)" }
Format: {type}:{filename} where:
type:token,network,wallet, orexchangefilename: The SVG filename without extension (e.g.,BTC,ethereum,metamask)
All metadata types are defined in packages/common/src/types.ts:
type TVariant = 'branded' | 'mono' | 'background'
type TType = 'network' | 'token' | 'wallet' | 'exchange'
type TExchangeType = 'cex' | 'dex'
interface ITokenMetadata {
id: string
filePath: string
symbol: string
name: string
marketCapRank: number | null
addresses: { [key: string]: string | undefined }
variants: TVariant[]
}
interface INetworkMetadata {
id: string
filePath: string
name: string
shortName?: string
nativeCoinId?: string
chainId?: number | string
caip2id?: string
variants: TVariant[]
}- Create SVG files in
raw-svgs/tokens/branded/and/orraw-svgs/tokens/mono/- Filename:
{SYMBOL}.svg(e.g.,BTC.svg,ETH.svg) - Must be 24x24px frame (see CONTRIBUTING.md)
- Filename:
- Run
bun add-icons - CLI detects new files and prompts for metadata
- Enter token name, ID, contract addresses, etc.
- Run
bun build:packagesto generate components - Verify in
packages/core/src/svgs/tokens/andpackages/react/src/icons/tokens/
- Run
bun add-metadata - Select "Network" as the type
- Enter icon reference (e.g.,
network:ethereum) - Provide testnet details (name, chainId, etc.)
- Build packages - testnet will use mainnet's icon
- Replace SVG in
raw-svgs/{type}/{variant}/ - Git will show modification
- Run
bun build:coreto re-optimize - Incremental cache detects change and re-processes only that file
Icons not showing up after adding:
- Ensure
bun build:packageswas run - Check metadata JSON files in
packages/common/src/metadata/ - Verify SVG files were copied to
packages/core/src/svgs/ - Check React components generated in
packages/react/src/icons/
Build failing:
- Run
bun formatto fix formatting issues - Check SVG files are valid XML
- Ensure metadata JSON files are valid JSON
- Check for duplicate IDs in metadata files
Dynamic components not working:
- Remember they are client-side only (
'use client') - Check lookup logic matches your props (case-insensitive, kebab-case conversions)
- Use fallback prop to handle missing icons gracefully
Slow builds:
- Incremental cache should be enabled automatically
- Clear cache:
rm -rf node_modules/.cache/web3icons/ - Check if processing all SVGs vs. only changed ones in build output