Skip to content

Decorators

Attach checked compiler, tooling, runtime, and data metadata to source declarations.

Updated View as Markdown

A decorator begins with @ and precedes the declaration, field, parameter, or binding it modifies.

@inline
fn small(value: int): int {
    return value + 1
}

@sealed
trait InternalProtocol {
    fn execute(self): void
}

The parser preserves arbitrary decorator syntax. A decorator has behavior only when a compiler pass, tool, runtime adapter, or domain subsystem recognizes it.

Syntax

A decorator name is lowercase and can be dotted for a subsystem namespace.

@sql.name("booking_records")
model Booking {
    @id
    id: int
}

Arguments are parsed as expressions, but every recognized decorator defines a narrower compile-time argument contract. A decorator written without parentheses has no arguments.

Multiple decorators can apply to one target. Their source order normally does not change their meaning.

@host("clock", "monotonic")
@suspend
fn monotonic_time(): int

Compilation

These decorators affect ordinary program compilation:

Decorator Target Meaning
@allow(naming) Supported declaration Suppress its naming diagnostic
@derive(Trait, ...) Struct or enum Synthesize supported trait implementations
@sealed Trait Restrict implementations to the declaring file
@inline Function Request inlining
@inline(always) Function Require inlining where valid
@noinline Function Prevent inlining
@linear Local binding Require linear-use checking
@externalizable Struct or enum Opt into serialization code generation
@extern Struct or enum Alias of @externalizable
@weak Field Store a supported optional reference weakly

@derive requires one or more bare trait names.

@derive(Equatable, Hashable)
struct Coordinate {
    x: int
    y: int
}

Only compiler-supported derivations can be synthesized. @derive is not a general macro system and does not execute arbitrary user code.

The naming lint is currently opt-in. Its suppression is retained on functions, structs, enums, error types, traits, error unions, and implementation blocks. Enum-level suppression also covers variants. Aliases and constants do not currently retain declaration decorators for this lint. See Naming conventions for exact coverage.

@weak has layout and type restrictions. It applies to supported nullable reference-shaped fields, not scalars, strings, tuples, or non-optional values. See References.

Tooling

The CLI recognizes entry-point decorators:

Decorator Meaning
@test Discover a function as a test
@bench Discover a function as a benchmark
@ignore Skip a discovered test unless ignored tests are requested

They take no arguments. @test is diagnosed on non-function declarations.

@test
fn addition_works(): void {
    assert(20 + 22 == 42)
}

Runtime

The prelude and runtime adapter use low-level decorators:

Decorator Meaning
@host("namespace", "name") Bind a function to a typed host import
@pure Mark a host binding synchronous and non-suspending
@suspend Mark a function as a suspension source
@builtin Mark a declaration supplied by compiler lowering
@intrinsic Bind a function to its same-named intrinsic
@intrinsic("name") Bind an explicit intrinsic name
@niche Select a compiler-known niche representation
@cycle_free Assert that an internal type cannot form RC cycles

These are part of the compiler/runtime ABI. Application code should normally call safe standard-library functions rather than declare new host imports or intrinsics.

@host requires exactly two string arguments. @builtin, @pure, @suspend, @niche, and @cycle_free take no arguments. @builtin and @host conflict. @pure requires @host and conflicts with @suspend.

The removed @kind routing decorator produces a migration diagnostic. Use a two-argument @host binding instead.

Data

The data layer recognizes decorators such as @id, @unique, @sql.name, @sql.function, full-text metadata, vector dimensions, and selected index options.

@sql.name("people")
model Person {
    @id
    id: int

    @unique
    email: string
}

Their valid targets, arguments, and engine restrictions are documented in Models and Schemas.

Unknown names

Core parsing retains an unknown decorator so domain-specific tools can inspect it. Core sema may otherwise ignore the name.

@acme.reviewed("2026-07")
fn calculate(): int => 42

Preservation does not mean that the decorator executes, validates its arguments, changes code generation, or exists at runtime. A subsystem must document and implement those semantics.

The legacy docs/decorators/ catalog proposes actor, job, UI, auth, AI, MCP, HTTP-routing, and event decorators. Those application systems are not current core-language features and remain classified under Feature Status.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close