Published on June 1, 2025

Kotlin is packed with features that make coding cleaner and more intuitive. Two concepts that often spark confusion — even among seasoned developers — are companion objects and singletons. Let’s demystify them with a fresh perspective, zero jargon, and a quirky example you won’t find anywhere else.

A companion object is like a loyal sidekick tied to a specific class. It can access the class’s private members (yes, even the secrets!) and is ideal for housing methods or properties that belong to the class but don’t need a separate instance.
Declare it inside a class with the companion keyword:
class Spaceship(private val engineSerial: String) {
// Companion object
companion object BlackBox {
fun logLaunch(serial: String) {
println("Spaceship with engine $serial launched! 🚀")
}
}
fun launch() {
BlackBox.logLaunch(engineSerial) // Access private engineSerial
}
}
Here, BlackBox is a companion object inside the Spaceship class. It logs launches using the private engineSerial, something only a companion can do.
Access Private Data: It’s the only “object” that can peek into a class’s private properties.
Class-Specific Logic: Perfect for factory methods (Spaceship.create()) or constants tied to the class.
No Duplicate Instances: There’s only one companion per class, so no memory bloat.
A singleton in Kotlin is a globally accessible, single instance of an object. Declare it using object (not inside a class!), and it lives independently.
object CentralComputer {
private val spaceships = mutableListOf<String>()
fun trackSpaceship(serial: String) {
spaceships.add(serial)
println("Now tracking ${spaceships.size} spaceships.")
}
}
The CentralComputer singleton tracks all spaceships across your app. Any class can call CentralComputer.trackSpaceship(...), and there’s only one instance managing the list.
Global Access: Need a shared resource (like a database connection)? Singletons are your friend.
Lazy Initialization: Created only when first used, saving memory.
Stateless Services: Great for logging, analytics, or hardware control.
Aspect | Companion Object | Singleton
---------------------|-------------------------------------------|-----------------------------------------
Scope | Tied to a class (like Spaceship.BlackBox) | Standalone (CentralComputer)
Private Access | Can access private members of its class | Can’t unless nested inside the class
Initialization | Created when the class is loaded | Created lazily on first use
Use Case | Class-specific factories, constants | App-wide resources, shared state
You need a factory method for a class (e.g., Spaceship.fromConfig()).
Storing constants specific to a class (e.g., Spaceship.MAX_SPEED).
Accessing private properties of the class (like logging internal data).
2. Singletons Shine When…
Managing app-wide resources (e.g., a network client or database).
You need a single source of truth (e.g., a user session manager).
You want lazy initialization to optimize performance.
Let’s combine both concepts in a real-world scenario:
// Singleton: Manages all spaceships in the universe
object UniverseRegistry {
private val allShips = mutableListOf<Spaceship>()
fun register(ship: Spaceship) {
allShips.add(ship)
println("Universe now has ${allShips.size} spaceships!")
}
}
class Spaceship(private val engineSerial: String) {
init {
UniverseRegistry.register(this) // Singleton in action!
}
// Companion: Handles launch logic for individual ships
companion object BlackBox {
fun launch(ship: Spaceship) {
println("Engine ${ship.engineSerial} firing!")
}
}
fun launch() {
BlackBox.launch(this)
}
}
// Example Usage
val ship1 = Spaceship("X-101")
val ship2 = Spaceship("X-202")
ship1.launch() // Output: Engine X-101 firing!
Here, UniverseRegistry (singleton) tracks all ships globally, while BlackBox (companion) handles ship-specific launches.
Companion objects are your class’s trusted ally, handling intimate tasks.
Singletons are the overseers, managing cross-cutting concerns.
Next time you’re coding in Kotlin, ask: “Does this belong to a single class, or is it a global service?” The answer will guide you to the right tool.