Coroutines are Kotlin's solution for concurrency and allow doing something else while waiting for results. They avoid issues with threading like memory usage and bottlenecks. Coroutines use suspending functions to pause execution and switch to other coroutines. They can be cancelled, have timeouts set, and structured hierarchically with jobs. Common coroutine patterns include producers that return values on channels and actors that receive messages on inbound channels. Coroutines are backed by event loops and may require yield() if CPU bound to allow other coroutines to run.