Skip to content

Scopes

A scope groups declarations under a name. Inside the schema it is a namespace; in the generated modules it becomes a nested table and a prefix on type names. Use scopes to keep a large schema organised by feature – Shop, Combat, Admin – rather than as one flat list.

Write scope, a name, and the declarations inside braces. A scope may hold types, events, functions and other scopes:

type Coins = u32
scope Shop {
type ItemId = u16
struct Offer {
Item: ItemId,
Price: Coins,
}
event OffersChanged {
From: Server,
Type: Reliable,
Call: SingleSync,
Data: Offer[..32]
}
scope Admin {
event SetPrice {
From: Client,
Type: Reliable,
Call: SingleSync,
Rate: 1,
Data: Offer
}
}
}
struct Receipt {
Item: Shop.ItemId,
Paid: Coins,
}

Options cannot go in a scope: they apply to the whole schema and must come before any declaration.

Inside a scope, everything declared around it is visible. Offer uses ItemId from its own scope and Coins from the top level without qualifying either, and SetPrice in the nested Admin scope uses Offer the same way.

Outside a scope, qualify the name with the scope’s. Receipt writes Shop.ItemId. A nested scope takes one qualifier per level: Shop.Admin.SomeType. An unqualified name from inside a scope is an unknown reference outside it.

A scope is not a way to reuse a name. A declaration inside a scope may not repeat a name already visible from it – one declared at the top level, or in any scope around it:

Refused: T is already declared at the top level
type T = u8
scope Inner {
type T = u16
}

Sibling scopes are separate, so Shop.ItemId and Inventory.ItemId can both exist, and so can two events named Changed in two different scopes.

A scope’s name is declared once. Writing scope Shop { ... } a second time is a duplicate declaration, not a continuation of the first.

A scope becomes a nested table of the module, holding its events and functions. Its types are exported with the scope’s names joined to the type’s by underscores:

Server.luau
local Net = require(path.to.Server)
Net.Shop.OffersChanged.FireAll({
{ Item = 1, Price = 250 },
})
Net.Shop.Admin.SetPrice.On(function(Player: Player, Offer: Net.Shop_Offer)
-- ...
end)
local Id: Net.Shop_ItemId = 1

A type in a nested scope takes every level: an ItemId in Shop.Admin is exported as Net.Shop_Admin_ItemId.

Imports are scopes too: an imported file’s declarations land in a scope named after the file, and everything on this page applies to them.