modules

module organization

patterns for organizing zig modules, derived from ghostty and tigerbeetle.

file + directory pattern

idiomatic zig uses foo.zig alongside foo/ directory:

src/
├── apprt.zig          # entry point / public API
└── apprt/             # implementation files
    ├── action.zig
    ├── structs.zig
    └── gtk.zig

the parent file re-exports from the subdirectory:

// apprt.zig
pub const action = @import("apprt/action.zig");
pub const structs = @import("apprt/structs.zig");

pub const Action = action.Action;
pub const Runtime = @import("apprt/runtime.zig").Runtime;

no ambiguity because import paths are explicit:

  • @import("apprt.zig") → the file (public API)
  • @import("apprt/action.zig") → from the directory

anti-patterns

don't do foo/foo.zig - redundant naming:

src/
└── orchestration/
    └── orchestration.zig   # wrong

don't do foo/mod.zig - this is rust convention, not zig:

src/
└── orchestration/
    └── mod.zig             # wrong (rust pattern)

examples in the wild

ghostty:

  • src/apprt.zig + src/apprt/
  • src/cli.zig + src/cli/
  • src/config.zig + src/config/

tigerbeetle:

  • src/io.zig + src/io/
  • src/lsm.zig + src/lsm/

prefect-server:

  • src/orchestration.zig + src/orchestration/
  • src/broker.zig + src/broker/
  • src/services.zig + src/services/