Question

Kotlin Spread Operator (*) Before an Array Variable

kotlinsyntax

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.

Take Quiz

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:

  1. requestTags is created as one Array<String> containing "api" and "authenticated".

  2. logTags is called with "production" as its first argument.

  3. *requestTags spreads the two array elements into the call.

  4. The effective call is equivalent to:

    logTags("production", "api", "authenticated")
    
  5. Inside logTags, the tags vararg parameter contains all three strings.

  6. joinToString produces:

    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 accepts vararg String, as in Spring Boot.
  • Logging or formatting APIs: Sending an existing collection of message parts to a vararg function.
  • 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.

Take Quiz

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

SituationCorrect approachWhy
Separate values for a varargprintNames("Ada", "Grace")Each value is already a separate argument.
Array<String> for vararg StringprintNames(*names)The array must be expanded.
List<String> for vararg StringprintNames(*names.toTypedArray())Convert the list to an array, then spread it.
IntArray for vararg Intsum(*numbers)The primitive array matches Int vararg.
One array parameter, not varargprocess(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.”

Take Quiz

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 compatible vararg parameter.
  • Do not use * for values that are already separate arguments.
  • A List must be converted with toTypedArray() before spreading.
  • Use intArrayOf, longArrayOf, and similar primitive arrays for primitive varargs.
  • A vararg parameter 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")
Take Quiz

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

  1. Create a Kotlin main function that accepts args: Array<String>.
  2. Create a function named reportTags with a vararg String parameter.
  3. Forward the command-line array to reportTags using the spread operator.
  4. Print a message when no tags were supplied.
  5. Print each supplied tag with its position.
Take Quiz

Keep learning

Related questions

View more