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:
And all the util.go
files contain the same function:
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
- First, you need to create another module called
shared
and moveutil/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
- 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 theshared
module as a requirement in theaccount
app.go mod edit -replace=old[@v]=new[@v]
: Replace theshared
module version with the local path to theshared
module.
After running those commands, your go.mod
should look like this:
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:
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.