Help us shape the future of Go! Take the 2026 Go Developer Survey

bedrock

package module
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2026 License: MIT Imports: 5 Imported by: 7

README

bedrock

Mentioned in Awesome Go Go Reference Go Report Card Coverage build

bedrock provides a minimal, modular and composable foundation for quickly developing more use case specific frameworks in Go.

Building custom frameworks with bedrock

One of the guiding principals for bedrock is to be composable. This principal comes from the experience gained from working with custom, tailor made frameworks which over their lifetime within an organization are unable to adapt to changing development and deployment patterns. Eventually, these frameworks are abandoned for new ones or completely rewritten to reflect the current state of the organization.

bedrock defines a small set of types and carefully chooses its opinions to balance composability and functionality, as much as it can. The result is, in fact, a framework that isn't necessarily designed for building services directly, but instead meant for building more custom, use case specific frameworks.

For example, bedrock could be used by your organizations platform engineering or framework team(s) to quickly develop internal frameworks which abstract over all of your organizations requirements e.g. OpenTelemetry, Logging, Authenticated endpoints, etc. Then, due to the high composibility of bedrock, any changes within your organization would then be very easy to adapt to within your internal framework.

Core Concepts

Builder
type Builder[T any] interface {
	Build(context.Context) (T, error)
}

Builder is a generic interface for constructing application components with context support. Builders can be composed using functional combinators like Map and Bind.

Runtime
type Runtime interface {
	Run(context.Context) error
}

Runtime is a simple abstraction over the execution of your specific application type e.g. HTTP server, gRPC server, background worker, etc.

Runner
type Runner[T Runtime] interface {
	Run(context.Context, Builder[T]) error
}

Runner executes application components built from Builders. Runners can be wrapped to add cross-cutting concerns like signal handling with NotifyOnSignal and panic recovery with RecoverPanics.

Configuration
package config

type Reader[T any] interface {
	Read(context.Context) (Value[T], error)
}

The config.Reader is arguably the most powerful abstraction defined in any of the bedrock packages. It abstracts over reading configuration values that may or may not be present, distinguishing between "not set" and "set to zero value." Readers can be composed using functional combinators like Or, Map, Bind, and Default.

Putting them altogether

Below is a tiny and simplistic example of all the core concepts of bedrock.

main.go
package main

import (
	"context"
	"log/slog"
	"os"
	"syscall"

	"github.com/z5labs/bedrock"
	"github.com/z5labs/bedrock/config"
)

func main() {
	os.Exit(run())
}

func run() int {
	// Create a runner with signal handling and panic recovery
	runner := bedrock.NotifyOnSignal(
		bedrock.RecoverPanics(
			bedrock.DefaultRunner[bedrock.Runtime](),
		),
		os.Interrupt,
		os.Kill,
		syscall.SIGTERM,
	)

	// Build and run the application
	err := runner.Run(
		context.Background(),
		bedrock.BuilderFunc[bedrock.Runtime](buildApp),
	)
	if err == nil {
		return 0
	}
	return 1
}

type myApp struct {
	log *slog.Logger
}

// buildApp constructs the application using functional config composition
func buildApp(ctx context.Context) (bedrock.Runtime, error) {
	// Read log level from environment with a default
	logLevelReader := config.Default(
		"INFO",
		config.Env("MIN_LOG_LEVEL"),
	)

	logLevel, err := config.Read(ctx, logLevelReader)
	if err != nil {
		return nil, err
	}

	// Parse the log level string
	var level slog.Level
	err = level.UnmarshalText([]byte(logLevel))
	if err != nil {
		return nil, err
	}

	return &myApp{
		log: slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
			Level: level,
		})),
	}, nil
}

// Run implements the bedrock.Runtime interface.
func (a *myApp) Run(ctx context.Context) error {
	// Do something here like:
	// - run an HTTP server
	// - start the AWS lambda runtime,
	// - run goroutines to consume from Kafka
	//   etc.

	a.log.InfoContext(ctx, "running my app")
	return nil
}

Built with bedrock

Documentation

Overview

Package bedrock provides a functional, composable framework for building and running applications.

The package is built around three core abstractions:

  • Builder[T]: A generic interface for constructing application components with context support
  • Runtime: An interface representing a runnable application component
  • Runner[T]: An interface for executing application components built from Builders

Functional Composition

Bedrock embraces functional programming patterns to enable flexible composition:

  • Map: Transform builder outputs using pure functions
  • Bind: Chain builders together, allowing the output of one to inform the construction of the next

These combinators allow you to build complex applications from simple, reusable components.

Basic Usage

Create a builder for your application component:

builder := bedrock.BuilderFunc[MyApp](func(ctx context.Context) (MyApp, error) {
    return MyApp{}, nil
})

Create a runtime by transforming the builder:

runtime := bedrock.Map(builder, func(app MyApp) (bedrock.Runtime, error) {
    return bedrock.RuntimeFunc(func(ctx context.Context) error {
        return app.Start(ctx)
    }), nil
})

Run the application with signal handling and panic recovery:

runner := bedrock.RecoverPanics(
    bedrock.NotifyOnSignal(
        bedrock.DefaultRunner[bedrock.Runtime](),
        os.Interrupt,
    ),
)
if err := runner.Run(context.Background(), runtime); err != nil {
    log.Fatal(err)
}
Example
buildRuntime := BuilderFunc[RuntimeFunc](func(ctx context.Context) (RuntimeFunc, error) {
	rt := func(ctx context.Context) error {
		fmt.Println("hello from runtime")
		return nil
	}

	return rt, nil
})

err := NotifyOnSignal(
	RecoverPanics(
		DefaultRunner[RuntimeFunc](),
	),
	os.Interrupt,
	os.Kill,
	syscall.SIGTERM,
).Run(
	context.Background(),
	buildRuntime,
)
if err != nil {
	fmt.Println(err)
	return
}
Output:
hello from runtime

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func MustBuild added in v0.21.0

func MustBuild[T any](ctx context.Context, builder Builder[T]) T

MustBuild builds the application component using the provided Builder.

Types

type Builder added in v0.21.0

type Builder[T any] interface {
	Build(context.Context) (T, error)
}

Builder is a generic interface for building application components.

func Bind added in v0.21.0

func Bind[A, B any](builder Builder[A], binder func(context.Context, A) Builder[B]) Builder[B]

Bind chains two Builders together, where the output of the first is used to create the second.

func BuilderOf added in v0.21.0

func BuilderOf[T any](value T) Builder[T]

BuilderOf creates a Builder that always returns the provided value.

func Map added in v0.21.0

func Map[A, B any](builder Builder[A], mapper func(context.Context, A) (B, error)) Builder[B]

Map transforms the output of a Builder using the provided mapper function.

func MemoizeBuilder added in v0.21.0

func MemoizeBuilder[T any](builder Builder[T]) Builder[T]

MemoizeBuilder wraps a Builder to cache its result after the first build. It is safe for concurrent use.

type BuilderFunc added in v0.21.0

type BuilderFunc[T any] func(context.Context) (T, error)

BuilderFunc is a function type that implements the Builder interface.

func (BuilderFunc[T]) Build added in v0.21.0

func (f BuilderFunc[T]) Build(ctx context.Context) (T, error)

Build implements the Builder interface for BuilderFunc.

type Runner added in v0.21.0

type Runner[T Runtime] interface {
	Run(context.Context, Builder[T]) error
}

Runner is a generic interface for running application components.

func DefaultRunner added in v0.21.0

func DefaultRunner[T Runtime]() Runner[T]

DefaultRunner returns a Runner that builds and runs the application component.

func NotifyOnSignal added in v0.21.0

func NotifyOnSignal[T Runtime](runner Runner[T], signals ...os.Signal) Runner[T]

NotifyOnSignal wraps a Runner to listen for specified OS signals and cancel the context when received.

func RecoverPanics added in v0.21.0

func RecoverPanics[T Runtime](runner Runner[T]) Runner[T]

RecoverPanics wraps a Runner to recover from panics during execution and return them as errors.

type RunnerFunc added in v0.21.0

type RunnerFunc[T Runtime] func(context.Context, Builder[T]) error

RunnerFunc is a function type that implements the Runner interface.

func (RunnerFunc[T]) Run added in v0.21.0

func (f RunnerFunc[T]) Run(ctx context.Context, builder Builder[T]) error

Run implements the Runner interface for RunnerFunc.

type Runtime

type Runtime interface {
	Run(context.Context) error
}

Runtime is an interface representing a runnable application component.

type RuntimeFunc added in v0.21.0

type RuntimeFunc func(context.Context) error

RuntimeFunc is a function type that implements the Runtime interface.

func (RuntimeFunc) Run added in v0.21.0

func (f RuntimeFunc) Run(ctx context.Context) error

Run implements the Runtime interface for RuntimeFunc.

Directories

Path Synopsis
circuit module
Package config provides a functional approach to reading and composing configuration values.
Package config provides a functional approach to reading and composing configuration values.
example
fit module
host module
internal
retry module
runtime
http
Package http provides HTTP server runtime functionality for bedrock applications.
Package http provides HTTP server runtime functionality for bedrock applications.
http/rest
Package rest provides a REST API builder with automatic OpenAPI v3 spec generation.
Package rest provides a REST API builder with automatic OpenAPI v3 spec generation.
otel
Package otel provides OpenTelemetry integration for bedrock applications.
Package otel provides OpenTelemetry integration for bedrock applications.
otel/noop
Package noop provides no-operation implementations of OpenTelemetry exporters for traces, metrics, and logs.
Package noop provides no-operation implementations of OpenTelemetry exporters for traces, metrics, and logs.
otel/otlp
Package otlp provides bedrock Builders for creating OpenTelemetry Protocol (OTLP) exporters.
Package otlp provides bedrock Builders for creating OpenTelemetry Protocol (OTLP) exporters.
otel/stdout
Package stdout provides bedrock builders for OpenTelemetry exporters that write telemetry data to an io.Writer.
Package stdout provides bedrock builders for OpenTelemetry exporters that write telemetry data to an io.Writer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL