
Golang Modules are a game-changer for developers, allowing for more efficient and organized code management.
With Golang Modules, you can now easily manage dependencies and versioning, which was a major pain point in the past.
The introduction of Go Modules in Go 1.11 marked a significant shift in the way we write Go code, making it more modular and scalable.
This new approach replaces the traditional GOPATH-based workflow, which was often cumbersome and prone to errors.
By using Go Modules, you can now create a single, self-contained module for your project, making it easier to share and reuse code.
Curious to learn more? Check out: Golang Go
Creating and Managing Modules
Creating a new module is straightforward. Create a new, empty directory outside of $GOPATH/src, and then create a new source file, hello.go. Writing a test in hello_test.go is also a good idea.
To make the current directory the root of a module, use the go mod init command. This will write a go.mod file, which only appears in the root of the module. Packages in subdirectories will have import paths consisting of the module path plus the path to the subdirectory.
The go mod init command is essential for creating a module, and it's what allows the go command to know the import path for the current directory. Without it, the go command will make up a fake import path based on the directory name.
Explore further: Wireless Internet Module
Creating A New

Creating a new module is a straightforward process. Create a new, empty directory somewhere outside $GOPATH/src, and then create a new source file, hello.go.
To write a test, create a new file, hello_test.go. At this point, the directory contains a package, but not a module, because there is no go.mod file.
If you run go test now, you'll see a fake import path based on the directory name. To make the current directory the root of a module, use go mod init and try go test again.
The go mod init command will write a go.mod file. This file only appears in the root of the module, and packages in subdirectories will have import paths consisting of the module path plus the path to the subdirectory.
For example, if you create a subdirectory world, you wouldn't need to run go mod init there. The package would automatically be recognized as part of the example.com/hello module, with import path example.com/hello/world.
Here are the steps to create a new module:
- Create a new, empty directory outside $GOPATH/src
- Create a new source file, hello.go
- Create a new test file, hello_test.go
- Run go mod init to make the current directory the root of a module
- Run go test to see the results
Paths
A module path is the canonical name for a module, declared with the module directive in the module's go.mod file. It describes what the module does and where to find it.
A module path typically consists of a repository root path, a directory within the repository, and a major version suffix, if the module is released at major version 2 or higher. For example, golang.org/x/net is the repository root path for the module of the same name.
The repository root path is the portion of the module path that corresponds to the root directory of the version control repository where the module is developed. Most modules are defined in their repository's root directory, so this is usually the entire path.
If the module is not defined in the repository's root directory, the module subdirectory is the part of the module path that names the directory, not including the major version suffix. This also serves as a prefix for semantic version tags.
You might like: Lora Wireless Module

Here are the rules for a module path:
- The path must consist of one or more path elements separated by slashes (/, U+002F). It must not begin or end with a slash.
- Each path element is a non-empty string made of up ASCII letters, ASCII digits, and limited ASCII punctuation (-, ., _, and ~).
- A path element may not begin or end with a dot (., U+002E).
- The element prefix up to the first dot must not be a reserved file name on Windows, regardless of case (CON, com1, NuL, and so on).
- The element prefix up to the first dot must not end with a tilde followed by one or more digits (like EXAMPL~1.COM).
If a module path appears in a require directive and is not replaced, or if the module path appears on the right side of a replace directive, the go command may need to download modules with that path. In this case, the leading path element must contain only lower-case ASCII letters, ASCII digits, dots (., U+002E), and dashes (-, U+002D); it must contain at least one dot and cannot start with a dash.
Here's an interesting read: Switch Case Golang
Minimal Selection (MVS)
Minimal Selection (MVS) is a clever algorithm used by Go to select the right versions of modules for building packages. It's a crucial part of the module management process.
MVS operates on a directed graph of modules, which is specified with go.mod files. Each vertex in the graph represents a module version, and each edge represents a minimum required version of a dependency.
The graph may be modified by exclude and replace directives in the go.mod file(s) of the main module(s) and by replace directives in the go.work file. This ensures that the build list is always up-to-date and accurate.
Discover more: Golang Mod Update
MVS starts at the main modules, which are special vertices in the graph that have no version. From there, it traverses the graph, tracking the highest required version of each module.
At the end of the traversal, the highest required versions comprise the build list, which is the minimum set of versions that satisfy all requirements. This build list can be inspected with the command go list -m all.
The build list is not saved in a "lock" file, which means it's not persisted across different versions of dependencies. Instead, MVS is used to compute it at the beginning of every module-aware command.
For example, consider a graph where the main module requires module A at version 1.2 or higher and module B at version 1.2 or higher. MVS would visit and load the go.mod file for each of the highlighted module versions, and return a build list containing the bolded versions: A 1.2, B 1.2, C 1.4, and D 1.2.
MVS is deterministic, which means the build list doesn't change when new versions of dependencies are released. This ensures that the build list is always consistent and reliable.
Broaden your view: Golang vs Go
Why

The "why" of Go modules is an important one. Go mod why shows a shortest path in the import graph from the main module to each of the listed packages.
This command is useful for understanding how your packages are connected and what dependencies they have. The output is a sequence of stanzas, one for each package or module named on the command line, separated by blank lines.
Each stanza begins with a comment line giving the target package or module, followed by a path through the import graph, one package per line. If the package or module is not referenced from the main module, the stanza will display a single parenthesized note indicating that fact.
The -m flag causes go mod why to treat its arguments as a list of modules. This means it will print a path to any package in each of the modules.
Using the -m flag can be particularly helpful when working with large projects that have many modules. It allows you to see how all the different packages are connected and what dependencies they have.
The -vendor flag causes go mod why to ignore imports in tests of packages outside the main module. This can be useful when you're trying to simplify the import graph and focus on the most important dependencies.
You might enjoy: Golang Mod Install
-m

The -m flag is a useful tool for getting detailed information about the modules used in your Go executable. It causes go version to print a table with tab-separated columns showing the embedded module version information.
You can obtain the same information from runtime/debug.ReadBuildInfo, but using the -m flag is often a quicker and more straightforward approach. The format of the table may change in the future, so it's good to be aware of this possibility.
The table will include the following columns: path, mod, dep, and =>. The path column shows the path of the main package used to build the executable.
Here's a breakdown of the other columns:
- mod: the module containing the main package, with columns for the module path, version, and sum.
- dep: a module that provided one or more packages linked into the executable, with the same format as mod.
- =>: a replacement for the module on the previous line, which can be a local directory or a module version.
If the replacement is a local directory, only the directory path is listed. If it's a module version, the path, version, and sum are listed, as with mod and dep. A replaced module has no sum.
Dependency Management
Dependency management is a crucial aspect of working with Go modules. The go command resolves imports by using the specific dependency module versions listed in go.mod, and automatically looks up the module containing that package and adds it to go.mod, using the latest version.
Intriguing read: Golang Mod
Go modules maintain a file named go.sum containing the expected cryptographic hashes of the content of specific module versions, ensuring that future downloads of these modules retrieve the same bits as the first download. This prevents modules from changing unexpectedly, whether for malicious, accidental, or other reasons.
Adding a new dependency is quick and easy with the go command, but it's not without cost – your module now depends on the new dependency in critical areas such as correctness, security, and proper licensing.
You might like: Azure Verified Modules
Upgrading Dependencies
Upgrading dependencies is an essential part of maintaining a healthy module graph. You can use the go list -m all command to see which dependencies you're using and their versions.
When you want to upgrade a dependency, you can use the go get command with an explicit version tag, such as @v0.3.0, to upgrade to the latest tagged version. This ensures that you're using a specific version of the dependency.
Additional reading: Golang Test Command
Upgrading to the latest version isn't always the best option, as it may introduce compatibility issues. For example, upgrading the rsc.io/sampler minor version to v1.99.99 caused a test failure due to incompatibility. In this case, downgrading to v1.3.1 or finding a different version that works for you might be a better solution.
The go command allows you to specify an explicit version for each dependency, which can help you manage upgrades more effectively. You can use the go get command with an explicit version, such as go get rsc.io/[email protected], to upgrade to a specific version of a dependency.
When upgrading a dependency, it's essential to test your code thoroughly to ensure that everything still works as expected. If you encounter issues, you can use the go list -m all command to see which dependencies you're using and their versions, and then try to identify the root cause of the problem.
In some cases, upgrading to a new major version of a dependency may require significant changes to your code. For example, upgrading from rsc.io/quote to rsc.io/quote/v3 may require updating your use of quote.Hello() to use quoteV3.HelloV3(). Be prepared to make these changes and test your code thoroughly to ensure that everything works as expected.
Curious to learn more? Check out: Golang Source
Exclude

Exclusions can be specified in the main module's go.mod file using an exclude directive. This directive prevents a module version from being loaded by the go command.
Exclusions change the module graph, and requirements on the excluded version are redirected to the next higher version. For example, if C 1.3 is excluded, MVS will act as if A 1.2 required C 1.4 instead.
Excluded versions are ignored by the go command, and this may cause commands like go get and go mod tidy to add new requirements on higher versions to go.mod. If an excluded version is referenced by a require directive, the requirement is ignored.
Exclude directives only apply in the main module's go.mod file and are ignored in other modules. If an excluded version is referenced by a require directive, the go command listed available versions for the module and loaded the next higher non-excluded version before Go 1.16.
Broaden your view: Golang Test Main
Require
The require directive is a powerful tool for managing dependencies in Go. It declares a minimum required version of a given module dependency.
In Go 1.17 and above, the go command adds an indirect requirement for each module that provides any package imported by a package or test in the main module, or passed as an argument to go get. This comprehensive requirement enables module graph pruning and lazy module loading.
A require directive loads the go.mod file for the required module version and incorporates the requirements from that file. Once all requirements have been loaded, the go command resolves them using minimal version selection (MVS) to produce the build list.
The go command automatically adds // indirect comments for some requirements, indicating that no package from the required module is directly imported by any package in the main module. This can occur when the selected version of a module is higher than what is already implied by the main module's other dependencies.
A fresh viewpoint: Install Golang Package
Replacement
Replacement is a powerful tool in dependency management that allows you to change the content of a module, including its go.mod file, to a different version or a completely new module.
You can use a replace directive in a main module's go.mod file or a workspace's go.work file to replace a module. This can be done for a specific version of a module or for all versions of a module.
A replacement changes the module graph, since a replacement module may have different dependencies than the replaced versions. For example, if C 1.4 has been replaced with R, R depends on D 1.3 instead of D 1.2.
This means that the build list will contain A 1.2, B 1.2, C 1.4 (replaced with R), and D 1.3, which is different from the original build list that included A 1.2, B 1.2, C 1.3, and D 1.2.
Package and Version Management
A module is a collection of packages that are released, versioned, and distributed together. It's identified by a module path, declared in a go.mod file, along with information about the module's dependencies.
The main module is the module containing the directory where the go command is invoked. Each package within a module is a collection of source files in the same directory that are compiled together.
A package path is the module path joined with the subdirectory containing the package (relative to the module root). For example, the module "golang.org/x/net" contains a package in the directory "html", so its package path is "golang.org/x/net/html".
Here's a summary of how versions work in Go:
- The major version must be incremented and the minor and patch versions must be set to zero after a backwards incompatible change.
- The minor version must be incremented and the patch version set to zero after a backwards compatible change.
- The patch version must be incremented after a change that does not affect the module's public interface.
- The pre-release suffix indicates a version is a pre-release.
- The build metadata suffix is ignored for the purpose of comparing versions.
A version is considered unstable if its major version is 0 or it has a pre-release suffix. Unstable versions are not subject to compatibility requirements.
Discover more: Golang Version Manager
Packages
Packages are a collection of source files in the same directory that are compiled together. Each package has a unique path, which is the module path joined with the subdirectory containing the package (relative to the module root).
A package path can be as simple as "golang.org/x/net" or as complex as "golang.org/x/net/html", where "golang.org/x/net" is the module path and "html" is the subdirectory containing the package.
The go command checks if a module contains a package by looking for at least one file with the .go extension in the directory. Build constraints are not applied for this purpose.
The GOPROXY environment variable controls how the go command looks up new modules for a package path. It can be a comma-separated list of proxy URLs or the keywords direct or off.
The go command requests the latest version of each module path that might provide the package, and then downloads the module at the latest version to check if it contains the requested package.
If one or more modules contain the requested package, the module with the longest path is used. If one or more modules are found but none contain the requested package, an error is reported.
The GOPROXY list can contain multiple entries, and the go command will try each entry in sequence until it finds a suitable module or runs out of entries.
Versions
A version identifies an immutable snapshot of a module, which may be either a release or a pre-release. Each version starts with the letter v, followed by a semantic version.
A semantic version consists of three non-negative integers separated by dots, representing the major, minor, and patch versions. The patch version may be followed by an optional pre-release string starting with a hyphen, which indicates a version is a pre-release.
The major version must be incremented and the minor and patch versions must be set to zero after a backwards incompatible change is made to the module's public interface or documented functionality. This is a significant change, requiring a new major version.
Here's a summary of the version rules:
- The major version must be incremented after a backwards incompatible change.
- The minor version must be incremented and the patch version set to zero after a backwards compatible change.
- The patch version must be incremented after a change that does not affect the module's public interface.
- The pre-release suffix indicates a version is a pre-release and sorts before the corresponding release versions.
- The build metadata suffix is ignored for the purpose of comparing versions.
A version is considered unstable if its major version is 0 or it has a pre-release suffix. Unstable versions are not subject to compatibility requirements, so they may not be compatible with previous versions.
The go command can access modules in version control systems using tags, branches, or revisions that don't follow the standard versioning conventions. However, within the main module, the go command will automatically convert revision names into canonical versions.
Resolving and Retrieving Packages
Resolving and retrieving packages is a crucial part of working with Go modules. The go command starts by searching the build list for modules with paths that are prefixes of the package path.
To find a module that provides a package, the go command checks the GOPROXY environment variable, which is a comma-separated list of proxy URLs or the keywords direct or off. A proxy URL indicates the go command should contact a module proxy using the GOPROXY protocol.
The go command will attempt to download modules from each server in the GOPROXY list in sequence. If the keyword direct is used, the go command will download modules from version control repositories instead of using a proxy.
Here are the environment variables that can be used to configure access to private modules:
- GOPROXY — list of module proxy URLs
- GOPRIVATE — list of glob patterns of module path prefixes that should be considered private
- GONOPROXY — list of glob patterns of module path prefixes that should not be downloaded from a proxy
- GONOSUMDB — list of glob patterns of module path prefixes that should not be checked using the public checksum database
- GOINSECURE — list of glob patterns of module path prefixes that may be retrieved over HTTP and other insecure protocols
The go mod download command can be used to download modules into the module cache. It's useful for pre-filling the module cache or for loading data to be served by a module proxy.
Resolving a Package

Resolving a package is a crucial step in the Go programming language. The go command loads a package using a package path, and it needs to determine which module provides the package.
The go command starts by searching the build list for modules with paths that are prefixes of the package path. For example, if the package example.com/a/b is imported, and the module example.com/a is in the build list, the go command will check whether example.com/a contains the package in the directory b.
At least one file with the .go extension must be present in a directory for it to be considered a package. Build constraints are not applied for this purpose.
If exactly one module in the build list provides the package, that module is used. If no modules provide the package or if two or more modules provide the package, the go command reports an error.
The go command can be instructed to attempt to find new modules providing missing packages and to update go.mod and go.sum using the -mod=mod flag. This flag is also used by the go get and go mod tidy commands.

The GOPROXY environment variable is a comma-separated list of proxy URLs or the keywords direct or off. A proxy URL indicates the go command should contact a module proxy using the GOPROXY protocol.
Here are the possible values for the GOPROXY variable:
- A proxy URL, which instructs the go command to contact a module proxy using the GOPROXY protocol.
- The keyword direct, which tells the go command to communicate with a version control system.
- The keyword off, which indicates that no communication should be attempted.
The GOPRIVATE and GONOPROXY environment variables can also be used to control the behavior of the go command.
The go command requests the latest version of each module path that might provide the package, and for each successfully requested module path, it downloads the module at the latest version and checks whether the module contains the requested package. If one or more modules contain the requested package, the module with the longest path is used.
Download
The go command will automatically download modules as needed during ordinary execution, but sometimes you might want to pre-fill the module cache or load data to be served by a module proxy.
You can use the `go mod download` command to download the named modules into the module cache. This command can take module paths or module patterns selecting dependencies of the main module or version queries of the form path@version.

With no arguments, the `go mod download` command applies to all dependencies of the main module. By default, it writes nothing to standard output, but prints progress messages and errors to standard error.
You can use the `-json` flag to cause the `go mod download` command to print a sequence of JSON objects to standard output, describing each downloaded module (or failure).
The JSON output corresponds to this Go struct:
```json
{
"Path": string,
"Version": string,
"Reused": bool,
"Error": string,
}
```
The `-reuse` flag accepts the name of a file containing the JSON output of a previous `go mod download -json` invocation. This can be useful on systems that don't preserve the module cache, as it allows the go command to determine that a module is unchanged since the previous invocation and avoid redownloading it.
For another approach, see: Golang String Templating
Toolchain and Commands
A toolchain directive in a Go module declares a suggested Go toolchain to use with the module, and its version cannot be less than the required Go version declared in the go directive. This directive only has an effect when the module is the main module and the default toolchain's version is less than the suggested toolchain's version.
The go command writes its own toolchain name in a toolchain line any time it is updating the go version in the go.mod file. For details, see "Go toolchains".
Most go commands may run in Module-aware mode or GOPATH mode. In module-aware mode, the go command uses go.mod files to find versioned dependencies, and it typically loads packages out of the module cache, downloading modules if they are missing.
Here is a list of build commands that use go.mod files to interpret import paths: go buildgo fixgo generatego installgo listgo rungo testgo vet
Additional reading: How to Run a Golang Program
Toolchain
A toolchain directive is a suggestion for a Go toolchain to use with a module, and its version must be at least as high as the required Go version declared in the go directive.
The toolchain directive only affects the main module and only when the default toolchain's version is lower than the suggested toolchain's version.
The go command writes its own toolchain name in a toolchain line when updating the go version in the go.mod file, usually during go get, for reproducibility.
For a tool directive, a package is added as a dependency and made available to run with go tool, but if the tool package is not in the current module, a require directive is needed to specify the version to use.
The tool meta-pattern resolves to the list of tools defined in the current module's go.mod or the union of all tools defined in all modules in the workspace.
Debug
Debugging your code can be a real pain, especially when you're working on a complex project. You can use the godebug directive to declare a single GODEBUG setting that applies when your module is the main module.
The godebug directive is quite flexible, allowing you to have more than one line and even factor them out for easier maintenance. However, if your main module tries to name a GODEBUG key that doesn't exist, you'll get an error.
You can think of the effect of godebug key=value as if every main package being compiled contained a source file that listed //go:debug key=value. This can be a helpful way to understand how godebug works in practice.
Lazy Loading
Lazy loading is a feature in Go 1.17 and higher that allows the go command to delay loading the complete module graph until it's actually needed.
If the main module is at Go 1.17 or higher, the go command loads only the main module's go.mod file initially.
The go command then attempts to load the packages to be built using only those requirements.
If a package to be imported is not found among those requirements, the rest of the module graph is loaded on demand.
This approach can significantly reduce the time it takes to load the module graph, especially in large projects.
Inconsistencies can arise due to version-control merges, hand-edits, and changes in modules that have been replaced using local filesystem paths.
The go command checks the go.mod files for the modules containing those packages and their requirements against the requirements of the main module to ensure local consistency.
If all imported packages can be found without loading the module graph, the go command loads the go.mod files for only those modules, and their requirements are checked as a precaution.
Commands Outside
Some commands can be run without a go.mod file, but they behave differently than in module-aware mode. The go command runs in GOPATH mode, ignoring modules and looking in vendor directories and GOPATH to find dependencies.
If you set the GO111MODULE environment variable to off, the go command ignores go.mod files and runs in GOPATH mode. This means you can build packages from the standard library or specified on the command line.
The go get command is one of the few that can be run without a go.mod file. It can build and install packages as usual, but there's no main module, so replace and exclude directives aren't applied.
However, some commands require a go.mod file. These include go mod download, go mod edit, go mod graph, go mod tidy, go mod vendor, and go mod verify. If you try to run these commands without a go.mod file, you'll get an error.
Expand your knowledge: Golang Mode
Here's a rundown of the behavior of various commands when run outside a module:
Automatic Updates
Automatic updates are a convenient feature of Go modules that can save you time and effort. The update modifies requirements to respect exclusions, so if you've excluded a specific version of a module, the update will use the next available version.
The go command will automatically update go.mod if any changes are needed, but if only formatting changes are needed, it will not update the file. This means you can rely on the go command to keep your module up to date without having to manually edit go.mod.
In Go 1.15 and lower, the -mod=mod flag was enabled by default, so updates were performed automatically. Since Go 1.16, the go command acts as if -mod=readonly were set instead, so if any changes to go.mod are needed, the go command reports an error and suggests a fix.
The go command resolves imports by using the specific dependency module versions listed in go.mod, and if it encounters an import of a package not provided by any module in go.mod, it automatically looks up the module containing that package and adds it to go.mod, using the latest version.
The go command maintains a file named go.sum containing the expected cryptographic hashes of the content of specific module versions, which ensures that future downloads of these modules retrieve the same bits as the first download.
Graph and Cache Management
Graph and Cache Management is crucial for smooth Go development. The go clean command is often used to remove the module cache.
go clean -modcache is the best way to remove the module cache entirely, including unpacked source code of versioned dependencies. This flag causes the removal of the entire module cache.
By default, most files and directories in the module cache are read-only to prevent unintentional changes. This can cause commands like rm -r to fail, since files can't be removed without making their parent directories writable.
The -modcacherw flag can be used to make new directories in the module cache writable. However, this should be used with caution, as developers should be careful not to make changes to files in the cache.
Graph

The go mod graph command prints the module requirement graph in text form.
Each vertex in the module graph represents a specific version of a module.
Each edge in the graph represents a requirement on a minimum version of a dependency.
go mod graph prints the edges of the graph, one per line. Each line has two space-separated fields: a module version and one of its dependencies.
For more insights, see: Golang Line
Graph Pruning
Graph pruning is a feature that helps reduce the complexity of a module graph in Go. It's particularly useful for large projects with many dependencies.
For Go 1.17 and higher, the module graph used for minimal version selection only includes immediate requirements for each module dependency that specifies Go 1.17 or higher in its go.mod file. This means that transitive dependencies of Go 1.17 dependencies are pruned out of the module graph.
This pruning doesn't affect the run-time behavior of packages, but it can cause interference between unrelated modules. A module that's not needed to build any package or test in a given module can still be included in the module graph, but its selected versions are known and well-defined.
Discover more: Golang Install Dependencies

Packages can be loaded from pruned modules, but the go command can't easily identify which dependencies of these modules are satisfied. As a result, go build and go test can't include packages from modules whose requirements have been pruned out.
However, go get promotes the module containing each named package to an explicit dependency, allowing go build or go test to be invoked on that package. This is a useful workaround for cases where pruning would otherwise cause issues.
In Go 1.16 and earlier, the full transitive closure of dependencies is still included for each module that specifies Go 1.16 or lower. This is because these versions of Go didn't support module graph pruning.
A fresh viewpoint: T Golang
Cache
The cache is a critical component of the Go module system. It stores unpacked source code of versioned dependencies.
To remove the entire module cache, you should use the command "go clean -modcache". This is usually the best way to remove the module cache.

Removing the module cache can be tricky due to its read-only nature. Most files and directories in the module cache are read-only to prevent tests and editors from unintentionally changing files.
Using "rm -r" to remove the module cache won't work because the parent directories are read-only. To make new directories in the module cache writable, you can use the "-modcacherw" flag.
This flag can be passed to all module-aware commands by adding it to the GOFLAGS variable. You can set GOFLAGS permanently using the command "go env -w".
Using "-modcacherw" requires caution, as developers should be careful not to make changes to files in the module cache.
Additional reading: Golang Read in File
Repository and Proxy Management
You can configure the go command to download modules from a private proxy server or directly from version control repositories. To do this, you can set the GOPROXY environment variable to a comma-separated list of proxy URLs or the keyword direct.
The GOPROXY setting instructs the go command to only download modules from the specified proxy server, bypassing public proxies and version control repositories.
A private proxy server can be configured to serve all modules, providing the most control for administrators and requiring the least configuration for individual developers. To do this, you can set the GOPROXY setting to the proxy URL and the GONOSUMDB setting to the module prefix.
The GOPRIVATE setting instructs the go command not to connect to a proxy or to the checksum database for modules starting with the specified prefix. This can be useful when running a private proxy server is not feasible.
To ensure smooth authentication, make sure the go command uses the correct repository URL and that the version control tool doesn’t require a password to be entered interactively.
Here are some common patterns for providing access to private module proxies and version control repositories:
Repository directories
Repository directories are crucial for a module's go command to locate the directory that contains the module's go.mod file, the module's root directory.

A module path consists of three parts: a repository root path, a module subdirectory, and a major version suffix for modules released at v2 or higher. For most modules, the module path is equal to the repository root path, so the module's root directory is the repository's root directory.
Modules can be defined in repository subdirectories, typically for large repositories with multiple components that need to be released and versioned independently. This means the go.mod file must be in the subdirectory that matches the part of the module's path after the repository root path.
A module with a major version suffix may be defined in one of two subdirectories: one with the suffix, and one without. For example, if a module is released with the path example.com/monorepo/foo/bar/v2, its go.mod file may be in either foo/bar or foo/bar/v2.
Subdirectories with a major version suffix are major version subdirectories, which may be used to develop multiple major versions of a module on a single branch. This can be unnecessary when development of multiple major versions proceeds on separate branches.
Readers also liked: Golang Progressbar
Private Proxy for All Packages
A private proxy server that serves all packages provides the most control for administrators and requires the least configuration for individual developers.
To configure the go command to use such a server, you'll need to set the GOPROXY and GONOSUMDB environment variables. The GOPROXY setting instructs the go command to only download modules from the specified proxy URL, while the GONOSUMDB setting tells the go command not to use the public checksum database to authenticate modules with paths starting with your module prefix.
A proxy running in this configuration will likely need read access to private version control servers and access to the public internet to download new versions of public modules.
Here are the environment variables you'll need to set, replacing https://proxy.corp.example.com with your proxy URL and corp.example.com with your module prefix:
- GOPROXY: https://proxy.corp.example.com
- GONOSUMDB: true
There are several existing implementations of GOPROXY servers that may be used this way, including a minimal implementation that serves files from a module cache directory and uses go mod download to retrieve missing modules.
Work Sync

Work Sync is a crucial command in Go that keeps your workspace's build list in sync with your modules.
The go work sync command generates the workspace build list using the Minimal Version Selection (MVS) algorithm.
This build list is the set of versions of all dependency modules used to do builds in the workspace.
go work sync syncs those versions back to each of the modules specified in the workspace.
The go.mod file for each module in the workspace is rewritten with dependencies upgraded to match the workspace build list.
Minimal Version Selection guarantees that the build list's version of each module is always the same or higher than that in each workspace module.
Broaden your view: Watermill Golang Sync
Private Packages and Authentication
Private packages can be accessed directly from version control servers without a proxy, but this requires some configuration. This approach is useful when running a private proxy server is not feasible.
To configure direct access to private packages, set the GOPRIVATE environment variable to the private module prefix. For example, if the private module prefix is corp.example.com, set GOPRIVATE to "corp.example.com". This instructs the go command not to connect to a proxy or the checksum database for modules starting with corp.example.com.
Developers will need read access to repositories containing private packages, which may be configured in global VCS configuration files like .gitconfig. It's best if VCS tools are configured not to need interactive authentication prompts.
Here's a summary of the environment variables used to configure access to private packages:
Special License Case
When the go command creates a .zip file for a module, it will copy the LICENSE file from the repository root directory if it is present in the same revision.
The go command does not include symbolic links when creating module .zip files.
If a repository doesn't have a LICENSE file in its root directory, authors can create copies of their license files in modules defined in subdirectories to ensure those files are included in module .zip files.
A LICENSE file in the root directory of a module is required for the go command to include it in the .zip file.
Private Packages
Private packages can be configured to be downloaded directly from version control repositories, bypassing public proxies. This is useful when running a private proxy server is not feasible.
To configure the go command for direct access to private modules, you'll need to set the GOPRIVATE environment variable. This instructs the go command not to connect to a proxy or the checksum database for modules starting with a specific prefix.
For example, if you have a private module prefix of corp.example.com, you would set GOPRIVATE to that value. This allows the go command to download private modules directly from version control repositories.
However, this approach requires read access to repositories containing private modules. You'll also need to configure VCS tools not to require interactive authentication prompts. The go command disables interactive prompts by default, but you can explicitly set GIT_TERMINAL_PROMPT to 0.
Alternatively, you can use a central private proxy server that serves all modules, both public and private. This approach provides the most control for administrators and requires the least configuration for individual developers.

To configure a private proxy server, you'll need to set the GOPROXY environment variable to the URL of your proxy server. You'll also need to set GONOSUMDB to instruct the go command not to use the public checksum database for modules with paths starting with your module prefix.
Here's a summary of the environment variables you can use to configure access to private modules:
- GOPROXY: list of module proxy URLs
- GOPRIVATE: list of glob patterns of module path prefixes that should be considered private
- GONOPROXY: list of glob patterns of module path prefixes that should not be downloaded from a proxy
- GONOSUMDB: list of glob patterns of module path prefixes that should not be checked using the public checksum database
- GOINSECURE: list of glob patterns of module path prefixes that may be retrieved over HTTP and other insecure protocols
When using a private proxy server, ensure that it has read access to private version control servers and access to the public internet to download new versions of public modules.
Ignore
Ignoring certain directories and files is a crucial aspect of working with Go modules. An ignore directive can be used to tell the go command to ignore specific paths when matching package patterns.
The ignore directive can be used to ignore slash-separated directory paths, and any files or directories recursively contained in them. This is particularly useful when you have a large project with many subdirectories.
If the path starts with ./, it's interpreted relative to the module root directory, and that directory and any directories or files recursively contained in it will be ignored. This means you can ignore a specific directory within your project by specifying its path relative to the module root.
Any directories with the path at any depth in the module, and any directories or files recursively contained in them, will be ignored if the path doesn't start with ./. This can be useful for ignoring entire sections of your project that you don't want to include in your Go module.
Frequently Asked Questions
Is Netflix using Golang?
Yes, Netflix is using Golang for building internal tools. They leverage Go for high-performance systems, such as Chaos Monkey, to test the resilience of their infrastructure.
Featured Images: pexels.com
