Question
What does the asterisk (*) before a variable mean in Kotlin? In this Spring Boot Kotlin application, why is *args passed to SpringApplication.run?
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.Bean
@SpringBootApplication
open class Application {
@Bean
open fun init(repository: CustomerRepository) = CommandLineRunner {
repository.save(Customer("Jack", "Bauer"))
repository.save(Customer("Chloe", "O'Brian"))
repository.save(Customer("Kim", "Bauer"))
repository.save(Customer("David", "Palmer"))
repository.save(Customer("Michelle", "Dessler"))
}
}
fun main(args: Array<String>) {
SpringApplication.run(Application::class.java, *args)
}
Short Answer
The * in *args is Kotlin’s spread operator. It expands the elements of an array so they can be supplied as separate arguments to a function with a vararg parameter. You will learn when it is required, how it differs from an ordinary array argument, and why it appears in Spring Boot startup code.
Concept
Kotlin uses the spread operator (*) when an array must be expanded into individual arguments for a vararg parameter.
A vararg parameter lets a function accept zero or more values of one type:
fun announce(vararg names: String) {
println(names.joinToString())
}
You can call it with separate values:
announce("Ada", "Linus", "Grace")
But if those values are already stored in an array, Kotlin does not expand the array automatically. You must write *:
val names = arrayOf("Ada", "Linus", "Grace")
announce(*names)
In the Spring Boot example, args has type Array<String>, while SpringApplication.run accepts application arguments as a variable number of strings. *args turns the array contents into separate arguments.
The operator is used in an expression, such as a function call. It is not a general prefix operator that can be put before any variable declaration or arbitrary variable use.
Mental Model
Think of a vararg function as a row of individual input slots:
announce(slot 1, slot 2, slot 3, ...)
An array is a single box containing several items:
names = ["Ada", "Linus", "Grace"]
The spread operator opens the box and places each item into its own slot:
announce(*names)
^ opens the array for this call
Without *, Kotlin sees one box where it expects individual items.
Syntax and Examples
The basic syntax is:
functionWithVararg(*arrayVariable)
Here is a complete example:
fun printScores(vararg scores: Int) {
println(scores.joinToString(separator = ", "))
}
fun main() {
val dailyScores = intArrayOf(12, 18, 25)
printScores(5, 8)
printScores(*dailyScores)
}
Output:
5, 8
12, 18, 25
printScores receives an IntArray internally, but callers can provide separate Int values. Since dailyScores is already an IntArray, *dailyScores expands it into 12, 18, 25.
You can also combine normal arguments with a spread array:
val extraScores = intArrayOf(20, 30)
printScores(10, *extraScores, 40)
This passes 10, 20, 30, and 40.
Step by Step Execution
Consider this program:
fun logTags(vararg tags: String) {
println(tags.joinToString(separator = " | "))
}
fun main() {
val requestTags = arrayOf("api", "authenticated")
logTags("production", *requestTags)
}
Execution trace:
-
requestTagsis created as oneArray<String>containing"api"and"authenticated". -
logTagsis called with"production"as its first argument. -
*requestTagsspreads the two array elements into the call. -
The effective call is equivalent to:
logTags("production", "api", "authenticated") -
Inside
logTags, thetagsvararg parameter contains all three strings. -
joinToStringproduces:production | api | authenticated
Real World Use Cases
Common uses of the spread operator include:
- Application startup arguments: Passing
main(args: Array<String>)to a framework method that acceptsvararg String, as in Spring Boot. - Logging or formatting APIs: Sending an existing collection of message parts to a
varargfunction. - Test setup: Passing an array of expected values into assertion helpers that use
vararg. - UI construction: Giving a function a dynamically built set of modifiers, styles, or child values when its API uses
vararg. - Java interoperability: Calling Java methods or constructors that use Java varargs from Kotlin.
For example, Java-style formatting methods often accept varargs:
val values = arrayOf("Sam", 3)
val message = String.format("Hello %s, you have %d alerts", *values)
The array is expanded so each value becomes its own formatting argument.
Real Codebase Usage
In production code, developers usually use * at the boundary where dynamically assembled arrays meet a vararg API.
Forwarding command-line arguments
fun main(args: Array<String>) {
SpringApplication.run(Application::class.java, *args)
}
This preserves every command-line option supplied to the application.
Forwarding one vararg parameter to another
fun addAuditTags(vararg tags: String) {
saveAuditRecord("created", *tags)
}
fun saveAuditRecord(event: String, vararg tags: String) {
println("$event: ${tags.joinToString()}")
}
A vararg parameter behaves as an array inside the function, so it must be spread again when forwarded to another vararg parameter.
Prefer typed arrays
Use the array type expected by the vararg parameter:
val ids = longArrayOf(10L, 20L)
processIds(*ids)
fun processIds(vararg ids: Long) {
// ...
}
This avoids unnecessary conversions and makes the intended element type clear.
Common Mistakes
Forgetting * when passing an array
This does not compile because send expects individual String values, not an Array<String> argument:
fun send(vararg recipients: String) {}
val recipients = arrayOf("a@example.com", "b@example.com")
send(recipients) // Error
Fix it:
send(*recipients)
Using * with a non-array value
The spread operator requires an array expression compatible with the vararg element type:
val name = "Ada"
// greet(*name) // Invalid: String is not an array
Use the value directly:
greet(name)
Trying to spread a List directly
A List<String> is not an Array<String>:
val names = listOf("Ada", "Grace")
// announce(*names) // Invalid
Convert it first:
announce(*names.toTypedArray())
Confusing Array<Int> and IntArray
Kotlin has generic arrays such as Array<String> and specialized primitive arrays such as IntArray. A vararg Int works naturally with IntArray:
fun total(vararg values: Int) = values.sum()
val values = intArrayOf(1, 2, 3)
println(total(*values))
Do not assume Array<Int> and IntArray are interchangeable; they are different types.
Adding * when values are already separate
No spread operator is needed here:
announce("Ada", "Grace")
Use * only when the arguments are currently held in an array.
Comparisons
| Situation | Correct approach | Why |
|---|---|---|
Separate values for a vararg | printNames("Ada", "Grace") | Each value is already a separate argument. |
Array<String> for vararg String | printNames(*names) | The array must be expanded. |
List<String> for vararg String | printNames(*names.toTypedArray()) | Convert the list to an array, then spread it. |
IntArray for vararg Int | sum(*numbers) | The primitive array matches Int vararg. |
One array parameter, not vararg | process(names) | The function expects the array itself; no spreading is needed. |
Compare these two function declarations:
fun acceptsArray(names: Array<String>) {}
fun acceptsVararg(vararg names: String) {}
val names = arrayOf("Ada", "Grace")
acceptsArray(names) // Passes one array
acceptsVararg(*names) // Passes each array element
Array<String> means “one array argument.” vararg String means “zero or more string arguments.”
Cheat Sheet
// Declare a vararg parameter
fun greet(vararg names: String) {}
// Pass individual values
greet("Ada", "Grace")
// Spread an Array<String>
val names = arrayOf("Ada", "Grace")
greet(*names)
// Spread a primitive array for vararg Int
fun sum(vararg values: Int) = values.sum()
val values = intArrayOf(1, 2, 3)
sum(*values)
// Spread a list after conversion
val list = listOf("Ada", "Grace")
greet(*list.toTypedArray())
// Mix normal values and an array
greet("Linus", *names, "Margaret")
Rules:
- Use
*only when passing an array into a compatiblevarargparameter. - Do not use
*for values that are already separate arguments. - A
Listmust be converted withtoTypedArray()before spreading. - Use
intArrayOf,longArrayOf, and similar primitive arrays for primitive varargs. - A
varargparameter is accessible as an array inside the function.
FAQ
What does *args mean in Kotlin?
It is the spread operator applied to args. It expands the elements of the Array<String> so they are passed as separate vararg arguments.
Why does Spring Boot use *args in main?
main receives command-line arguments as Array<String>. SpringApplication.run accepts application arguments as varargs, so Kotlin needs *args to forward them.
Is the Kotlin spread operator the same as JavaScript ...?
They serve a similar purpose: expanding values into a call. Kotlin uses * for arrays in vararg calls; JavaScript uses ... and supports more iterable contexts.
Can I use the spread operator with a Kotlin List?
Not directly. Convert the list to an array first:
function(*items.toTypedArray())
Does every function call with an array need *?
No. Use * only when the receiving parameter is vararg. If a function expects an array parameter, pass the array normally.
Can a vararg parameter be used like an array inside a function?
Yes. Kotlin exposes it as an array, so you can iterate over it, access indexes, or call array operations.
Can I mix normal arguments and a spread array?
Yes, as long as the values have the correct type:
greet("First", *moreNames, "Last")
Mini Project
Description
Build a small command-line tag reporter. It accepts command-line arguments as tags and forwards them from main to a function that uses a vararg parameter. This mirrors the same array-to-vararg forwarding used in Spring Boot startup code.
Goal
Use *args to pass command-line arguments into a Kotlin vararg function and print a readable report.
Requirements
- Create a Kotlin
mainfunction that acceptsargs: Array<String>. - Create a function named
reportTagswith avararg Stringparameter. - Forward the command-line array to
reportTagsusing the spread operator. - Print a message when no tags were supplied.
- Print each supplied tag with its position.
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.
Add a Maven Repository URL in Gradle Kotlin DSL (build.gradle.kts)
Learn how to add Maven Central and a custom Maven repository URL in Gradle Kotlin DSL using build.gradle.kts syntax.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.