REW

What Are Access Modifiers In Kotlin?

Published Aug 29, 2025 4 min read
On this page

Access modifiers, also known as visibility modifiers, are keywords in Kotlin that control the visibility and accessibility of declarations like classes, objects, interfaces, functions, properties, and constructors.

They enforce encapsulation, modularity, and abstraction, helping to create more secure, organized, and maintainable code.

Kotlin offers four visibility modifiers: public, private, protected, and internal.

public

public is the default visibility in Kotlin. If you don't specify any modifier, the declaration is public.

  • Accessibility: Accessible from anywhere in the codebase.

  • Use case: Use public for elements that are part of your public API and should be accessible globally.

  • **Example:**kotlin

    // Top-level function, public by default
    fun sayHello() {
        println("Hello, World!")
    }
    class Example {
        // Public property and method, visible everywhere
        val myProperty: String = "Public Property"
        fun myMethod() {
            println("Public Method")
        }
    }
    

    Use code with caution.

private

The private modifier restricts visibility to the containing scope, which can be a class or a file.

  • Accessibility:

    • Class members: A private member within a class is only accessible from within that class.
    • Top-level declarations: A private declaration (function, property, or class) in a file is only accessible from within the same file.
  • Use case: Ideal for encapsulating implementation details that should not be exposed to the outside world. This prevents unintended modification of internal state.

  • **Example:**kotlin

    // This top-level variable is only visible within this file
    private const val GREETING = "Hi"
    class EncapsulatedData {
        // This property is only accessible from inside this class
        private var secretKey: String = "verySecret"
        fun getSecret(): String {
            // Accessible here, but not outside the class
            return secretKey
        }
    }
    

    Use code with caution.

protected

The protected modifier is similar to private, but also allows visibility to subclasses. It cannot be used for top-level declarations.

  • Accessibility: A protected member is visible only within its own class and its subclasses.

  • Use case: Designed for inheritance scenarios where you want to expose certain members to child classes for overriding or reuse, but not to unrelated code.

  • Note on Kotlin vs. Java: In Java, a protected member is also accessible from other classes in the same package. Kotlin does not have this behavior, making its protected modifier more restrictive and secure.

  • **Example:**kotlin

    open class Shape {
        protected val shapeName: String = "Shape"
    }
    class Circle : Shape() {
        fun printShapeName() {
            // Can access 'shapeName' because Circle is a subclass of Shape
            println("The shape name is: $shapeName")
        }
    }
    fun main() {
        val circle = Circle()
        circle.printShapeName() // Works
        // val shape = Shape()
        // println(shape.shapeName) // ERROR: shapeName is protected
    }
    

    Use code with caution.

internal

The internal modifier limits visibility to the same module, which is a set of Kotlin files compiled together.

  • Accessibility: Accessible from any declaration within the same module.

  • Use case: Useful in multi-module projects or libraries to expose APIs within the library while hiding internal implementations from external users.

  • **Example:**kotlin

    // In Module A
    internal class InternalService {
        fun doInternalWork() {
            println("Performing internal task...")
        }
    }
    // In Module A
    class PublicApi {
        fun executeWork() {
            InternalService().doInternalWork()
        }
    }
    // In Module B (different module)
    // val service = InternalService() // ERROR: InternalService is internal to Module A
    

    Use code with caution.

Visibility with constructors and properties

Access modifiers can also be applied to constructors and property setters for finer control.

  • Constructors: By default, constructors have the same visibility as their class. To change this, use the constructor keyword explicitly.kotlin

    class InternalClass internal constructor() // Constructor is internal
    class PrivateFactory private constructor() {
        companion object {
            fun create(): PrivateFactory {
                return PrivateFactory()
            }
        }
    }
    

    Use code with caution.

  • Property Setters: A property's setter visibility can be set separately from its getter.kotlin

    var myProperty: String = "value"
        private set // Setter is private, getter is public
    

    Use code with caution.

Nested vs. inner classes

Nested and inner classes have distinct visibility rules. A nested class's private members are not accessible to the outer class. An inner class, however, can access the outer class's members because it holds a reference to an outer class instance.

Summary of visibility scope

Modifier Top-Level Declarations Class Members Constructor
public Visible everywhere Visible everywhere Visible everywhere the class is visible
private Visible only within the same file Visible only within the containing class Visible only within the containing class
protected Not allowed Visible within the containing class and its subclasses Visible within the containing class and its subclasses
internal Visible only within the same module Visible to any client in the same module Visible only within the same module
Enjoyed this article? Share it with a friend.