Kotlin Get Started (Hello World)

Every Kotlin journey starts with the same three lines: a function called main, a call to println, and a string in quotes. This lesson walks through writing, compiling, and running that first program, and explains exactly what happens between typing the source code and seeing text appear on your screen. By the end you’ll understand not just how to type "Hello, World!", but how Kotlin turns it into a running program on the Java Virtual Machine (JVM).

Overview / How It Works

Kotlin is a modern, statically-typed language created by JetBrains. Its most common target is the JVM: when you compile a .kt file with the Kotlin compiler, kotlinc, it produces JVM bytecode — the exact same kind of .class files the Java compiler produces. That shared bytecode format is why Kotlin can call Java libraries directly, why IntelliJ IDEA (also built by JetBrains) runs Kotlin and Java side by side in one project, and why any machine with a Java runtime installed can execute a compiled Kotlin program.

If you have a Java background, the first surprise is that Kotlin does not force every piece of code to live inside a class. A Java "Hello, World!" needs a class wrapping a public static void main(String[] args) method before anything can run. Kotlin lets you declare a top-level function named main directly in a file, with no enclosing class at all. The compiler still generates the equivalent class-with-static-method bytecode behind the scenes — the JVM has no concept of a "classless" function — but you never have to type that ceremony yourself. This is one of the clearest cases where Kotlin is simply a less verbose Java: the same runtime behavior, far less boilerplate.

fun main() is the entry point the JVM looks for when it starts your program. Kotlin accepts two shapes for it: fun main() with no parameters, and fun main(args: Array<String>), which receives whatever command-line arguments were passed to the program as an array of strings (an empty array, not null, if none were passed — Kotlin’s null safety means args is always a real, non-null Array<String>, never a nullable reference you’d have to check).

println() is a top-level function from the Kotlin standard library (package kotlin.io) that writes a value followed by a line separator to standard output. Its sibling, print(), writes the value with no trailing newline. Both are thin wrappers around Java’s System.out — Kotlin just spares you from typing System.out.println(...) every single time.

Syntax

The general shape of a minimal Kotlin program is:

fun main() {
    println("some text")
}
Part Meaning
fun Keyword that declares a function.
main The function name the JVM looks for as the program’s entry point.
() or (args: Array<String>) The parameter list — empty, or a single parameter holding command-line arguments.
{ } The function body: the block of statements executed when the program runs.
println("...") A call to the standard library function that prints text plus a trailing newline.

String literals must be wrapped in double quotes. Inside a string, $name or ${expression} is a string template — Kotlin substitutes the value at that point instead of you concatenating strings with +.

Examples

Example 1: The classic Hello World

fun main() {
    println("Hello, World!")
}
Hello, World!

A single top-level function, main, is the whole program. Inside it, one statement calls println with a string literal. When the JVM runs the compiled program, it invokes main, which executes that one statement and prints the text followed by a newline.

Example 2: Using a variable and a string template

fun main() {
    val name = "Kotlin"
    println("Hello, $name!")
    println("Welcome to programming.")
}
Hello, Kotlin!
Welcome to programming.

Here val name = "Kotlin" declares a read-only reference; Kotlin infers its type as String from the value on the right, so you don’t need to write val name: String = "Kotlin" explicitly (though you could). The string template $name inside the second string is replaced with the variable’s value at print time. Statements inside main run strictly top to bottom, so the two println calls print on separate lines in the order they appear.

Example 3: Calling a function from main

fun greet(name: String): String {
    return "Hello, $name! Welcome to Kotlin."
}

fun main() {
    val userName = "Ava"
    val message = greet(userName)
    println(message)
    println("Today you wrote your first Kotlin program.")
}
Hello, Ava! Welcome to Kotlin.
Today you wrote your first Kotlin program.

This example shows that a Kotlin file can hold more than one top-level function — greet and main sit side by side with no enclosing class. greet takes a non-null String parameter and returns a non-null String; there’s no way to accidentally pass or return null here without the compiler flagging it, because neither type is marked with ?. main calls greet, stores the result in a val, and prints it.

Example 4: Reading command-line arguments

fun main(args: Array) {
    println("Hello, World!")
    println("Number of arguments received: ${args.size}")
}
Hello, World!
Number of arguments received: 0

This is the second valid form of main. When you run the compiled program without passing any extra arguments on the command line, args is a real, non-null, empty array, so args.size is 0. If you ran it as java -jar hello.jar foo bar instead, args would contain ["foo", "bar"] and args.size would print 2.

How It Works Step by Step

Getting from source code to printed text involves a few concrete steps:

1. You save your code in a file with a .kt extension, for example Hello.kt.

2. You compile it. From the command line: kotlinc Hello.kt -include-runtime -d hello.jar turns the source into JVM bytecode and bundles the Kotlin runtime into a single runnable .jar. In an IDE like IntelliJ IDEA, clicking the green "Run" arrow next to fun main() does the same compilation behind the scenes. For quick experiments with no local install at all, the online Kotlin Playground compiles and runs snippets in the browser.

3. You run the compiled program: java -jar hello.jar. The JVM starts, loads the generated class, and locates the entry point that corresponds to your top-level main function.

4. The JVM executes the statements inside main‘s body in order, top to bottom. Each println call writes its text to standard output immediately.

5. When main finishes executing (falls off the end of its body, since it returns Unit), the process exits. If an exception is thrown and never caught, the program exits with a nonzero status and prints a stack trace instead of completing normally.

Common Mistakes

Mistake 1: Forgetting the fun keyword

Coming from a scripting-language background, it’s easy to try writing a function without its keyword:

main() {
    println("Hello, World!")
}

This does not compile. At the top level of a .kt file, Kotlin only accepts declarations (functions, classes, properties, and a few others) — a bare call like main() { ... } isn’t a valid declaration, so the compiler reports something like "expecting a top level declaration." The fix is to always start a function with fun:

fun main() {
    println("Hello, World!")
}

Mistake 2: Wrong capitalization

Kotlin is case-sensitive, and it’s common to mistype the standard library function’s casing, especially if you’re used to languages with capitalized method names:

fun main() {
    Println("Hello, World!")
}

This fails with an unresolved reference error — there is no Println in the standard library, only println (lowercase). Kotlin will not silently match it for you:

fun main() {
    println("Hello, World!")
}

Mistake 3: Wrapping main in a class out of Java habit

Java developers sometimes assume Kotlin needs the same class-wrapper ceremony:

class Main {
    fun main() {
        println("Hello, World!")
    }
}

This actually compiles — main is a perfectly legal member function name inside a class — but it is not an entry point. The JVM looks for a static main method, and a plain instance method inside a class doesn’t qualify, so running it fails at launch with an error like "Main method not found in class Main." The fix is to drop the class entirely and declare main as a top-level function, exactly as in Examples 1–3 above.

Best Practices

  • Declare fun main() (or fun main(args: Array<String>) if you need command-line arguments) as a top-level function — you don’t need a wrapping class to run a Kotlin program.
  • Prefer println() when each piece of output should sit on its own line; reserve print() for building a single line piece by piece.
  • Default to val for anything that doesn’t need to change after its first assignment; reach for var only when a value genuinely must be reassigned later.
  • Use string templates ("Hello, $name") instead of concatenation ("Hello, " + name) — they read more clearly and avoid manual type conversions.
  • Try the Kotlin Playground or your IDE’s built-in run button first, so you can focus on the language before learning the full command-line kotlinc/java workflow.
  • Give source files descriptive names (Hello.kt) — unlike Java, a Kotlin file with only top-level functions isn’t required to match a class name.

Practice Exercises

1. Modify the first Hello World program so it greets you by name using a string template, e.g. it should print something like Hello, Priya!.

2. Declare two val variables — a String for your favorite programming language and an Int for how many years you’ve been coding (use 0 if you’re just starting) — and print one sentence that combines both using string templates.

3. Write a function fun sayHello(name: String): String that returns a greeting string, then call it twice from main() with two different names, printing both results on separate lines.

Summary

  • Kotlin source compiles with kotlinc into JVM bytecode, so compiled programs run on the JVM and interoperate directly with Java.
  • fun main() is a top-level function, not a method inside a class — no boilerplate wrapper class is needed to run a program.
  • main can optionally take args: Array<String> to receive command-line arguments; if none are passed, args is a non-null, empty array.
  • println() writes text plus a trailing newline to standard output; print() omits the newline.
  • Kotlin is case-sensitive, and every top-level line in a file must be a declaration (a function, class, or property), not a bare statement.
  • val declares a read-only reference; prefer it over var unless the value truly needs to change later.