What is `suspend fun main` and when would you use it?
answer
- suspend main = call suspend fns without runBlocking
- Added in Kotlin 1.3
- Compiler generates a synthetic blocking main
- Still blocks the launching thread
- Great for scripts; use runBlocking/scope in real apps
basics
~20 ssuspend fun main lets the program's entry point call suspending coroutine functions directly, without manually creating a runBlocking block. The runtime starts a coroutine for you and waits until it finishes before the program exits.
solid answer
~40 sSince Kotlin 1.3, you can mark the entry point `suspend fun main()` or `suspend fun main(args: Array<String>)`. This lets you call `suspend` functions (like `delay`) directly in `main` without wrapping them in `runBlocking { }`. Under the hood the compiler generates a synthetic non-suspend `main` that bootstraps a coroutine via an internal `runSuspend`-style helper and blocks the launching thread until the top-level coroutine completes — so the JVM still gets an ordinary `static main(String[])` to call. It's mainly a convenience for small programs, scripts, and examples. In production apps you usually still use an explicit `runBlocking` or a structured `CoroutineScope` so you control the dispatcher, exception handling, and scope. `suspend main` runs on the default single-threaded event loop unless you switch context.
code
kotlin · 11 linesimport kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.delay
suspend fun main() = coroutineScope {
launch {
delay(500)
println("world")
}
println("hello")
}go deeper
Knows suspend main lets you call delay/suspend functions without runBlocking.
Explains the synthetic blocking launcher and that it still blocks the launching thread until completion.
Weighs suspend main vs explicit runBlocking/scope for dispatcher, exception handling, and structured concurrency.
Considers startup architecture, lifecycle ownership, and why production entry points usually centralize scope/dispatcher policy rather than rely on suspend main.
## The problem it solves A **suspending function** (`suspend fun`) can pause and resume without blocking a thread — but it can only be called from another `suspend` function or a coroutine builder. Normally, to call one from a plain `main`, you'd write: ```kotlin import kotlinx.coroutines.* fun main() = runBlocking { delay(1000) println("done") } ``` `runBlocking` bridges the non-suspending world (`main`) and the suspending world by blocking the current thread until its coroutine finishes. ## What `suspend main` does Since **Kotlin 1.3**, you can declare the entry point itself as suspending: ```kotlin import kotlinx.coroutines.delay suspend fun main() { println("start") delay(1000) // calling a suspend fun directly println("done") } ``` No `runBlocking` needed. You can call `suspend` functions like `delay` straight from `main`. ## How it works under the hood The JVM can only launch a plain `static main(String[])`. So the Kotlin compiler generates a **synthetic, non-suspend `main`** that: 1. Starts the top-level coroutine for your `suspend fun main` using an internal runner (a `runSuspend`/event-loop helper from the standard library — note this needs `kotlin-stdlib`, and for `delay` you also need `kotlinx-coroutines`). 2. Blocks the launching thread until that coroutine completes, then returns. So from the JVM's view it's still an ordinary blocking `main`. ## When to use it (and not) - **Use it** for scripts, demos, CLI tools, and small programs where coroutine setup boilerplate isn't worth it. - **Prefer explicit `runBlocking` / a `CoroutineScope`** in real applications, because you often need to pick a dispatcher (`Dispatchers.IO`), install a `CoroutineExceptionHandler`, or apply structured concurrency. `suspend main` gives you a bare event-loop context with little control. ## Gotchas - It blocks the launching thread just like `runBlocking` — it's not magic non-blocking startup. - All four signatures are valid: `fun main()`, `fun main(args)`, `suspend fun main()`, `suspend fun main(args)`. - Mixing a regular `main` and a `suspend main` in the same file is ambiguous and should be avoided. ## Key keywords/APIs - `suspend` — marks a function as suspendable. - `delay` — a suspend function that pauses without blocking. - `runBlocking` — bridges blocking and suspending worlds. - `CoroutineScope`, `Dispatchers`, `CoroutineExceptionHandler` — the control you give up with bare `suspend main`.
- Does `suspend main` make program startup non-blocking?No. The generated launcher still blocks the launching thread until the top-level coroutine completes — just like `runBlocking`.
- Why might you still prefer `runBlocking` in production?To explicitly choose a dispatcher, install exception handling, and apply structured concurrency — control that bare `suspend main` doesn't expose.
It's a built-in runBlocking doormat at the front door — you step from the blocking street straight into coroutine-land.
saying these in an interview costs you the question
- Claiming `suspend main` runs asynchronously and returns immediately
- Saying you can call any suspend function from a normal `fun main` without a builder
- Not knowing it was added in Kotlin 1.3
- Thinking `suspend main` requires no stdlib/coroutines support at all
- Believing `suspend main` removes the need for a dispatcher entirely in complex apps