diff --git a/lib/gat/module/module.go b/lib/gat/module/module.go
new file mode 100644
index 0000000000000000000000000000000000000000..20fda542ab94dd7a7840e061ab3c9e2a50ee68b6
--- /dev/null
+++ b/lib/gat/module/module.go
@@ -0,0 +1,19 @@
+package module
+
+type ModuleInfo struct {
+	ID  string
+	New func() Module
+}
+
+type Module interface {
+	GatModule() ModuleInfo
+}
+
+var globalModuleMap = newModuleMap()
+
+func Register(name string, module Module) {
+	err := globalModuleMap.Register(name, module)
+	if err != nil {
+		panic(err)
+	}
+}
diff --git a/lib/gat/module/registry.go b/lib/gat/module/registry.go
new file mode 100644
index 0000000000000000000000000000000000000000..00a2a82e688721b5a6ed57e802be506f4b5793d9
--- /dev/null
+++ b/lib/gat/module/registry.go
@@ -0,0 +1,22 @@
+package module
+
+import "fmt"
+
+type moduleMap struct {
+	m map[string]Module
+}
+
+func newModuleMap() *moduleMap {
+	return &moduleMap{
+		m: map[string]Module{},
+	}
+}
+
+func (m *moduleMap) Register(name string, module Module) error {
+	_, ok := m.m[name]
+	if ok {
+		return fmt.Errorf("module with name already registered: %s", name)
+	}
+	m.m[name] = module
+	return nil
+}