Library / SDK
ondrajz/go-callvis avatar
ondrajz/go-callvis

go-callvis: rendering a Go call graph as an interactive SVG map

Visualize call graph of a Go program using Graphviz

6,526 stars428 forksGoMIT

At a glance

What is it?
go-callvis runs pointer analysis over a Go program and turns the resulting call graph into Graphviz output. It is aimed at developers who need to read unfamiliar or large codebases, and it works best when you scope the graph before it becomes a hairball.
Who is it for?
Adopt go-callvis if you regularly need a visual overview of a Go program's call relations and are willing to narrow the graph with -focus, -limit and -nostd before rendering. Skip it if you want a dependency graph of modules rather than calls between functions, or if you need a maintained web application: the README says the interactive tool was published as a separate project, goexplorer.
Can I use it commercially?
Yes. MIT 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?
Activity is slowing. The repository last received commits 6 months 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 September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What go-callvis produces that a directory listing cannot

Reading a Go repository top down tells you which packages exist. It does not tell you which functions actually call which other functions, and in a program that uses interfaces and function values, the textual answer is spread across many files. go-callvis exists to close that gap. The README states its purpose plainly: to provide developers with a visual overview of a Go program using data from the call graph and its relations with packages and types. The stated audience is people working in larger projects where the complexity of the code is much higher, or people trying to understand code written by somebody else.

The output is not a module dependency diagram. It is a graph whose nodes are functions and methods, grouped by package or by receiver type, with edges for calls. That distinction matters when you pick a tool: a package-level graph tells you that net/http is imported, while a call graph tells you which of your handlers reach into it and through which functions. The README lists the practical controls that follow from this model: focus a specific package, group functions by package, group methods by receiver type, filter packages to import path prefixes, ignore calls to and from the standard library, and omit various types of function calls.

How the call graph is built and rendered

The pipeline has two stages. First, go-callvis runs pointer analysis to construct the call graph of the program, using the golang.org/x/tools pointer package. Second, it emits that data in dot format, which Graphviz tools can render. The repository layout matches this split: analysis.go, dot.go and output.go sit at the top level, with dot_cgo.go and dot_nocgo.go as build-tag variants for the rendering path.

The -algo flag selects the analysis algorithm and accepts static, cha, rta or vta, defaulting to static. This is the part of the tool worth understanding before you trust a picture. Static analysis resolves calls that are syntactically obvious; the more precise algorithms reason about which concrete types can flow to an interface method, and they cost more time and memory. The README does not explain the trade-offs between the four options beyond naming them, so treat the default as a starting point rather than a recommendation.

The dot file itself carries meaning through styling, and the README documents the legend. Packages and types are coloured: focused is blue, stdlib is green, other is yellow. Functions and methods differ by border: exported is bold, unexported is normal, anonymous is dotted. Calls encode three independent facts at once. Internal calls are black and external calls brown; static calls are solid lines and dynamic calls dashed; regular arrows are simple, concurrent calls carry a circle, deferred calls carry a diamond. Once you know the legend, a dashed brown line with a circle is readable at a glance as an indirect, cross-package, concurrent call.

Installing go-callvis and rendering a first graph

The README lists two requirements: Go 1.19 or newer, and Graphviz, which it marks as optional and required only with the -graphviz flag. The go.mod file in the repository declares go 1.22.0 with a toolchain of go1.23.1, so the README's minimum is looser than what the module itself specifies.

The documented install path is a go install against the module path:

bash
go install github.com/ofabry/go-callvis@latest

The README also gives a development variant, go install github.com/ofabry/go-callvis@master, and an alternative that clones the repository and runs make install. Note the module path in go.mod is github.com/ofabry/go-callvis even though the repository lives under ondrajz; use the path the README prints, not the repository URL.

Running the binary with a target package and no output file starts the interactive viewer. The README says the HTTP server listens on http://localhost:7878/ by default:

bash
go-callvis <target package>

The viewer serves SVG images of focused packages, and clicking a package switches the focus. The -http flag changes the listen address, and -skipbrowser stops the browser from opening automatically. For a single artifact instead of a server, pass -file:

bash
go-callvis -file=<file path>

That command writes one file instead of starting the server. The -format flag accepts svg, png, jpg and others, defaulting to svg. If the output is empty or the tool reports nothing to draw, the usual cause is that -focus or -limit excluded everything; widen the prefix before assuming the analysis failed.

Where the output stops being useful

The main failure mode is scale. A call graph of a whole program with no filters is a dense graph, and the README's own options exist because of it: -limit restricts package paths to given prefixes, -ignore drops paths containing given prefixes, -include keeps paths with given prefixes, -nostd removes standard library calls, and -nointer omits calls to unexported functions. If you render without them, expect a file that takes a long time to lay out and is hard to read even when it finishes. The layout flags, -minlen, -nodesep and -rankdir, change spacing and direction but do not reduce the amount of information.

The second limitation is analytical, not visual. The graph shows what the chosen algorithm believes the program calls. With -algo=static, calls through interfaces and function values may be resolved conservatively or missed, and the README does not document accuracy per algorithm. A picture that omits a dynamic call looks just as authoritative as one that includes it, which is the real risk: you cannot tell from the rendering alone how much was resolved.

Third, this is the wrong tool for questions about modules. If you want to know which modules a build pulls in, or which packages import which, a call graph answers a different question and the extra node detail is noise. It is also the wrong tool for runtime behaviour: nothing here records actual execution, argument values or timing, only static call relations.

go-callvis compared with go tool callgraph and pprof graphs

The closest alternative in the Go toolchain is the call graph output produced by golang.org/x/tools, which go-callvis itself depends on. That route gives you the graph data, typically as text or dot, without the presentation layer. The difference is what you get for free: go-callvis adds the colour and border conventions for focused, stdlib and other packages, the grouping by package or receiver type, and the interactive viewer that re-renders a focused package as SVG on request. If you only need the raw edges, the underlying tool is enough; if you need to hand a readable diagram to someone else, the styling is the product.

The other comparison people reach for is a runtime profile graph, such as the call graph view in pprof. Those two answer different questions. A pprof graph is built from samples collected while the program ran, so its edges carry weight and cost; a go-callvis graph is built by static analysis before anything executes, so it can show paths that never run in practice and cannot show how often a path is taken. Use the static graph to find structure and the profile graph to find expense.

A third option is a general code visualizer that indexes symbols and references across languages. Those tend to be editor-integrated and reference-based, which is easier to query but does not model Go's interface dispatch the way pointer analysis does. For Go specifically, the analysis step is the part that is hard to replace.

Maintenance, the goexplorer split, and the MIT licence

The repository is not archived, and the last push was on 2026-03-30. Release history is uneven: v0.7.1 on 2025-01-02, v0.7.0 on 2023-05-08, and v0.6.1 on 2020-08-05. The gap between v0.6.1 and v0.7.0 is roughly three years, so a long pause between releases is normal for this project and not by itself a sign that it has been abandoned. The README also points to a Slack channel, #go-callvis on gophers.slack.com, and to a TODO project board for contributors.

One roadmap item has already left the repository. The README states that the interactive tool described in the roadmap has been published as a separate project called goexplorer, whose stated goal is a web app that stores call graph data locally and provides quick access to call graphs for any package in your dependency tree. That means the web-application ambitions of go-callvis live elsewhere now, and the CLI in this repository should be judged on the CLI alone.

The licence is MIT, which the repository carries as a top-level LICENSE file. MIT is permissive and imposes no copyleft obligation on your own code, but this is a description of the licence identifier and not legal advice; if you redistribute the binary or embed it in a product, read the LICENSE file in the repository and handle attribution accordingly. On upgrade cost, the practical risk is the analysis dependency rather than the CLI surface: go.mod pins golang.org/x/tools v0.28.0, and that library is where pointer analysis lives, so behaviour can shift when it moves even if no flag changes.

Editorial conclusion

Adopt go-callvis if you regularly need a visual overview of a Go program's call relations and are willing to narrow the graph with -focus, -limit and -nostd before rendering. Skip it if you want a dependency graph of modules rather than calls between functions, or if you need a maintained web application: the README says the interactive tool was published as a separate project, goexplorer. Before relying on it, run go-callvis -h on your installed binary and compare the option list with the README, then render one small package with -file to confirm the output format you need is produced.

Frequently asked questions

Is go get deprecated for installing tools like go-callvis?

The README does not use go get. It gives go install github.com/ofabry/go-callvis@latest for the latest release and go install github.com/ofabry/go-callvis@master for the development version, plus cloning the repository and running make install.

How can I visualise Go code?

The README describes go-callvis as a development tool that visualises the call graph of a Go program. It runs pointer analysis to construct the call graph and generates output in dot format, which Graphviz tools can render, either as a static file via -file or through an interactive viewer that serves SVG images of focused packages.

Is Go a programming language?

Yes, and go-callvis is written in Go. The README lists Go 1.19 or newer as a requirement, and the repository's go.mod declares module github.com/ofabry/go-callvis with go 1.22.0 and a toolchain of go1.23.1.

Official sources

  1. License: MIT
  2. ondrajz/go-callvis on GitHub
  3. Project website
  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/ondrajz-go-callvis.svg)](https://hysenlabs.com/projects/ondrajz-go-callvis)