blog

Go Share Your Packages

26 Jul 2024

Sometimes in life, we need to share things. It might be useful, it might not. But when you’re working with a monorepo, sharing code between apps is a must. Like, the account app might need a function to combine user data with profile data, and the payment app might need the same function to merge user data with order data. So, let me show you how to share a package between multiple apps in your monorepo.

Let’s Get Started

Let’s say you have a monorepo that looks like this:

app
account
util
util.go
go.mod
main.go
payment
util
util.go
go.mod
main.go

And all the util.go files contain the same function:

util.go
package util

func MergeMaps[M ~map[K]V, K comparable, V any](m ...M) M {
	if len(m) <= 1 {
		return m[0]
	}

	dest := make(M)
	for _, v := range m {
		if v == nil {
			continue
		}
		for k, v := range v {
			dest[k] = v
		}
	}
	return dest
}

You have the exact same code scattered across your monorepo. If there’s a bug in that code, you’d need to update each util.go file individually. But there’s a better way to do this. You can move that code into a single location that all apps can access. Now, let me show you how to share a package between multiple apps in your monorepo.

Shifting Things Around

  1. First, you need to create another module called shared and move util/util.go into it:
mkdir shared
cd shared
go mod init example.com/shared
mv ../account/util .
rm -rf ../payment/util # we don't need it anymore
app
account
go.mod
main.go
payment
go.mod
main.go
shared
util
util.go
go.mod
  1. Next, run these commands to update the module dependencies:
cd ../account
go mod edit -require=example.com/[email protected]
go mod edit -replace=example.com/[email protected]=../shared
  • go mod edit -require=path@version: Add the shared module as a requirement in the account app.
  • go mod edit -replace=old[@v]=new[@v]: Replace the shared module version with the local path to the shared module.

After running those commands, your go.mod should look like this:

app/account/go.mod
module example.com/account

go 1.22.4

require example.com/shared v0.0.0

replace example.com/shared v0.0.0 => ../shared

Now, repeat step 2 for payment.

Making the Code Work

Now you can import your shared package like this:

app/account/main.go
package main

import (
	"example.com/account/util"
	"example.com/shared/util"
)

func main() {
	user := map[string]interface{}{
		"firstName": "John",
		"lastName":  "Doe",
	}
	profile := map[string]interface{}{
		"age": 2,
	}
	userWithAge := util.MergeMaps(user, profile)
}

And that’s it! By moving your shared code to a common location and updating your imports, you’ve made it easier to maintain and reuse your code across different apps. No more juggling the same function in multiple places—now you’ve got a clean, efficient setup. If you find yourself needing to update or fix something, you only have to do it in one place. It’s a small change that can make a big difference in keeping your monorepo organized and manageable.

Go
Monorepo