How to Fix Go Import Cycle Not Allowed
In this tutorial, you'll learn about How to Fix Go Import Cycle Not Allowed. We cover key concepts, practical examples, and best practices.
The Problem
You compile your Go project and get:
package myapp/users
imports myapp/orders
imports myapp/users
import cycle not allowed
Package users imports orders, which imports users back. Go does not allow circular imports. The compiler refuses to build until the cycle is broken.
Quick Fix
Step 1: Identify the cycle
go mod graph | grep "myapp/users" | head -10
This shows which packages import users and which packages users imports. Follow the chain to find the cycle.
Step 2: Extract shared types into a separate package
Move common types that both packages need into a new types or models package:
// models/user.go
package models
type User struct {
ID int
Name string
}
// models/order.go
package models
type Order struct {
ID int
UserID int
Total float64
}
Both users and orders now import models instead of each other.
Step 3: Use interfaces instead of concrete types
Define an interface in the importing package:
// users/service.go
package users
type UserService interface {
GetUser(id int) (*User, error)
}
The orders package depends on the interface, not the concrete implementation:
// orders/handler.go
package orders
type Handler struct {
users UserService
}
The concrete implementation lives in users and does not import orders.
Step 4: Merge the packages
If the packages are tightly coupled, they should be a single package:
package users
// User and Order types both live here
This is a pragmatic solution when the packages are logically inseparable.
Step 5: Use a service layer as mediator
Create an intermediate package that both packages import:
// service/service.go
package service
import (
"myapp/models"
"myapp/users"
"myapp/orders"
)
func PlaceOrder(userID int, productID int) (*models.Order, error) {
user, _ := users.GetUser(userID)
return orders.CreateOrder(user, productID)
}
Step 6: Verify the cycle is broken
go build ./...
Expected:
(no output, build succeeds)
Step 7: Visualize the dependency graph
go install golang.org/x/tools/cmd/deadcode@latest
deadcode ./...
Dead code detection can also reveal unnecessary imports that lead to cycles.
Alternative Solutions
Restructure your project following the standard Go project layout with clear separation between internal/, pkg/, and cmd/ directories.
Use dependency injection to invert the import direction. Instead of users importing orders, have users accept an OrderService interface defined in a shared package.
Prevention
- Design packages with a clear dependency direction (domain -> application -> infrastructure).
- Keep packages small and focused on a single responsibility.
- Run
go vetas part of CI to catch cycle-related issues early. - Review import statements during code reviews to prevent cycles from forming.
- Use
go mod graph | dot -Tpng > deps.pngto visualize the dependency graph periodically. - Add a
go vet ./...check in your CI pipeline to catch import cycles before merge.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro