CLI tool
moshebe/gebug avatar
moshebe/gebug

Gebug writes the Dockerfile and compose file your Go container needs

Debug Dockerized Go applications better

631 stars17 forksGoApache-2.0

At a glance

What is it?
Gebug is a Go command line tool that generates the Docker and Docker Compose configuration for debugging a containerised Go application, either with hot reload or with the Delve debugger attached, and it hands you a YAML file to edit. The README is candid that there is no voodoo in it, which is exactly the point.
Who is it for?
Adopt Gebug if you run Go applications in containers and want a repeatable debugging setup with either hot reload or a Delve attach point, and you are willing to own the generated files. Do not adopt it if your pipeline is not Go, if you need multi-service orchestration, or if you want the tool to remain hands off, because the README invites you to edit the generated Dockerfile and compose files directly.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 112 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A generator for two files and a YAML contract

Gebug is described as a tool that makes debugging of Dockerized Go applications easy by enabling debugger and hot reload features, and the section titled How Does It Work is refreshingly blunt about the implementation. It says nothing special, no voodoo. Gebug just handles the Dockerfile and docker-compose configuration files generation with an easy to use command line utility.

That is the whole product, and it is a reasonable product. Getting a Go service running under Docker with a remote debugger attached is a small but fiddly job: the binary has to be built with optimisation and symbol removal disabled, the debugger has to listen on a port, that port has to be published, and the volume mounts have to line up so your editor's breakpoints match the source in the container. Gebug turns that into a config file and a generated Dockerfile.

The generated files land in a .gebug directory inside your project, and the README is explicit that they are yours to change. It says we are all programmers and I know you like to play with your toys, so feel free to edit any of those files in order to fit your use case. The only rule is that if you do edit them, you run gebug start --skip-generate so the next run does not override your changes.

That last point is the whole contract, and it is a good one: generation is a starting point, not a cage. The tool is aimed at Go developers who containerise their services, and it is a single binary written in Go, with the Apache 2.0 licence.

Six commands, and one that starts a browser

The command surface is small enough to take in at a glance, and the help output in the README shows it in full.

code
➜ gebug --help
Gebug helps you setup a fully suited debugging environment of Go application running inside a container.
It enables options like connecting with remote debugger and breakpoints inside the code or 
use hot-reload features which auto-build and run upon new change detected on the source code.

Usage:
  gebug [command]

Available Commands:
  clean       Clean Gebug stack
  destroy     Destroy the Gebug project
  help        Help about any command
  init        Initialize a Gebug project
  start       Start Gebug services
  ui          Start Gebug web UI
  version     Gebug's version

The lifecycle reads clearly. init creates the project configuration and generates the files, start brings the services up, clean clears the running stack, and destroy removes the Gebug project entirely. version reports the version.

The interesting command is ui, which starts a web interface for people who prefer a browser to a terminal or a YAML file. The Go dependency list backs that up: gin provides the HTTP server, with the gin contrib package, and the webui/ directory at the repository root is a separate frontend. The README section introducing it is cut off mid sentence, so the exact command is not spelled out there, and the web UI is the part of this tool you would want to read the current documentation for.

Two global flags exist as well. The verbose flag turns on verbose mode, and the workdir flag points at your Go application root directory, defaulting to the current directory. That workdir flag matters when you are running gebug from somewhere other than the project root, which is common in scripts and CI.

config.yaml is the part you will actually edit

The README documents the configuration fields in a table, and the defaults tell you a lot about how the tool is meant to be used.

The name field is the application or project name, with no default given. The output_binary defaults to /app, and it is described as the output binary artifact inside the runtime container. The build_command defaults to go build -o {{.output_binary}}, and the note is that you can reference other configuration fields, and that when the Debugger is enabled the flags -gcflags="all=-N -l" will be appended to the build command to stop compiler optimisation and symbol removal. The run_command defaults to the output binary path.

The runtime_image defaults to golang:1.23, described as the base Docker image for the runtime container. The debugger_enabled flag defaults to false, and it decides whether you run a remote debugger inside the container or just hot reload. The debugger_port defaults to 40000, and it is relevant only when debugger_enabled is set.

The expose_ports list defaults to empty and uses docker-compose port mapping syntax, for example 8080:8080. The README notes that you do not need to add the debugger listen port yourself, because it is added automatically, which is a small convenience that saves a class of misconfiguration.

The networks list defaults to empty and names docker external networks to join, and if no network is selected a new one is created. The environment list defaults to empty, with the syntax FOO=BAR for a literal value, or just FOO to take the variable from the host and pass it through.

So the configuration is a template, and every field has a default that produces a working hot reload setup. You only touch it when your project needs something the defaults do not cover.

The debugger path is a build flag and a published port

The mechanism behind the debugger support is worth spelling out, because it is the part that people tend to get wrong when they set this up by hand.

When debugger_enabled is set, the build command gets -gcflags="all=-N -l" appended. Those are the Go compiler flags that disable optimisation and stop the linker removing symbols, and without them a debugger cannot map your breakpoints back to source lines, because the binary has been optimised and stripped of the information the debugger needs.

That is why the flags cannot simply be a separate field. They have to be part of the build command, and because the build command is a template you can edit, the tool appends to whatever you configured rather than replacing it. It also means that if you write your own build command that already includes those flags, you will end up with them twice, which is harmless but worth knowing.

The other half is the port. The debugger listens on 40000 by default, and the expose_ports documentation states explicitly that you do not need to add it because it is auto-added. So the generated compose file publishes the debug port alongside whatever your application needs, and the container runs the debugger inside it while the application itself runs as usual.

The repository shows the IDE side too. The demo section includes a Goland Debugger recording and a Visual Studio Code Debugger recording, so the supported path is an IDE attaching to a remote debugger instance over the published port, with the source mounted so the file paths line up.

Hot reload, and the flag that stops Gebug overwriting you

The hot reload path is the default, because debugger_enabled defaults to false. The behaviour it provides is described in the help text as auto-build and run upon new change detected on the source code.

The point of a generated setup here is repetition. Writing the Dockerfile and compose file once by hand is fine; rewriting them every time you add a port, a volume or an environment variable is not, and a debug configuration that differs from your production configuration is a debugging session that lies to you. Gebug keeps the debug setup in one place, generated from one YAML file, so that the environment you debug in matches the one you ship in, and so that a colleague can reproduce it by running the same two commands.

The --skip-generate flag is the escape valve for when the generated files stop being good enough. The README's How Does It Work section says to feel free to edit any of those files to fit your use case, and then to make sure you run gebug start --skip-generate so the next run does not override your changes. That is a simple and honest arrangement, with one caveat: once you start editing, the YAML is no longer the single source of truth, and there is nothing in the tool that reconciles the two. You have to remember which state you are in.

There is also a clean-up story. The clean command clears the Gebug stack and destroy removes the project, and the repository's Makefile clean target removes the gebug binary and the .gebug directory as well, which is what you want when a config has drifted far enough that regenerating is cleaner than patching.

Installing it, and the version drift in the docs

Installation is two commands depending on your platform.

On Linux and macOS, Homebrew:

shell
brew install gebug

Or from source, for Linux, Windows, macOS or any other platform Go supports:

shell
go install github.com/moshebe/gebug@latest

The README attaches a version requirement to that second option, saying that if you have Go 1.16+ you can install the latest released version from source. But the Version Requirements section that follows asks for Go 1.24 or newer for building from source, and the go.mod in the repository declares go 1.25.0. The installation text is stale, and the go.mod is the thing the build actually enforces.

The other requirements are Docker 20.10 or newer and Docker Compose 2.0 or newer. That second one matters, because a v1 compose file is a different format and a different command, and the generated files are compose v2 style.

The upgrade path from v1.x is spelled out, and the v2.0 breaking changes are listed: Go 1.24 minimum instead of 1.16, a default runtime image of golang:1.23 instead of golang:1.20, a web UI rewrite on Vue 3 with Vite with Vue 2 removed, and a distroless base Docker image at about 30MB instead of about 1.5GB. The upgrade commands are:

bash
brew upgrade gebug
cd your-project
gebug destroy && gebug init  # Regenerates config with new defaults

That destroy and init pairing is the practical consequence of the v2 changes. The generated configuration is replaced with the new defaults, so anything you had customised in the old config is gone, and the README is not describing a migration path that preserves it.

A young tool with an uneven release history

The release history of gebug is short and lumpy, which is the honest signal about how new this is.

The tagged releases listed are v1.0.4 on 2023-06-02, v1.0.6 and v1.0.7 both on 2023-06-05, and the version in the README's upgrade section discusses v2.0 as the current breaking change. The last push was on 2026-07-03, and the default branch is master.

So the picture is a v1 line that shipped three patches in three days in June 2023, and a v2 that exists in the documentation and in the code but whose tag is not in the list of recent releases. The README's v2 upgrade instructions are written as though v2 is the thing you are moving to, which suggests the tag naming does not line up neatly with the release numbering. If you are pinning a version, check the tag list rather than assuming the semantic version in the docs matches a published artefact.

The repository itself is well organised for a project of this size. There is a Makefile with compile, build, test, vet, coverage, package, check and clean targets, where the test target runs the test cases with coverage and the vet target runs go vet, and the check target installs and runs staticcheck. There is a .goreleaser.yaml for release builds, a CHANGELOG.md, a CODE_OF_CONDUCT.md, a SECURITY.md, and the standard cmd/, pkg/ and version/ layout. The dependency list shows a sensible stack: cobra for the command line, viper-style YAML through yaml.v3, zap for logging, promptui for interactive selection, afero for a virtual filesystem, and a web UI served by gin.

The Apache 2.0 licence means you can fork it, vendor it, and change it without the copyleft obligation that GPL would impose, which matters for a tool that is likely to be modified by the teams who use it.

Editorial conclusion

Adopt Gebug if you run Go applications in containers and want a repeatable debugging setup with either hot reload or a Delve attach point, and you are willing to own the generated files. Do not adopt it if your pipeline is not Go, if you need multi-service orchestration, or if you want the tool to remain hands off, because the README invites you to edit the generated Dockerfile and compose files directly. Before you start, note the version drift in the documentation, since the installation section mentions Go 1.16 while the requirements section asks for Go 1.24 or newer, and the go.mod declares Go 1.25.0.

Frequently asked questions

How do I install gebug?

On Linux and macOS you can use Homebrew with `brew install gebug`. Otherwise install from source with `go install github.com/moshebe/gebug@latest`, which the README lists for Linux, Windows, macOS and any other platform Go supports.

What does gebug generate for my project?

It generates the Dockerfile and docker-compose configuration files for a debugging environment, and writes them under a .gebug directory in your project. The behaviour is driven by a config.yaml whose fields include the runtime image, build and run commands, exposed ports, networks, environment variables and the debugger settings.

How do I enable the Go debugger in gebug?

Set debugger_enabled in config.yaml and pick a debugger_port, which defaults to 40000. The build command then gets -gcflags="all=-N -l" appended to disable optimisation and symbol removal, and the debugger port is published automatically without adding it to expose_ports.

What happens if I edit the generated Docker files?

The README says to feel free to edit them to fit your use case, but to run `gebug start --skip-generate` so the next run does not override your changes. Without that flag, regenerating will replace your edits.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. moshebe/gebug on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/moshebe-gebug.svg)](https://hysenlabs.com/projects/moshebe-gebug)

Was this useful?