# How to Access Beads Storage and Issue Operations Using the Go API

> Access Beads storage and issue operations programmatically with the Go API. Learn to use methods like CreateIssue, AddDependency, and RunInTransaction for CRUD and atomic transactions.

- Repository: [Gas Town Hall/beads](https://github.com/gastownhall/beads)
- Tags: how-to-guide
- Published: 2026-04-27

---

**The Beads Go library exposes a `Storage` interface in [`internal/storage/storage.go`](https://github.com/gastownhall/beads/blob/main/internal/storage/storage.go) that provides CRUD operations, dependency management, and atomic transactions for issues through methods like `CreateIssue`, `AddDependency`, and `RunInTransaction`.**

The `gastownhall/beads` repository ships a native Go package (`github.com/steveyegge/beads`) that wraps the underlying Dolt storage layer. You can access Beads storage and issue operations using the Go API to build automation, CI pipelines, or custom workflows that manage issues directly from Go code without invoking the CLI.

## Opening a Beads Database Programmatically

Before executing operations, you must locate and open the database. The entry point is [`beads.go`](https://github.com/gastownhall/beads/blob/main/beads.go), which provides helper functions to discover the database path and initialize the storage layer.

Use `FindDatabasePath()` to walk up the directory tree searching for a `.beads/*.db` file, then pass the result to `Open()` to obtain a `Storage` instance:

```go
ctx := context.Background()
dbPath := beads.FindDatabasePath()
if dbPath == "" {
    log.Fatal("Beads DB not found – run `bd init` first")
}
store, err := beads.Open(ctx, dbPath)
if err != nil {
    log.Fatalf("open storage: %v", err)
}
defer store.Close()

```

The `Open` function returns a concrete implementation of the `Storage` interface defined in [`internal/storage/storage.go`](https://github.com/gastownhall/beads/blob/main/internal/storage/storage.go). This interface is the sole contract you need to import; it maps every method call directly to SQL operations against the embedded Dolt database.

## Creating and Modifying Issues

The `Storage` interface provides full CRUD capabilities for issues. Key methods include `CreateIssue`, `GetIssue`, `UpdateIssue`, `CloseIssue`, and `DeleteIssue`, all of which accept a `context.Context` and an **actor** string for auditability.

To create an issue programmatically, populate a `beads.Issue` struct (defined in [`internal/types/types.go`](https://github.com/gastownhall/beads/blob/main/internal/types/types.go)) and call `CreateIssue`:

```go
newIssue := &beads.Issue{
    Title:     "Programmatic demo issue",
    Status:    beads.StatusOpen,
    Priority:  2,
    IssueType: beads.TypeTask,
    CreatedAt: time.Now(),
    UpdatedAt: time.Now(),
}
if err := store.CreateIssue(ctx, newIssue, "go-demo"); err != nil {
    log.Fatalf("create issue: %v", err)
}

```

For bulk imports, use `CreateIssues` to insert multiple records in a single call, reducing round-trips to the storage layer.

## Managing Dependencies and Labels

Issue relationships are handled through the dependency subsystem. The methods `AddDependency`, `RemoveDependency`, `GetDependencies`, and `GetDependents` let you wire issues together using types like `DepBlocks` or `DepDiscoveredFrom`.

```go
dep := &beads.Dependency{
    IssueID:     newIssue.ID,
    DependsOnID: "bd-1",
    Type:        beads.DepDiscoveredFrom,
    CreatedAt:   time.Now(),
    CreatedBy:   "go-demo",
}
if err := store.AddDependency(ctx, dep, "go-demo"); err != nil {
    log.Printf("dependency add failed: %v\n", err)
}

```

For categorization, `AddLabel`, `RemoveLabel`, and `GetIssuesByLabel` allow you to tag issues and filter collections programmatically.

## Executing Atomic Workflows with Transactions

When you need to perform multiple operations atomically—such as creating an issue and immediately adding dependencies—use `RunInTransaction`. This method accepts a callback that receives a `Transaction` interface exposing the same methods as `Storage`, but guarantees that all calls within the callback commit together or rollback on error.

```go
err := store.RunInTransaction(ctx, "create-with-deps", func(tx beads.Transaction) error {
    if err := tx.CreateIssue(ctx, parent, "go-demo"); err != nil {
        return err
    }
    if err := tx.CreateIssue(ctx, child, "go-demo"); err != nil {
        return err
    }
    dep := &beads.Dependency{
        IssueID:     child.ID,
        DependsOnID: parent.ID,
        Type:        beads.DepBlocks,
        CreatedAt:   time.Now(),
        CreatedBy:   "go-demo",
    }
    return tx.AddDependency(ctx, dep, "go-demo")
})

```

According to the source code in [`internal/storage/storage.go`](https://github.com/gastownhall/beads/blob/main/internal/storage/storage.go), the `Transaction` interface supports `CreateIssue`, `UpdateIssue`, `AddDependency`, and other mutating methods, making it ideal for consistent issue graph updates.

## Querying Work Status and Statistics

The API includes specialized query methods for workflow automation. `GetReadyWork` returns open issues ready for scheduling, while `GetBlockedIssues` identifies items with unresolved dependencies.

```go
ready, err := store.GetReadyWork(ctx, beads.WorkFilter{
    Status: beads.StatusOpen,
    Limit:  10,
})
if err != nil {
    log.Fatalf("ready work: %v", err)
}
for _, i := range ready {
    fmt.Printf("- %s: %s (prio %d)\n", i.ID, i.Title, i.Priority)
}

```

For dashboarding or reporting, `GetStatistics` returns global counts including `TotalIssues`, `OpenIssues`, and `BlockedIssues` without loading full issue records.

## Summary

- **Locate and open** the database using `FindDatabasePath` and `Open` from [`beads.go`](https://github.com/gastownhall/beads/blob/main/beads.go) to obtain a `Storage` handle.
- **Perform CRUD operations** through the `Storage` interface methods like `CreateIssue`, `UpdateIssue`, and `CloseIssue` defined in [`internal/storage/storage.go`](https://github.com/gastownhall/beads/blob/main/internal/storage/storage.go).
- **Link issues** with `AddDependency` and categorize with `AddLabel` using types from [`internal/types/types.go`](https://github.com/gastownhall/beads/blob/main/internal/types/types.go).
- **Ensure atomicity** by wrapping multi-step workflows in `RunInTransaction` to prevent partial updates.
- **Query efficiently** using `GetReadyWork` for scheduling and `GetStatistics` for metrics.

## Frequently Asked Questions

### How do I find the Beads database path automatically?

Call `beads.FindDatabasePath()`, which traverses parent directories looking for a `.beads/*.db` file. If it returns an empty string, initialize a new database with `bd init` before attempting to open it.

### What is the difference between Storage and Transaction interfaces?

The `Storage` interface provides standalone methods that auto-commit, while the `Transaction` interface (accessed via `RunInTransaction`) groups multiple operations into a single atomic unit. If any step in the transaction callback returns an error, the entire batch rolls back.

### Can I create multiple issues at once using the Go API?

Yes. Use the `CreateIssues` method on the `Storage` interface to batch insert issues in one call. This is more efficient than calling `CreateIssue` repeatedly when importing large datasets.

### Where are the core data structures like Issue and Dependency defined?

The core types—including `Issue`, `Dependency`, `Comment`, and `Statistics`—are defined in [`internal/types/types.go`](https://github.com/gastownhall/beads/blob/main/internal/types/types.go). These structs are used throughout the public API in [`beads.go`](https://github.com/gastownhall/beads/blob/main/beads.go) and the storage layer.