# Quickstart

This quickstart gets a first command running with **ArchitectureKit** in a few minutes: you start **EventSourcingDB** with **Docker**, define a **command**, an **event**, and the **state** to decide on, and execute the command. It uses a **temporary setup for development and testing** – for everything else, see the links at the end.

## Before You Begin

You need **Go 1.27.1** or later, which ArchitectureKit requires, and **Docker** to run EventSourcingDB.

> **Compatibility**
>
> ArchitectureKit 2.0 runs with **EventSourcingDB 1.1** and later.

## Starting EventSourcingDB

ArchitectureKit stores its events in EventSourcingDB. Start it with the following command. On the first start, Docker downloads the image:

```shell
docker run -it -p 3000:3000 \
  thenativeweb/eventsourcingdb run \
  --api-token=secret \
  --data-directory-temporary \
  --http-enabled \
  --https-enabled=false
```

This starts EventSourcingDB on port `3000`, with the API token `secret`, a **temporary data directory** that is cleaned up on shutdown, and unencrypted HTTP.

> **For Development and Testing Only**
>
> These settings simplify the setup but are not secure for production. For production-ready configurations, see **[Running EventSourcingDB](/docs/eventsourcingdb/running-eventsourcingdb)**.

## Creating a Module

In a second terminal, create a Go module, and add ArchitectureKit and the **[client SDK for Go](/docs/eventsourcingdb/sdks/go)**:

*(Changed in 2.0)*

```shell
mkdir library
cd library
go mod init library
go get github.com/thenativeweb/architecturekit-golang/v2/architecturekit github.com/thenativeweb/eventsourcingdb-client-golang/v2/eventsourcingdb
```

If you are upgrading from version 1 of ArchitectureKit, see **[Upgrading From Version 1](/docs/architecturekit/v2.0/upgrading-from-version-1)**.

## Defining a Command, an Event, and the State

Create a file `main.go`. A **command** describes what someone wants to do, an **event** describes what has happened, and the **state** holds what a command needs to decide on. The example acquires a book for a library:

*(Changed in 2.0)*

```go
package main

import (
  "context"
  "fmt"
  "log"
  "net/url"

  "github.com/thenativeweb/architecturekit-golang/v2/architecturekit"
  "github.com/thenativeweb/eventsourcingdb-client-golang/v2/eventsourcingdb"
)

type AcquireBook struct {
  BookID string
  Title  string
  Author string
  ISBN   string
}

func (c AcquireBook) Subject() string {
  return "/books/" + c.BookID
}

func (c AcquireBook) Preconditions() []architecturekit.Precondition {
  return []architecturekit.Precondition{
    architecturekit.OnStateRead(),
  }
}

type BookAcquired struct {
  Title  string `json:"title"`
  Author string `json:"author"`
  ISBN   string `json:"isbn"`
}

func (BookAcquired) EventType() string {
  return "io.eventsourcingdb.library.book-acquired"
}

type Book struct {
  IsAcquired bool
}

var bookState = architecturekit.NewState(Book{}).
  Evolve(func(book Book, event BookAcquired) Book {
    book.IsAcquired = true
    return book
  })
```

The command names the subject it acts on, and its precondition `OnStateRead` makes sure that its events are only written if nothing has been written to that subject since the state was read. The event names its event type, the kit derives the JSON schema of its data from the struct, and the state evolves from every `BookAcquired` event. For details, see **[Defining Commands](/docs/architecturekit/v2.0/defining-commands)**, **[Defining Events](/docs/architecturekit/v2.0/defining-events)**, and **[Defining State](/docs/architecturekit/v2.0/defining-state)**.

## Deciding on the Command

A **decider** connects the state with the decision made on it. Create it with the `NewDecider` function, from the state and a function that receives the command and the current state, and returns the events to write, or an error to reject the command. Add it to `main.go`:

```go
var acquireBook = architecturekit.NewDecider(bookState,
  func(ctx context.Context, cmd AcquireBook, book Book) ([]architecturekit.Event, error) {
    if book.IsAcquired {
      return nil, architecturekit.NewDomainError("book %s has already been acquired", cmd.BookID)
    }

    return []architecturekit.Event{
      BookAcquired{
        Title:  cmd.Title,
        Author: cmd.Author,
        ISBN:   cmd.ISBN,
      },
    }, nil
  })
```

For details, see **[Making Decisions](/docs/architecturekit/v2.0/making-decisions)**.

## Executing the Command

Finally, create a client and a store, register the schema of the event, and execute the command. Add the `main` function to `main.go`:

```go
func main() {
  baseURL, err := url.Parse("http://localhost:3000")
  if err != nil {
    log.Fatal(err)
  }

  client, err := eventsourcingdb.NewClient(baseURL, "secret")
  if err != nil {
    log.Fatal(err)
  }

  store := architecturekit.NewStore(client, "https://library.eventsourcingdb.io")

  err = architecturekit.RegisterSchemas(context.TODO(), store, bookState.Schemas())
  if err != nil {
    log.Fatal(err)
  }

  writtenEvents, err := architecturekit.Execute(
    context.TODO(),
    store,
    acquireBook,
    AcquireBook{
      BookID: "42",
      Title:  "2001 – A Space Odyssey",
      Author: "Arthur C. Clarke",
      ISBN:   "978-0756906788",
    },
  )
  if err != nil {
    log.Fatal(err)
  }

  for _, event := range writtenEvents {
    fmt.Println(event.ID, event.Type, event.Subject)
  }
}
```

`NewStore` creates the store from the client and the source to use for all events you write, and returns a `*Store`, which reads and writes the events of all commands (see **[Creating a Store](/docs/architecturekit/v2.0/creating-a-store)**). `RegisterSchemas` registers the schema of the event with the database, which from then on rejects events that do not match it. `Execute` reads the events of the book's subject, evolves the state from them, calls the decider, and writes the events it returns.

*Note that calling `NewStore` with `nil` as the client, or as one of the options, panics.*

Run the program:

```shell
go run .
```

It prints the ID, the type, and the subject of the written event:

```
0 io.eventsourcingdb.library.book-acquired /books/42
```

Run it again. This time, the state shows that the book has already been acquired, so the decider rejects the command, and nothing is written:

```
2026/10/07 08:22:39 book 42 has already been acquired
exit status 1
```

## Shutting Down

Press Ctrl+C in the first terminal to shut down EventSourcingDB. Since the data directory is temporary, the event is gone afterwards.

## Next Steps

- **[First Steps with ArchitectureKit](/learn/tutorials/first-steps-with-architecturekit)** builds a small library step by step, up to a tested HTTP API.
- **[Using Preconditions](/docs/architecturekit/v2.0/using-preconditions)** shows how to prevent duplicates and guard against concurrent changes, even when two commands run at the same time.
- **[Projections](/docs/architecturekit/v2.0/projections)** and **[Defining Queries](/docs/architecturekit/v2.0/defining-queries)** cover the reading side, from events to the answers of queries.
- **[Testing Deciders](/docs/architecturekit/v2.0/testing-deciders)** shows how to test the decider without a database.
- **[Setting Up an HTTP API](/docs/architecturekit/v2.0/setting-up-an-http-api)** exposes commands and queries over HTTP.

## Further Resources

- **Repository**: **[thenativeweb/architecturekit-golang](https://github.com/thenativeweb/architecturekit-golang)**
- *(Changed in 2.0)* **Registry**: **[pkg.go.dev](https://pkg.go.dev/github.com/thenativeweb/architecturekit-golang/v2)**, with the packages **[architecturekit](https://pkg.go.dev/github.com/thenativeweb/architecturekit-golang/v2/architecturekit)**, **[httpapi](https://pkg.go.dev/github.com/thenativeweb/architecturekit-golang/v2/architecturekit/httpapi)**, **[query](https://pkg.go.dev/github.com/thenativeweb/architecturekit-golang/v2/architecturekit/query)**, **[architecturekittest](https://pkg.go.dev/github.com/thenativeweb/architecturekit-golang/v2/architecturekit/architecturekittest)**, and **[dbtest](https://pkg.go.dev/github.com/thenativeweb/architecturekit-golang/v2/architecturekit/architecturekittest/dbtest)**
- **License (MIT)**: **[License file](https://github.com/thenativeweb/architecturekit-golang/blob/main/LICENSE.md)**
- **Issue tracker**: **[GitHub Issues](https://github.com/thenativeweb/architecturekit-golang/issues)**
