Getting Started with Devnet
This guide walks through creating, starting, and managing a local Cardano development network. You'll learn cluster lifecycle operations, container management, and how to integrate Kupo and Ogmios for full blockchain access.
Installation
pnpm add @evolution-sdk/devnet @evolution-sdk/evolution
The package requires Docker to be running. Verify Docker is available:
docker --version
Basic Cluster Creation
import { Cluster } from "@evolution-sdk/devnet";
const cluster = await Cluster.make({
clusterName: "my-first-devnet",
ports: { node: 3001, submit: 3002 }
});
console.log("Cluster created:", cluster.cardanoNode.name);
The make function returns a cluster configuration containing container references. The cardano-node will bind to port 3001 for peer connections and port 3002 for transaction submission.
Starting the Cluster
import { Cluster } from "@evolution-sdk/devnet";
const cluster = await Cluster.make()
await Cluster.start(cluster);
console.log("Devnet is now producing blocks");
await new Promise(resolve => setTimeout(resolve, 3000));
Checking Container Status
import { Cluster, Container } from "@evolution-sdk/devnet";
const cluster = await Cluster.make()
const status = await Container.getStatus(cluster.cardanoNode);
console.log("Container state:", status?.State.Status)
console.log("Container health:", status?.State.Health?.Status)
The status object includes full Docker inspect output: state, network settings, mounts, resource usage, and health check results.
Stopping and Removing
import { Cluster } from "@evolution-sdk/devnet";
const cluster = await Cluster.make()
await Cluster.stop(cluster);
console.log("Cluster stopped");
await Cluster.remove(cluster);
console.log("Cluster removed");
Stopping containers preserves blockchain state in Docker volumes. Removing deletes containers but keeps named volumes by default. To completely reset state, manually remove volumes using Docker commands.
Adding Kupo and Ogmios
import { Cluster, Container } from "@evolution-sdk/devnet";
const cluster = await Cluster.make({
clusterName: "full-stack-devnet",
ports: { node: 3001, submit: 3002 },
kupo: {
enabled: true,
port: 1442,
logLevel: "Info"
},
ogmios: {
enabled: true,
port: 1337,
logLevel: "info"
}
});
await Cluster.start(cluster);
await new Promise(resolve => setTimeout(resolve, 5000));
if (cluster.kupo) {
const kupoStatus = await Container.getStatus(cluster.kupo);
console.log("Kupo status:", kupoStatus?.State.Status);
}
if (cluster.ogmios) {
const ogmiosStatus = await Container.getStatus(cluster.ogmios);
console.log("Ogmios status:", ogmiosStatus?.State.Status);
}
The log levels control output verbosity:
- Kupo:
Debug,Info,Warning,Error - Ogmios:
debug,info,notice,warning,error
Individual Container Operations
import { Cluster, Container } from "@evolution-sdk/devnet";
const cluster = await Cluster.make()
await Container.stop(cluster.cardanoNode);
console.log("Node stopped, Kupo and Ogmios still running");
const stoppedStatus = await Container.getStatus(cluster.cardanoNode);
console.log("Status:", stoppedStatus?.State.Status);
await Container.start(cluster.cardanoNode);
await new Promise(resolve => setTimeout(resolve, 2000));
const runningStatus = await Container.getStatus(cluster.cardanoNode);
console.log("Status:", runningStatus?.State.Status);
Complete Workflow Example
import { Cluster, Container } from "@evolution-sdk/devnet";
async function runDevnetSession() {
const cluster = await Cluster.make({
clusterName: "dev-session",
ports: { node: 3001, submit: 3002 },
kupo: { enabled: true, port: 1442 },
ogmios: { enabled: true, port: 1337 }
});
try {
await Cluster.start(cluster);
console.log("Devnet started");
await new Promise(resolve => setTimeout(resolve, 5000));
const nodeStatus = await Container.getStatus(cluster.cardanoNode);
const kupoStatus = cluster.kupo
? await Container.getStatus(cluster.kupo)
: null;
const ogmiosStatus = cluster.ogmios
? await Container.getStatus(cluster.ogmios)
: null;
console.log("Node:", nodeStatus?.State.Status);
console.log("Kupo:", kupoStatus?.State.Status);
console.log("Ogmios:", ogmiosStatus?.State.Status);
console.log("Devnet ready for development");
console.log("Ogmios: http://localhost:1337");
console.log("Kupo: http://localhost:1442");
await new Promise(resolve => setTimeout(resolve, 10000));
} finally {
await Cluster.stop(cluster);
await Cluster.remove(cluster);
console.log("Devnet stopped and removed");
}
}
runDevnetSession().catch(console.error);
Next Steps
- Configuration — Customize genesis parameters, fund addresses, and modify protocol settings
- Integration — Use the Evolution SDK client to query the blockchain and submit transactions
Troubleshooting
Port conflicts: If ports are already in use, choose different values:
ports: { node: 4001, submit: 4002 }
Slow startup: Initial Docker image pulls can take several minutes. Subsequent starts are fast. The SDK automatically pulls missing images.
Container won't start: Check Docker daemon is running and you have sufficient disk space for blockchain data.
Network errors: Ensure no firewall rules block localhost ports. The containers bind to 127.0.0.1 by default.