Question
I am learning Kotlin coroutines and understand that they are built around suspend functions, but I am not fully clear on what suspend actually means.
The Kotlin documentation says:
Basically, coroutines are computations that can be suspended without blocking a thread.
I often hear the phrase suspending function, but it seems to me that it is really the coroutine that gets suspended while waiting for some work to finish. In normal English, suspend means to stop operating temporarily, so it sounds like the coroutine becomes idle.
Should we say that the coroutine is suspended? If so, which coroutine is suspended?
For example, the Kotlin documentation gives an example like this:
async {
// outer coroutine
val result = computation.await()
}
It says that await() is a suspending function that suspends a coroutine until some computation is done and returns its result.
Suppose computation() returns a Deferred<Boolean> like this:
fun computation(): Deferred<Boolean> {
return async {
true
}
}
In that case, when await() is called:
- does it suspend the outer coroutine,
- or the inner coroutine that performs the computation,
- or both?
Also, if a coroutine is suspended and a coroutine is often described as being like a lightweight thread, how can the computation still continue?
Is the correct understanding this:
- the outer coroutine calls
await() - the outer coroutine is suspended while waiting
- the underlying thread is released back to the thread pool instead of being blocked
- the inner coroutine continues running
- when the inner coroutine finishes, the outer coroutine resumes, possibly on a different thread
Is that what suspend means in Kotlin coroutines?
Short Answer
By the end of this page, you will understand that suspend in Kotlin does not mean “pause a thread.” It means a function may pause the current coroutine, save its state, and let the thread do other work. You will also learn which coroutine is suspended during calls like await(), how suspension differs from blocking, and why a suspended coroutine can later resume on the same or a different thread.
Concept
suspend in Kotlin marks a function that can pause and resume a coroutine without blocking the underlying thread.
The key idea is:
- A suspending function is a function that is allowed to suspend.
- A coroutine is the running computation whose execution can be paused.
- A thread is the actual OS/JVM thread that may be freed while the coroutine is paused.
So both phrases are used correctly, but they refer to different things:
suspend functiondescribes the function's capability.coroutine is suspendeddescribes what happens at runtime.
What suspend really means
A suspend function does not automatically pause. It simply has permission to pause the current coroutine at certain points.
For example:
suspend fun loadData(): String {
delay(1000)
return "done"
}
This function is marked suspend because it calls another suspending function, delay(). During , the current coroutine may be suspended for 1 second without blocking a thread.
Mental Model
Think of a coroutine like a bookmark in a book.
- The coroutine is the reader's progress through the story.
- The thread is the chair the reader is sitting on.
- A
suspendfunction is a place where the reader is allowed to put in a bookmark and get up.
When suspension happens:
- the reader saves their place with a bookmark
- the chair becomes free for someone else
- later, the reader comes back
- they may sit in the same chair or a different one
- they continue from the bookmark
So:
- the coroutine is what pauses and resumes
- the thread is just where the coroutine happens to run at that moment
- the suspend function is a function that can create one of those bookmark points
For await() specifically:
- the outer coroutine reaches
await() - if the result is not ready, it puts down a bookmark and pauses
- the inner coroutine keeps working
- when the result is ready, the outer coroutine continues from the bookmark
Syntax and Examples
Core syntax
A suspending function is declared with the suspend keyword:
suspend fun fetchUser(): String {
delay(1000)
return "Alice"
}
You can only call a suspend function from:
- another
suspendfunction, or - a coroutine builder such as
launchorasync
Example: a suspending function
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
suspend fun greetLater(): String {
delay(500)
return "Hello"
}
fun main() = runBlocking {
val message = greetLater()
println(message)
}
What happens here?
Step by Step Execution
Consider this example:
import kotlinx.coroutines.*
fun main() = runBlocking {
val deferred = async {
println("Inner: start")
delay(1000)
println("Inner: done")
10
}
println("Outer: before await")
val result = deferred.await()
println("Outer: after await = $result")
}
Step-by-step trace
1. runBlocking starts
fun main() = runBlocking {
- A coroutine starts.
- In this example,
runBlockingblocks the main thread until its work is finished.
2. async launches the inner coroutine
val deferred = async {
- A new coroutine starts.
- It will eventually produce a value and store it in
deferred.
Real World Use Cases
1. Waiting for an API call
suspend fun loadUserProfile(): User {
return api.getUser()
}
While waiting for the network response, the coroutine can suspend instead of blocking a thread.
2. Waiting for database results
suspend fun findOrder(id: Long): Order? {
return orderRepository.findById(id)
}
Database libraries with coroutine support use suspending functions so server threads are not wasted while I/O is in progress.
3. Coordinating concurrent work
val profile = async { loadProfile() }
val posts = async { loadPosts() }
val userProfile = profile.await()
val userPosts = posts.await()
One coroutine can wait for others to finish using await().
4. Retrying after a delay
suspend fun {
delay()
}
Real Codebase Usage
In real projects, developers use suspending functions as the standard way to represent asynchronous operations.
Common patterns
Guard clauses and validation
suspend fun loadUser(id: String): User {
require(id.isNotBlank()) { "id must not be blank" }
return api.fetchUser(id)
}
Validation happens immediately; suspension only happens if the function reaches a suspending call.
Early return
suspend fun maybeLoadUser(id: String?): User? {
if (id == null) return null
return api.fetchUser(id)
}
A suspend function can still return early like a normal function.
Concurrent async work
suspend fun loadDashboard(): Dashboard = coroutineScope {
val user = async { api.fetchUser() }
notifications = async { api.fetchNotifications() }
Dashboard(user.await(), notifications.await())
}
Common Mistakes
1. Thinking suspend means “runs on another thread”
Broken assumption:
suspend fun doWork() {
// This is not automatically background work
}
Why it is wrong:
suspendonly means the function may suspend- it says nothing by itself about thread choice
How to avoid it:
- use the appropriate dispatcher when needed
- remember that suspension and threading are related but different concepts
2. Thinking a suspending function always suspends
suspend fun immediateValue(): Int {
return 5
}
This is valid. A suspend function may never actually suspend during a particular call.
3. Thinking await() suspends the producer coroutine
Broken understanding:
deferred = async { }
x = deferred.await()
Comparisons
| Concept | What pauses? | Does the thread wait? | Typical example |
|---|---|---|---|
| Blocking | The thread | Yes | Thread.sleep(1000) |
| Suspending | The coroutine | No | delay(1000) |
| Term | Meaning |
|---|---|
suspend fun | A function that is allowed to suspend the current coroutine |
| Suspended coroutine | A coroutine whose execution is paused and can resume later |
await() | A suspending call that waits for a Deferred result |
Cheat Sheet
suspend fun myFunction() {
delay(1000)
}
Quick rules
suspendmeans a function may suspend the current coroutine.suspenddoes not mean the function creates a new thread.suspenddoes not mean the function always suspends.- A suspending function can only be called from:
- another
suspendfunction - a coroutine builder like
launch,async, orrunBlocking
- another
await()
val deferred = async { 42 }
val result = deferred.await()
asyncstarts a coroutine that produces a resultawait()waits for that result- if the result is not ready, suspends the
FAQ
What does suspend mean in Kotlin?
It means the function is allowed to pause the current coroutine and resume later without blocking the underlying thread.
Does a suspend function always suspend?
No. It may suspend, but it can also run straight through and return immediately.
Does suspend create a new thread?
No. Thread creation and thread selection are separate from the suspend keyword.
Which coroutine is suspended by await()?
The coroutine that calls await() is suspended if the result is not ready yet.
Does await() stop the async coroutine that is computing the result?
No. The async coroutine continues running. await() only waits for its result.
Can a suspended coroutine resume on another thread?
Yes. Depending on the dispatcher and runtime context, it may resume on the same or a different thread.
What is the difference between delay() and Thread.sleep()?
delay() suspends a coroutine without blocking a thread. blocks the thread.
Mini Project
Description
Build a small Kotlin program that starts one coroutine to calculate a value and another coroutine that waits for that result using await(). This demonstrates the exact idea behind suspend: the waiting coroutine pauses without blocking a thread, while the worker coroutine continues and eventually provides the result.
Goal
Create a runnable example that shows await() suspending the caller and resuming it when the async computation finishes.
Requirements
- Start an outer coroutine using
runBlocking. - Launch an inner coroutine with
asyncthat waits briefly and returns a value. - Print messages before and after calling
await(). - Use
delay()inside the inner coroutine. - Show from the output that the outer coroutine waits for the inner result.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.
Android Foreground Service Notification Channels in Kotlin
Learn why startForeground fails on Android 8.1 and how to create a valid notification channel for foreground services in Kotlin.