message: String = "",
    level: Level = Level.ERROR)

Signals that the annotated annotation class is a marker of an API that requires an explicit opt-in.

Call sites of any declaration that is either annotated with such a marker or mentions in its signature any other declaration that requires opt-in should opt in to the API either by using OptIn, or by being annotated with that marker themselves, effectively causing further propagation of the opt-in requirement.

The intended uses of opt-in markers include, but are not limited to the following:

  • Experimental API for public preview that might change its semantics or affect binary compatibility.
  • Internal declarations that should not be used outside the declaring library, but are public for technical reasons.
  • Fragile or delicate API that needs a lot of expertise to use and thus require an explicit opt-in.


When a declaration is marked with an opt-in requirement, it is considered to be contagious, meaning that all its uses or mentions in other declarations will require an explicit opt-in. A rule of thumb for propagating is the following: if the marked declaration ceases to exist, only the places with explicit opt-in (or the corresponding warning) will break. This rule does not imply transitivity, e.g. the propagation does not propagate opt-in through inlining, making it the responsibility inline function author to mark it properly.

Type scopes

A type is considered requiring opt-in if it is marked with an opt-in marker, or the outer declaration (class or interface) requires opt-in. Any use of any declaration that mentions such type in its signature will require an explicit opt-in, even if it is not used directly on the call site, and even if such declarations do not require opt-in directly.

For example, consider the following declarations that are marked with non-propagating opt-in:

class Unstable

fun foo(): Unstable = Unstable()

fun bar(arg: Unstable = Unstable()) {}

fun Unstable?.baz() {}

and their respective call sites:

fun outerFun() {
    val s = foo()

Even though call sites do not mention Unstable type directly, the corresponding opt-in warning or error will be triggered in each call site due to propagation contagiousness. Note that the propagation is not transitive, i.e. calls to outerFun itself would not trigger any further opt-in requirements.

Lexical scopes

If a type requires an opt-in, such requirement is propagated to its lexical scope and all its nested declarations. For example, for the following scope:

class Unstable {
    fun memberFun() = ...

    class NestedClass {
        fun nestedFun() = ...

Any use of Unstable, NestedClass, or their member functions will require an explicit opt-in.

Overridden declarations

Opt-in markers are also propagated through the inheritance and interface implementation. If the base declaration requires an opt-in, overriding it requires either an explicit opt-in or propagating the opt-in requirement.

See also Kotlin language documentation for more information.