Skip to main content

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:

  1. Provider is updated - New API endpoints
  2. Network parameters refresh - Protocol params, epoch info
  3. Lucid instance reinitializes - Fresh connection
  4. 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...
}

Next Steps