Dagger Ruby

CI Gem Version

A small, chainable Ruby client for Dagger. Use Ruby to run container builds, mount source directories and caches, pass secrets, and connect services through Dagger's GraphQL API.

This is a community-maintained client, not an official Dagger SDK. It deliberately covers a practical subset of the API instead of Dagger module code generation.

Requirements

  • Ruby 3.2 or newer
  • Dagger 0.21.8
  • Docker, Colima, or another container runtime supported by Dagger

Installation

Add the gem to your bundle:

bundle add dagger_ruby

Install the Dagger CLI if it is not already available.

Quick start

Create pipeline.rb:

require "dagger_ruby"

DaggerRuby.connection do |client|
  output = client.container
                 .from("alpine:3.22")
                 .with_exec(["echo", "hello from Dagger"])
                 .stdout

  puts output
end

Then run it normally:

bundle exec ruby pipeline.rb

Outside an existing Dagger session, DaggerRuby.connection restarts the script under dagger run. Inside a session, it connects directly. You can also make the session explicit:

dagger run -- bundle exec ruby pipeline.rb

Common operations

Mount the current project and a persistent Bundler cache:

DaggerRuby.connection do |client|
  source = client.host.directory(Dir.pwd, exclude: [".git", "vendor"])
  gems = client.cache_volume("bundle-cache")

  tests = client.container
                .from("ruby:4.0.6")
                .with_directory("/src", source)
                .with_mounted_cache("/usr/local/bundle", gems)
                .with_workdir("/src")
                .with_exec(["bundle", "install"])
                .with_exec(["bundle", "exec", "rake", "test"])

  puts tests.stdout
end

Pass a secret without placing its plaintext in the container definition:

DaggerRuby.connection do |client|
  token = client.set_secret("registry-token", ENV.fetch("REGISTRY_TOKEN"))

  result = client.container
                 .from("alpine:3.22")
                 .with_secret_variable("REGISTRY_TOKEN", token)
                 .with_exec(["sh", "-c", "test -n \"$REGISTRY_TOKEN\""])
                 .exit_code

  abort "secret was unavailable" unless result.zero?
end

Bind a service to another container:

DaggerRuby.connection do |client|
  redis = client.container
                .from("redis:8-alpine")
                .with_exposed_port(6379)
                .as_service

  pong = client.container
               .from("redis:8-alpine")
               .with_service_binding("redis", redis)
               .with_exec(["redis-cli", "-h", "redis", "ping"])
               .stdout

  puts pong
end

Clone a repository:

source = client.git("https://github.com/example/project.git")
               .branch("main")
               .tree

Authenticated Git and registry operations accept Dagger Secret objects; see the public methods in DaggerRuby::Client and DaggerRuby::Container for the available options.

Configuration

config = DaggerRuby::Config.new(
  timeout: 300,
  progress: :pretty,
  log_output: $stderr,
  runtime: :apple,
)

DaggerRuby.connection(config) do |client|
  progress = config.progress_reporter
  container = client.container.from("alpine:3.22").with_exec(["apk", "add", "git"])
  progress.step("[build] RUN apk add git") { container.sync }
end

Use progress: :pretty for numbered, coloured application steps with live container output. Use :logs for Dagger's unadorned streaming logs or :plain for the complete execution graph. The supported modes are :pretty, :auto, :plain, :tty, :dots, and :logs.

DAGGER_QUIET, DAGGER_SILENT, and DAGGER_PROGRESS can provide the same CLI preferences through the environment.

The client verifies the installed Dagger CLI before it starts a runner and then verifies the connected engine version. This matters for runtime drivers because the compatible CLI provisions the runner; merely pointing an older CLI at a newer engine image is not sufficient. Use runtime: :apple or runtime: :docker when more than one runtime is installed and automatic detection would be ambiguous. A custom runner can be selected with runner_host:.

Errors

Connection, transport, GraphQL, and invalid-query failures use dedicated error classes:

begin
  DaggerRuby.connection { |client| puts client.container.from("missing").stdout }
rescue DaggerRuby::ConnectionError, DaggerRuby::GraphQLError => error
  warn error.message
end

Compatibility

The current branch is tested against maintained Ruby releases and Dagger 0.21.8. Dagger's GraphQL schema can change between releases, so each supported engine update is validated by the live integration suite before release. Earlier Ruby and Dagger versions are not covered by the current compatibility contract.

Development

bin/setup
bin/ci

The fast suite stubs the GraphQL endpoint. Run the engine-backed contract tests with the supported Dagger version:

DAGGER_LIVE_TESTS=1 dagger run -- bundle exec ruby test/integration/test_dagger_engine.rb

Working examples live in examples/. Contribution and security guidance are in CONTRIBUTING.md and SECURITY.md.

License

Dagger Ruby is available under the MIT License.