Create a Module

Purpose and Scope

This page teaches the first module-creation workflow a new Go developer uses: create a directory, initialize module metadata with the go command, write a package, and prepare that package to be imported by another module. A module is the unit of dependency tracking in modern Go. It has a module path, usually looking like an import path, and a go.mod file that records that path and the language version expected by the module. A package is a directory of Go source files compiled together; a module can contain one or many packages.

The official tutorial sequence starts with a library-style module named greetings and later adds a separate caller application. That separation is important: it shows that a module does not need to be an executable. The first module exposes a function another module can import, while the second module has a main package that can run as a program. Thinking in those two layers helps readers avoid mixing package design with command design too early.

Although the supplied repository source for this page is low-level runtime code, it still illustrates a constraint that applies whenever tools create files for developers: file creation is platform-specific inside the Go implementation. On Unix systems, the runtime-backed create helper opens a write-only file with create, truncate, and write-only flags; on non-Unix builds, the file marks creation as unavailable and throws if the helper is called. Module tutorials normally hide that detail behind the go command, but the distribution must still carry platform-specific implementation boundaries. Sources: src/runtime/create_file_unix.go, src/runtime/create_file_nounix.go

Relevant Source Files

  • src/runtime/create_file_unix.go — Defines the Unix build of the runtime file-creation helper. It declares that files can be created on this build target and implements creation by calling open with create, write-only, and truncate flags.
  • src/runtime/create_file_nounix.go — Defines the non-Unix build of the same helper. It records that this runtime path cannot create files and throws if the unimplemented helper is invoked.

These files are not module parser or go command files; they are included here because they are the requested repository evidence for this page. They are useful as a concrete reminder that a command such as go mod init presents a stable cross-platform developer workflow, while the implementation of file creation in the Go tree is divided by build constraints. In practice, new users should interact with the go command, not runtime internals, when creating module metadata.

Core Primitives

The central primitive in this workflow is the module. A module collects related packages and gives them one versioned identity. The module path is the name other Go code will use to refer to packages in the module. In the tutorial, example.com/greetings is a local teaching path; in a published module, the path usually corresponds to a repository location that the Go toolchain and module proxy ecosystem can resolve.

The second primitive is the go.mod file. Running go mod init example.com/greetings creates the go.mod file for the current directory. That file begins dependency tracking for code under the module root. Later workflows may add require, replace, or other directives, but the create-module tutorial begins with the smallest useful metadata: the module path and the Go version line managed by the tooling.

The third primitive is the package. The tutorial's first package is also named greetings and contains exported functions that another package can call. In Go, names beginning with an uppercase letter are exported from their package. A function such as Hello can therefore be imported and used by code in another module, while helper names beginning with lowercase letters remain package-internal implementation details.

A final primitive is the command module versus library module distinction. A package named main builds an executable program, while ordinary packages build reusable libraries. The create-module step focuses on the reusable side. The next tutorial step creates a separate hello module with package main, imports example.com/greetings, and calls its exported function. Keeping those roles separate makes dependency relationships easier to understand.

Tutorial Flow

Start in a terminal and create a directory for the library module. The official tutorial uses a greetings directory. From inside that directory, run go mod init with the module path you want the module to have. For the tutorial path, the command is go mod init example.com/greetings. The go command responds by creating a new go.mod file, establishing the current directory as the module root.

After initialization, create a Go source file for the package. The tutorial convention is greetings.go in the greetings directory. The file should declare package greetings and define a function that returns a greeting string. The important concept is that the package declaration, directory, and module metadata now work together: the module gives the package an importable path, while the package source provides exported behavior.

A minimal example follows the shape below. It is intentionally small because the lesson is the module boundary, not a complex algorithm. Once this file exists, another module can import example.com/greetings after the local dependency relationship is configured in the caller tutorial. The first module does not need a main function because it is not being run directly as an application.

package greetings
 
import "fmt"
 
func Hello(name string) string {
    return fmt.Sprintf("Hi, %v. Welcome!", name)
}

Next, inspect the generated go.mod file rather than editing it blindly. It should name the module path passed to go mod init. The file is ordinary text, but it is owned by the module workflow: commands such as go mod tidy, go get, and later dependency operations may update it. Treat it as source-controlled module metadata that should be reviewed like code.

module example.com/greetings
 
go 1.23

The go command workflow is deliberately simple for this first step. You do not need a GOPATH-style workspace layout, and you do not need to publish the module before experimenting locally. The module root is the directory containing go.mod. Code below that root is interpreted relative to the module path, so a subdirectory such as greetings/internal would become another package under the same module boundary.

System-to-Code Mapping

The visible developer action is go mod init, but the broader system includes command parsing, module metadata creation, source files, and platform-specific file operations. The repository snippets provided for this page show only the runtime side of creating files. On Unix, the helper reports canCreateFile as true and opens a write-only file with _O_CREAT, _O_WRONLY, and _O_TRUNC. That is the kind of primitive lower layers expose so higher-level tools can implement predictable file-writing behavior. Sources: src/runtime/create_file_unix.go

The non-Unix file is the complementary build of the same abstraction. It declares canCreateFile as false, and its create function throws because this particular runtime helper is not implemented for those targets. The Go tree commonly uses build tags to select source files for a target operating system or family. For a tutorial reader, the key lesson is not to call this helper, but to recognize that the distribution hides platform variation behind stable commands. Sources: src/runtime/create_file_nounix.go

Reader conceptRepository-backed signalPractical meaning
Stable command workflowRuntime code has platform-selected file creation helpersA single tutorial command can work across supported environments while internals differ by target
Generated metadataFile creation is an implementation concern, not a hand-authored runtime APILet go mod init create go.mod instead of inventing metadata manually
Module rootgo.mod marks the boundary of module-aware operationsRun the command from the directory intended to own the module
Reusable packageSource files declare ordinary package names such as greetingsExported identifiers become available to importing packages

Common Pitfalls

Do not name the first reusable package main unless you intend to build an executable. A package named main is special: it is the entry point for commands. The tutorial starts with a library module so that another module can import it. Use package greetings for the reusable code and reserve package main for the later caller application.

Do not confuse the module path with a file-system path. In the tutorial, example.com/greetings is a module path, even if there is no real example.com repository. During local learning, later steps can use module replacement to point an import at a nearby directory. In published modules, the path should be chosen carefully because import paths become part of the public API users write in their source code.

Do not edit generated module metadata without understanding why. The first go.mod file is small, but it is the foundation for dependency tracking. Manual edits are sometimes appropriate, especially for replace directives during local development, yet most routine changes should be made through go commands so version syntax and dependency graph updates remain consistent.

Next Steps

After creating the greetings module, continue with the caller workflow. Create a sibling hello directory, run go mod init example.com/hello, write a package main, import example.com/greetings, and call greetings.Hello. That second step demonstrates how modules interact, why imports use package paths, and how local development can connect one module to another before publishing.

Once the basic call works, extend the module the way the tutorial sequence does: return and handle an error, add randomized greetings, use a map for multiple people, and add a test. Those steps turn a tiny function into a realistic package surface and prepare the reader for dependency management, testing, and eventually publishing modules for other developers to use.