Highly discussable question. My answer is based on my own experience and few web-links to well known references.
If you're writing in Kotlin, I would always use coroutines.
1. Performance
baeldung.com
Creating too many threads can actually make an application
underperform in some situations; threads are objects which impose
overhead during object allocation and garbage collection.
To overcome these issues, Kotlin introduced a new way of writing
asynchronous, non-blocking code; the Coroutine.
Similar to threads, coroutines can run in concurrently, wait for, and
communicate with each other with the difference that creating them is
way cheaper than threads.
There are many other websites and statistics proving the point, that having coroutines is much cheaper than using java threads.
From my own experiences - I build an application in my company for logistics which has at some point of runtime over 20 coroutines running in parallel - I never had in 1,5 years of using them any 'OutOMemory', 'StackOverflow', or 'slowing down the main application' problems.
2. Usability / Difficulty
Compared to java Threads, using Kotlin coroutines is very easy and doesn't enforce you to change the way you code. The last point is well explained in this video.
Usually working in Java with Java threads, people built so many 'procedures' or classes to add safety with multi-threading, that it creates a big overhead of things to know about before you do real good multi-threading. And it takes alot of time.
In Kotlin its easy: you don't need Thread pools or twerking the code to make it asynchronous - you just do it with easy keyword async.