In this blog post, you will learn how to deploy a test instance of KurrentDB to Azure and access it from a console application in .NET.
Why did I write this blog post?
While updating my DDD, CQRS, and Event Sourcing in .NET training course to the latest version of .NET and C#, I also decided to switch from EventStoreDB to KurrentDB for the course’s hands-on exercises.
Previously, we ran EventStoreDB locally, but during our corporate training sessions, we found that installing software onto student machines often gets restricted. To work around this, I chose to host KurrentDB in Azure, with a separate instance running for each student.
As usual, I thought to share my learning with you! This blog post walks through how I deployed KurrentDB to Azure and connected to it from C#.
What is KurrentDB?
KurrentDB is the new name for EventStoreDB, one of the first purpose-built databases for event sourcing. It was created by Greg Young, who also introduced the Command and Query Responsibility Segregation (CQRS) pattern.
KurrentDB stores every change to your data as an event. Instead of just saving the latest state, it records what happened, when, and why. This approach lets you rebuild the full history of your system, create audit logs, replay behavior, or build read models that are tailored for specific needs.
The KurrentDB database is open-source, written in C#, and available on GitHub. The source code is well written and makes for an interesting codebase to review and explore. I find that reading and exploring real-world projects is a great way to pick up new techniques and ideas.
Is KurrentDB a new database?
No, it was originally released in 2012 and is one of the few purpose-built event store databases available. It has had many years to mature and evolve. If you’re curious about how it works internally, check out this talk by Gregory Young: How an EventStore actually works.
What is Event Sourcing?
Event sourcing is a way of storing data by recording each change as an event. Instead of saving the latest state, you store the full history of everything that happened. This makes it easy to rebuild states, trace changes, and support things like auditing and custom views.
For example, in a shopping cart, you can store each action as it happens:

To get to the current state, you would load all events and apply them one by one to the shopping cart. A big benefit of event sourcing, is that it makes it much easier to understand how and why something changed within a system, which is great for troubleshooting.
Deploying KurrentDB to Azure
There are several ways to host KurrentDB in Azure, but my requirements were:
- Each student should get their own dedicated instance.
- It must be easy to deploy and clean up using a PowerShell script.
- No need to deal with https (TLS) certificates.
- It should be cost-effective.
Given these needs, I decided to use Azure Container Instances. KurrentDB is available as a container image, and you can find the details in their installation guide.
Azure Container Instances are suitable for testing KurrentDB, but should not be used for production. ACI enforces certain restrictions that limit some features KurrentDB relies on to run properly.
KurrentDB and the network
Before we deploy KurrentDB, we need to understand its network configuration. By default, KurrentDB listens to two network ports:
Port 1113
KurrentDB uses port 1113 for internal TCP traffic between cluster nodes, such as replication and gossip.

In our case, since we’re running a single-node setup, we don’t need to worry about port 1113. This port is used only for internal node-to-node communication and should never be exposed to the public internet or client applications.
Port 2113
KurrentDB uses by default port 2113 for client communication over HTTP or HTTPS.

In this example, we expose port 2113 to the public internet. To simplify setup and avoid dealing with TLS certificates, we run KurrentDB in insecure mode by setting the KURRENTDB_INSECURE environment variable to true. This is fine for testing and development, but it should never be used in production.
Deploying KurrentDB to Azure Container Instances
For my first attempt at deploying KurrentDB as an Azure Container Instance, I used the following PowerShell script:
$containerImage = "docker.kurrent.io/kurrent-latest/kurrentdb:latest"
$ResourceGroupName = "rg-kurrenteventstore"
$containerName = "kurrentdb-attempt1"
$Location = "swedencentral"
# Create resource group if it doesn't exist
az group create --name $ResourceGroupName `
--location $Location `
# Create Azure Container Instance
az container create `
--resource-group $ResourceGroupName `
--name $containerName `
--image $containerImage `
--ports 2113 `
--environment-variables "KURRENTDB_INSECURE=true" `
--cpu 1 `
--memory 1 `
--os-type Linux `
--location $Location `
--restart-policy Never `
--dns-name-label "$containerName-$(Get-Random)" `
--query "ipAddress.fqdn"
After running the script, we had a working KurrentDB instance deployed to the public internet, accessible on port 2113.
When navigating to the URL in your browser, you’ll see KurrentDB’s built-in web interface. This gives you a quick way to check that the instance is up and running, and allows you to explore some basic information and diagnostics like below.

Deploying multiple instances of KurrentDB
Being able to deploy an instance to Azure is awesome. However, I need a script to deploy multiple instances to Azure.
The modified script eventually became this:
$containerImage = "docker.kurrent.io/kurrent-latest/kurrentdb:latest"
$ResourceGroupName = "rg-kurrenteventstore2"
$Location = "swedencentral"
$instanceCount = 2
# Create resource group if it doesn't exist
az group create --name $ResourceGroupName `
--location $Location `
$urls = @()
for ($i = 1; $i -le $InstanceCount; $i++)
{
$containerName = "kurrentdb-$i"
# Create Azure Container Instance
$fqdn = az container create `
--resource-group $ResourceGroupName `
--name $containerName `
--image $containerImage `
--ports 2113 `
--environment-variables "KURRENTDB_INSECURE=true" `
--cpu 1 `
--memory 1 `
--os-type Linux `
--location $Location `
--restart-policy Never `
--dns-name-label "$containerName-$(Get-Random)" `
--query "ipAddress.fqdn" `
--output tsv
$urls = $urls + "${fqdn}:2113"
}
Write-Output "`nAll instance URLs:"
$urls
Kurrent Navigator
To manage your KurrentDB instance, you can use Kurrent Navigator. This is a standalone desktop app with a clean, modern interface for browsing events, inspecting streams, working with projections, and more. It runs on Windows, macOS, and Linux, and it is useful for both daily administration and troubleshooting.

Sending events to KurrentDB from C#
For .NET developers, KurrentDB offers an official .NET client which is also available as a NuGet package: KurrentDB.Client. It supports both .NET Framework 4.8 and modern .NET versions. Details about how to use this package can be found in the getting started documentation.

The code below creates four events and sends it to KurrentDB:
using KurrentDB.Client;
using KurrentDB.Client.Core.Serialization;
var server = "[ServerAddress]";
var settings = KurrentDBClientSettings.Create($"esdb://{server}?tls=false");
settings.OperationOptions.ThrowOnAppendFailure = false;
await using var client = new KurrentDBClient(settings);
var events = new List
After sending the events, we can open Kurrent Navigator to view the events stored in the database:

Reading events from KurrentDB
Reading from KurrentDB is straightforward. You just need to create a client and specify the stream you want to read from, like this:
using KurrentDB.Client;
using System.Text;
using System.Text.Json;
Console.WriteLine("Reading events from KurrentDB...");
var server = "kurrentdb-2-1927695997.swedencentral.azurecontainer.io";
var settings = KurrentDBClientSettings.Create($"esdb://{server}?tls=false");
settings.OperationOptions.ThrowOnAppendFailure = false;
await using var client = new KurrentDBClient(settings);
var streamName = "order-12345";
var events = await client
.ReadStreamAsync(Direction.Forwards, streamName, StreamPosition.Start)
.ToListAsync();
foreach (var ev in events)
{
var json = Encoding.UTF8.GetString(ev.Event.Data.Span);
Console.WriteLine($"{ev.Event.EventNumber} - {json}");
}
As an output, we will get:
Reading events from KurrentDB...
0 - {"id":"0d0545fe-5242-4c06-8ad5-573cd4a89bd1",
"customerID":"264c704d-1754-4e56-9f2a-0f8b4202a045",
"salesPersonID":"3fa6e8f1-c114-4eea-81e0-eefa9fe2a4f4",
"salesPersonName":"John Doe"}
1 - {"id":"b3f37164-94c6-426d-bfe2-b8a6063f37ac",
"reason":"Customer changed their mind"}
2 - {"id":"4b391bb9-b288-4dc9-9f19-ad65dc577cad",
"productId":"4bcb44e5-6bc6-42dd-b47c-18496a4d5380",
"productName":"Laptop","quantity":1,"pricePerUnit":1200.00}
3 - {"id":"6f2fa70f-12ec-46e7-b715-aad3f559be32",
"productId":"bb5147e0-5fbb-4339-88ce-1249fb002d0b"}
Summary
Writing this blog post was a great way to explore everything new from the team behind KurrentDB. I especially enjoyed trying out the Kurrent Navigator, which was completely new to me. Hosting KurrentDB in Azure using Container Instances turned out to be a smooth experience. Just keep in mind that if you’re coming from EventStoreDB, some names and behaviors have changed, which caused a few bumps along the way.
Curious about DDD, CQRS, and Event Sourcing?
If you’re interested in learning more about these concepts, I offer several training classes, including DDD, CQRS and Event Sourcing in .NET and Modern Application Architecture. You can find the full list of workshops on my training page. I also offer coaching if you’d like help working through architectural challenges.
The CQRS and Event Sourcing framework that I use in my training can be found at https://cqrs.nu. It’s a project I was part of creating. There, you’ll also find an example of how to do BDD-style testing of Event Sourced systems.
About Tore
Hey! I’m Tore 👋 I’m an independent consultant, coach, trainer and a Microsoft certified MVP in .NET. My mission is to help developer teams to solve problems more quickly and effectively across tools and platforms like ASP.NET Core, Duende IdentityServer, web security, C#, Azure, .NET, and more. Sounds helpful? I’d love to be of service! You can check out my workshops for teams and my wider consulting and coaching services here.