Hackernoon logoGo repo structure by@matzhouse

Go repo structure

Author profile picture

@matzhouseMat Evans

Photo by Sanwal Deen on Unsplash

I’ve changed the way I structure Go repos a few times over the last few years, so here are my current views and what I used to do compared to now.

First things first

Like most people, when I started looking at Go back in 2013 my first repos were very flat, and very simple. There was no regard for any form of useful layout. The issues I found with this were

  • Single package/app namespace. Says it all really.
  • If it was a runnable program and not a package, then any useful code couldn’t be used in other apps and it was all under main.
  • The amount of files can get big fast.

Packages are useful

I’ve found it pretty useful to almost always start things as a package. One, this forces you to at least think about how the code should look from outside of the package, and two, it’s really easy to expose the useful parts of the code for use in other things.

As for how to do this, I have tried a few ways and settled on this.

  • The main package sites in the root of the repo.
  • Any other packages sit under a pkg folder

That’s it.

For example…


Where’s the binary?

By starting with a package we also have to separate out our binary. Using a cmd directory has become the idiomatic way in Go. This has some subtle advantages.

  • We can have multiple binaries for different things — just add a new folder and code away.
  • We get to use the package as a package giving us a different view point of the code.

Anything else?

There are a few other things which might become more prevalent over time.

The first is plugins. These are pre built packages that can be imported into an process at runtime. I’m not sure if there are any idioms appearing but I would be tempted to make a plugin directory at the root of the package if there are specific sub packages that will be plugins.

The second is the internal folder — this is worth knowing about. It’s pretty simple to be honest, it separates code out from the package so that it’s only allowed to be called from the package scope — that is code already in the package.

Don’t take my word for it

This layout might not work for everyone. There might be better ways. Let me know what you think — either on here and let everyone see your ideas or on twitter at matzhouse

If this was useful then why not hit the heart :)


The Noonification banner

Subscribe to get your daily round-up of top tech stories!