But how do you avoid duplicating the interface in many places?
We've tried both approaches, declaring the interface in one package and importing it where used but also declaring it directly colocated with the consumer.
I've found the first approach worked better when we had to add or modify the interface methods
You don’t. Each consumer of something declares what it needs via an interface, something concrete may be passed that implements it - including fakes for tests.
Of course this doesn’t apply when using interfaces for polymorphic return types in a library, but that is a distinct use case for interfaces to address.
Perhaps some of this is just taste, but this is the way I’ve found interfaces in Go to be most useful.
We've tried both approaches, declaring the interface in one package and importing it where used but also declaring it directly colocated with the consumer.
I've found the first approach worked better when we had to add or modify the interface methods