Modules and Files
The bootstrap module system — local imports, packages, lockfiles, and the current dependency story.
The bootstrap module system is intentionally small and strict.
That is a feature, not a bug. The project is trying to stabilize semantics before pretending that a full package ecosystem already exists.
Local imports
import name now resolves through a deterministic local order:
name.gofnext to the importing filesrc/name.gofinside the nearest package root withgof.modsrc/lib.goffrom a local path dependency declared asname = { path = "../dep" }
Reserved stdlib imports are the one explicit exception:
import bytesimport ioimport timeimport netimport http
Those names resolve to shipped modules under stdlib/ instead of local files or
dependency aliases. Reusing one of those names in user code is a compile error,
not a shadowing trick.
Same-directory imports still work exactly as before.
Package-root imports make it possible to keep entrypoints in subdirectories while sharing one flat package module surface.
Example package:
app/
gof.mod
src/
main.gof
math.gofwith gof.mod:
module = "example/app"
edition = "2026"
[dependencies]and src/main.gof:
import math
fn main() -> int:
return square(9)Local path dependencies
The current package workflow also supports local path dependencies.
Example app manifest:
module = "example/package_app"
edition = "2026"
[dependencies]
package_math = { path = "../package_math" }Dependency layout:
package_math/
gof.mod
src/
lib.gof
ops.gofsrc/lib.gof is the dependency entrypoint that gets loaded for import package_math.
Locking the local graph
Manifest-backed packages now use a committed gof.lock.
Generate or refresh it with:
gof mod resolve --dir package_appRules:
gof.lockis the only lockfile formatgof mod resolveis the only command that writes itgof run,gof build, and package-awaregof testrequire it for manifest-backed packages- editing
.gofsource files alone does not stale the lockfile - changing
gof.modmetadata or dependency paths does stale the lockfile - lockfile entries are deterministic and use forward-slash relative paths
How the current bootstrap graph behaves
Today the module graph:
- works for same-directory imports
- works for shipped stdlib imports through reserved module names
- works for package-root imports through the nearest
gof.mod - works for local path dependencies through
[dependencies] - loads imported files into one merged bootstrap module graph
- rejects import cycles
- rejects duplicate top-level functions
- rejects duplicate top-level structs
- rejects duplicate top-level enums
- rejects conflicting top-level names across functions, structs, and enums
That strictness exists because constructors, type names, and callable names must stay unambiguous.
How to organize small programs today
The current best practice is:
- keep a package root with
gof.mod - keep executable entrypoints in
src/main.gof - keep reusable package exports in
src/lib.goffor dependencies