Getting started

Get started by connecting your application to EventStoreDB.

Complete the form below to generate the connection string and examples for different languages and SDKs.

Connection details

The form below can help you to generate the connection string for a single-node or cluster deployment of EventStoreDB. You can use one of the following methods:

  • Use the Event Store Cloudopen in new window cluster ID.
  • Use the address of any node of a self-hosted cluster or single-node deployment. You need to have access to the node for the discovery feature to work.
  • Specify the deployment details manually.
Event Store Cloud
Node URL
Specify manually

 
Find your cluster ID in the Cloud Console, on the Cluster Details tab.
 
Enable KeepAlive:
KeepAlive settings are available for server and client versions 20.10+. Read more in KeepAlive settings docs

Connecting to EventStoreDB

For your application to start communicating with EventStoreDB, you need to instantiate the client, and configure it accordingly. Below, you will find instructions for supported SDKs.

Insecure Clusters

All our GRPC clients are secure by default, and must be configured to connect to an insecure server via a connection string, or the client's configuration.

Required packages

Install the client SDK package to your project.

# From Pypi
$ pip install esdbclient

# With Poetry
$ poetry add esdbclient
# Yarn
$ yarn add @eventstore/db-client

# NPM
$ npm install --save @eventstore/db-client
# TypeScript Declarations are included in the package.

# Yarn
$ yarn add @eventstore/db-client

# NPM
$ npm install --save @eventstore/db-client
# Maven
<dependency>
  <groupId>com.eventstore</groupId>
  <artifactId>db-client-java</artifactId>
  <version>5.2.0</version>
</dependency>

# Gradle
implementation 'com.eventstore:db-client-java:5.2.0'
$ dotnet add package EventStore.Client.Grpc.Streams --version 23.1.0
go get github.com/EventStore/EventStore-Client-Go/v3.2.0/esdb
No additional configuration is needed having Rust installed. Go check https://rustup.rs.

Connection string

Each SDK has its own way to configure the client, but it's always possible to use the connection string. You can use the connection string generator above on this page to generate the connection string for your EventStoreDB deployment. The connection string generated with this tool should work with each official SDK of EventStoreDB.

Creating a client

First, let's create a client that's connected to the database.

client = EventStoreDBClient(
    uri="{connectionString}"
)
1
2
3
const client = EventStoreDBClient.connectionString`{connectionString}`;
1
const client = EventStoreDBClient.connectionString`{connectionString}`;
1
EventStoreDBClientSettings settings = EventStoreDBConnectionString.parseOrThrow("{connectionString}");
EventStoreDBClient client = EventStoreDBClient.create(settings);
1
2
const string connectionString = "esdb://admin:changeit@localhost:2113?tls=false&tlsVerifyCert=false";

var settings = EventStoreClientSettings.Create(connectionString);

var client = new EventStoreClient(settings);
1
2
3
4
5
settings, err := esdb.ParseConnectionString("{connectionString}")

if err != nil {
    panic(err)
}

db, err := esdb.NewClient(settings)
1
2
3
4
5
6
7
let settings = "{connectionString}".parse()?;
let client = Client::new(settings)?;
1
2

The client instance can be used as a singleton across the whole application. It doesn't need to open or close the connection.

Creating an event

You can write anything to EventStoreDB as events. The client needs a byte array as the event payload. Normally, you'd use a serialized object and it's up to you to choose the serialization method.

Server-side projections

User-defined server-side projections require events to be serialized to JSON format.

We use JSON for serialization in the documentation examples.

The code snippet below creates an event object instance, serializes it and puts it as payload to the EventData structure, which the client is able to write to the database.

new_event = NewEvent(
    id=uuid4(),
    type="TestEvent",
    data=b"I wrote my first event",
)
1
2
3
4
5
const event = jsonEvent({
  type: "TestEvent",
  data: {
    entityId: uuid(),
    importantData: "I wrote my first event!",
  },
});
1
2
3
4
5
6
7
type TestEvent = JSONEventType<
  "TestEvent",
  {
    entityId: string;
    importantData: string;
  }
>;

const event = jsonEvent<TestEvent>({
  type: "TestEvent",
  data: {
    entityId: uuid(),
    importantData: "I wrote my first event!",
  },
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
TestEvent event = new TestEvent();
JsonMapper jsonMapper = new JsonMapper();
event.setId(UUID.randomUUID().toString());
event.setImportantData("I wrote my first event!");

EventData eventData = EventData
        .builderAsJson("TestEvent", jsonMapper.writeValueAsBytes(event))
        .build();
1
2
3
4
5
6
7
8
var evt = new TestEvent {
    EntityId      = Guid.NewGuid().ToString("N"),
    ImportantData = "I wrote my first event!"
};

var eventData = new EventData(
    Uuid.NewUuid(),
    "TestEvent",
    JsonSerializer.SerializeToUtf8Bytes(evt)
);
1
2
3
4
5
6
7
8
9
10
testEvent := TestEvent{
    Id:            uuid.NewString(),
    ImportantData: "I wrote my first event!",
}

data, err := json.Marshal(testEvent)

if err != nil {
    panic(err)
}

eventData := esdb.EventData{
    ContentType: esdb.ContentTypeJson,
    EventType:   "TestEvent",
    Data:        data,
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let event = TestEvent {
    id: Uuid::new_v4().to_string(),
    important_data: "I wrote my first event!".to_string(),
};

let event_data = EventData::json("TestEvent", event)?.id(Uuid::new_v4());
1
2
3
4
5
6

Appending events

Each event in the database has its own unique identifier (UUID). The database uses it to ensure idempotent writes, but it only works if you specify the stream revision when appending events to the stream.

In the snippet below, we append the event to the stream some-stream.

client.append_to_stream(
    "some-stream",
    events=[new_event],
    current_version=StreamState.ANY,
)
1
2
3
4
5
await client.appendToStream(STREAM_NAME, event);
1
await client.appendToStream(STREAM_NAME, event);
1
client.appendToStream("some-stream", eventData)
        .get();
1
2
await client.AppendToStreamAsync(
    "some-stream",
    StreamState.Any,
    new[] { eventData },
    cancellationToken: cancellationToken
);
1
2
3
4
5
6
_, err = db.AppendToStream(context.Background(), "some-stream", esdb.AppendToStreamOptions{}, eventData)
1
client
    .append_to_stream("some-stream", &Default::default(), event_data)
    .await?;
1
2
3

Here we are appending events without checking if the stream exists or if the stream version matches the expected event version. See more advanced scenarios in appending events documentation.

Reading events

Finally, we can read events back from the some-stream stream.

events = client.get_stream("some-stream")

for event in events:
    # Doing something productive with the event
    print(event)
1
2
3
4
5
const events = client.readStream(STREAM_NAME, {
  direction: FORWARDS,
  fromRevision: START,
  maxCount: 10,
});
1
2
3
4
5
const events = client.readStream<TestEvent>(STREAM_NAME, {
  direction: FORWARDS,
  fromRevision: START,
  maxCount: 10,
});
1
2
3
4
5
ReadStreamOptions options = ReadStreamOptions.get()
        .forwards()
        .fromStart()
        .maxCount(10);

ReadResult result = client.readStream("some-stream", options)
        .get();
1
2
3
4
5
6
7
var result = client.ReadStreamAsync(
    Direction.Forwards,
    "some-stream",
    StreamPosition.Start,
    cancellationToken: cancellationToken
);

var events = await result.ToListAsync(cancellationToken);
1
2
3
4
5
6
7
8
stream, err := db.ReadStream(context.Background(), "some-stream", esdb.ReadStreamOptions{}, 10)

if err != nil {
    panic(err)
}

defer stream.Close()

for {
    event, err := stream.Recv()

    if errors.Is(err, io.EOF) {
        break
    }

    if err != nil {
        panic(err)
    }

    // Doing something productive with the event
    fmt.Println(event)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let options = ReadStreamOptions::default().max_count(10);
let mut stream = client.read_stream("some-stream", &options).await?;

while let Some(event) = stream.next().await? {
    // Doing something productive with the events.
}
1
2
3
4
5
6

When you read events from the stream, you get a collection of ResolvedEvent structures. The event payload is returned as a byte array and needs to be deserialized. See more advanced scenarios in reading events documentation.

Last Updated:
Contributors: Alexey Zimarev, Oskar Dudycz, Claude Devarenne, George Payne, George Payne, Mathew McLoughlin, staubichsauger