Why use companion object to make singleton in Kotlin?

getInstance() is just a "traditional" way of creating singletons. It is a common technique in e.g. Java, because contrary to Kotlin, Java doesn't have singletons provided by the language itself. For this reason you will see getInstance() from time to time in Kotlin as well. It may be the code ported from Java, it may be developed by a person who has more experience with Java, so they don't know there is a better alternative in Kotlin, etc.

Additionally, object is pretty much static. If we have more complicated logic for creating a singleton, it may be required to create it by some kind of factory (e.g. companion object).

So I would say, the rule of thumb is to use object as a default and only if this is not possible, create it manually. And in the latter case, it is more "Kotlin-ish" to use a property, not a getInstance() function.