Realms

Lux treats GMod realms as part of the language. client, server, and shared are not just output folders; they affect name availability, imports, exports, generated artifacts, and diagnostics.

The goal is to remove manual if SERVER then AddCSLuaFile(...) end loader plumbing while still catching code that would call the wrong API in the wrong artifact.

Realm Sources

A declaration's default realm comes from the part file:

cl_*.lux        client
sv_*.lux        server
sh_*.lux        shared
client/**/*.lux client
server/**/*.lux server
shared/**/*.lux shared
unmarked files shared

If a prefix conflicts with the nearest realm directory, compilation fails. For example, server/cl_panel.lux is ambiguous and rejected.

Realm-marked Declarations

You can mark declarations explicitly. The marker works with exported and private declarations.

Realm-marked declarations
server fn grantItem(ply, id) {
  giveItem(ply, id)
}

client fn openInventoryPanel() {
  vgui.Create("LuxInventoryPanel")
}

The marker is not tied to export. A private server helper is still server-only.

Private realm helper and public export
server fn grantInternal(ply, itemId) {
  giveItem(ply, itemId)
}

export server { grant = grantInternal }

Top-level declarations default to the importer part's effective realm unless an explicit marker narrows or changes them.

Realm Blocks

Realm blocks express fine-grained client/server sections inside otherwise shared code. They are the Lux replacement for GLua's repeated if SERVER then or if CLIENT then blocks.

Realm blocks
fn ENT:Initialize() {
  self:DrawShadow(false)
  self:SetNoDraw(true)

  server {
    self:PhysicsInitBox(Vector(-20, -20, 0), Vector(20, 20, 86))
  }

  self:SetCustomCollisionCheck(true)
}

The server block is checked as server-only code. The surrounding function may still be shared.

Shared Does Not Mean Every Line Is Shared

Shared files often contain server-only setup and client-only UI pieces. The rule is not "a shared file can never mention server APIs"; the rule is "shared context cannot use a server-only value unless the use is inside a server-only context."

Fine-grained realms inside a shared function
fn ENT:Initialize() {
  self:SetCustomCollisionCheck(true)

  server {
    local phys = self:GetPhysicsObject()
    if phys:IsValid() {
      phys:EnableMotion(false)
    }
  }

  client {
    self:SetRenderBounds(Vector(-20, -20, 0), Vector(20, 20, 86))
  }
}

Realm blocks are also useful inside macro expansions and host transforms because they make the intended availability explicit.

Import Checks

An imported binding carries the export realms of the source module. The checker compares that availability to the active use-site realm.

server-only import can only be used in server context
import { grant } from "inventory"

fn sharedTick(ply) {
  grant(ply, "coin")
}

Move the use into a server declaration or a server block.

Server function in a shared file
import { grant } from "inventory"

server fn grantCoin(ply) {
  grant(ply, "coin")
}

The file can still be sh_module.lux; the function itself is server-only.

External API Availability

Lux uses three availability categories:

Lux symbol       -> strict
known GMod API   -> strict
unknown external -> allow + warning by default

Internally, unknown external symbols are not treated as shared. They keep a separate availability:

RealmAvailability =
  Known(shared | client | server)
  | UnknownExternal

Known realm mismatch is an error. Unknown external use is allowed with a warning by default because real GMod addons often use dynamic globals, third-party libraries, and binary modules that Lux cannot fully know.

The default warning looks like this:

warning[REALM_UNKNOWN]:
cannot verify realm availability of external symbol `ThirdPartyAddon`
used in shared context inside `run`

Add an extern declaration to make this strict:
  extern shared ThirdPartyAddon
  extern client ThirdPartyAddon
  extern server ThirdPartyAddon

Projects can choose how strict unknown externals should be:

[target.gmod.realm]
unknown_external = "warn" # allow | warn | error

warn is the default. error is useful for CI once a project has declared its externs.

Extern Declarations

Use extern when Lux should know the realm of an external symbol.

Source extern
extern server ThirdPartyAddon

server fn runAddon() {
  ThirdPartyAddon.Start()
}

Member-level extern declarations support APIs whose root table is shared but individual members are realm-specific.

Member-level extern
extern shared net
extern server net.Start
extern client net.Receive

Package-level externs belong in lux.toml when a team wants declarations in one place.

[target.gmod.extern]
ThirdPartyAddon = "server"
FancyHud = "client"
SharedLibrary = "shared"

[target.gmod.extern."ThirdPartyAddon.DoSomething"]
realm = "server"

Lux ships common GMod API realm data, but it cannot fully cover the whole addon ecosystem. Unknown external use remains allowed by default with a warning; if you ignore that warning, you are accepting the runtime risk yourself.