Network Switching
Seamlessly switch between networks during development without reinitializing your application.
Basic Switching
import { createDevKit } from 'cardano-devkit';
// Start with local devnet
const devKit = createDevKit({ network: 'LocalDevnet' });
await devKit.init();
// Develop and test locally...
// Ready for testnet testing
await devKit.switchNetwork('Preprod');
// Test complete, deploy to mainnet
await devKit.switchNetwork('Mainnet', { confirmMainnet: true });
Helper Methods
useLocalDevnet()
// Switch to local devnet
await devKit.useLocalDevnet();
// With custom port
await devKit.useLocalDevnet(9090);
usePreprod()
// Switch to Preprod testnet
await devKit.usePreprod();
usePreview()
// Switch to Preview testnet
await devKit.usePreview();
useMainnet()
// Switch to Mainnet (requires confirmation)
await devKit.useMainnet({ confirmMainnet: true });
What Happens During Switch
When you switch networks:
- Provider is updated - New API endpoints
- Network parameters refresh - Protocol params, epoch info
- Lucid instance reinitializes - Fresh connection
- Wallet remains selected - Same keys, different network
// Before switch
const preprodAddress = await lucid.wallet().address();
// addr_test1qz...
// After switch to mainnet
const mainnetAddress = await lucid.wallet().address();
// addr1qx... (same keys, mainnet format)
Preserving Wallet State
// Save wallet before switch
const seed = currentSeed; // Your saved seed
await devKit.switchNetwork('Preprod');
const lucid = await devKit.getLucid();
// Restore wallet after switch
lucid.selectWallet.fromSeed(seed);
Dynamic Configuration
Environment-Based Switching
async function initializeForEnvironment() {
const devKit = createDevKit({ network: 'LocalDevnet' });
await devKit.init();
switch (process.env.CARDANO_NETWORK) {
case 'mainnet':
await devKit.useMainnet({ confirmMainnet: true });
break;
case 'preprod':
await devKit.usePreprod();
break;
case 'preview':
await devKit.usePreview();
break;
default:
await devKit.useLocalDevnet();
}
return devKit;
}
User-Selectable Networks
async function handleNetworkChange(network: string) {
switch (network) {
case 'local':
await devKit.useLocalDevnet();
break;
case 'preview':
await devKit.usePreview();
break;
case 'preprod':
await devKit.usePreprod();
break;
case 'mainnet':
// Show confirmation dialog first
const confirmed = await showMainnetConfirmation();
if (confirmed) {
await devKit.useMainnet({ confirmMainnet: true });
}
break;
}
// Refresh UI
updateNetworkDisplay(devKit.getCurrentNetwork());
}
Network State Management
// Get current network
const network = devKit.getCurrentNetwork();
console.log(network); // 'LocalDevnet' | 'Preview' | 'Preprod' | 'Mainnet'
// Get environment type
const env = devKit.getEnvironment();
console.log(env); // 'development' | 'testnet' | 'production'
// Check network type
if (devKit.isLocalDevnet()) {
// Local-only features
}
if (devKit.isTestnet()) {
// Testnet features (Preview or Preprod)
}
if (devKit.isSafeForTesting()) {
// Not mainnet
}
Provider Management
Auto Provider Selection
// DevKit automatically selects appropriate provider
await devKit.usePreprod();
// Uses default Blockfrost for Preprod
await devKit.useLocalDevnet();
// Uses local Koios-compatible API
Manual Provider Override
// Override provider during switch
await devKit.switchNetwork('Preprod', {
provider: {
type: 'koios',
baseUrl: 'https://preprod.koios.rest/api/v1'
}
});
Provider Credentials
// Set up provider credentials for each network
const providerConfigs = {
Preprod: {
type: 'blockfrost' as const,
apiKey: process.env.BLOCKFROST_PREPROD_KEY
},
Mainnet: {
type: 'blockfrost' as const,
apiKey: process.env.BLOCKFROST_MAINNET_KEY
}
};
await devKit.switchNetwork('Preprod', {
provider: providerConfigs.Preprod
});
Event Handling
// Listen for network changes
devKit.on('networkChanged', (event) => {
console.log(`Switched from ${event.from} to ${event.to}`);
// Update UI
updateNetworkBadge(event.to);
// Refresh wallet balance
refreshBalance();
});
// Listen for errors
devKit.on('error', (error) => {
console.error('Network error:', error);
showErrorToast(error.message);
});
Switching Strategies
Hot Switching (Default)
// Immediate switch, might interrupt pending operations
await devKit.switchNetwork('Preprod');
Graceful Switching
// Wait for pending operations
async function gracefulSwitch(network: NetworkType) {
// Wait for any pending transactions
await Promise.all(pendingTxPromises);
// Save current state
const walletState = saveWalletState();
// Switch
await devKit.switchNetwork(network);
// Restore state
restoreWalletState(walletState);
}
Fallback Strategy
async function switchWithFallback(preferred: NetworkType, fallback: NetworkType) {
try {
await devKit.switchNetwork(preferred);
} catch (error) {
console.warn(`Failed to connect to ${preferred}, falling back to ${fallback}`);
await devKit.switchNetwork(fallback);
}
}
Error Handling
try {
await devKit.switchNetwork('Preprod');
} catch (error) {
if (error.code === 'PROVIDER_UNAVAILABLE') {
console.error('Provider is down, try again later');
} else if (error.code === 'INVALID_CREDENTIALS') {
console.error('Check your API key');
} else if (error.code === 'MAINNET_NOT_CONFIRMED') {
console.error('Must confirm mainnet switch');
} else {
throw error;
}
}
Best Practices
1. Always Check Before Destructive Operations
if (!devKit.isSafeForTesting()) {
throw new Error('Cannot run tests on mainnet!');
}
2. Use Environment Variables
// .env.local
CARDANO_NETWORK=LocalDevnet
// .env.staging
CARDANO_NETWORK=Preprod
// .env.production
CARDANO_NETWORK=Mainnet
3. Implement Confirmation for Mainnet
async function deployToMainnet() {
const confirmed = await showConfirmationDialog(
'You are about to deploy to MAINNET. This uses real ADA. Continue?'
);
if (!confirmed) return;
await devKit.useMainnet({ confirmMainnet: true });
// Deploy...
}