roblox-luau-patterns · git:20261015.28be409 · 2026-10-15 · sha256 a50128119526c85d
roblox-luau-patterns git:20261015.28be409A
Immutable. This exact content never changes and is served at /api/v1/blob/a50128119526c85d.
---
name: roblox-luau-patterns
description: "Use for Roblox module boundaries, object lifecycles, signals, task scheduling, fallible calls, and cleanup in Luau."
last_reviewed: 2026-10-04
sources:
- https://luau-lang.org/
- https://luau.org/library
- https://create.roblox.com/docs/reference/engine/classes/ObjectValue
- https://create.roblox.com/docs/reference/engine/classes/StringValue
- https://create.roblox.com/docs/reference/engine/classes/CFrameValue
- https://devforum.roblox.com/t/studio-beta-reference-instances-directly-with-attributes/4753441
- https://raw.githubusercontent.com/Kampfkarren/kampfkarren-luau-guidelines/main/README.md
- original
---
# Luau Patterns
## When to Load
Load for module shapes, resource ownership, scheduling, and failure contracts. See `roblox-luau-core` for semantics, `roblox-luau-types` for types, `roblox-architecture` for startup.
## Quick Reference
### Choose a shape
- **Plain functions:** default for stateless transformation or validation.
- **Module with private state:** one explicit subsystem owner. Do not create a manager class merely to namespace functions.
- **Object with metatable:** multiple independent values need shared behavior and lifecycle.
- **Existing library abstraction:** follow it when the project already uses it consistently. Do not add Promise, signal, cleanup, or framework dependencies for one call site.
Constructors use `.`, instance methods use `:`, and mutable fields belong on the instance, not the class table.
### Make ownership visible
Signal connections, instances, and tasks need cleanup owners. Disconnect/cancel at teardown. Export typed custom signal payloads (`Signal<T...>`).
Configure before parenting to hide partial state. Parent earlier only when ancestry is required; explain why. This does not guarantee replication ordering.
### Preserve failure semantics
```luau
local ok, value = pcall(dataStore.GetAsync, dataStore, key)
if not ok then
return nil, `read failed: {value}`
end
return value, nil -- value may legitimately be nil
```
Do not collapse "call succeeded and returned nil" into "call failed." Retry only when the domain operation is safe to repeat. Persistence, HTTP, purchases, and remotes belong to their domain skills.
### Naming and return contracts
Practitioner conventions: mark yielding functions `Async`, keep return counts consistent, and prefer named module exports. Respect existing project contracts; details in full.md.
### Schedule deliberately
Use `task.defer`, `task.spawn`, `task.delay`, and `task.cancel` deliberately. Avoid legacy `wait()` and unjustified polling. Prefer a real state-change signal; otherwise choose and measure an explicit cadence.
### Review
Clear owner, narrow public API, no circular require, no accidental concurrent startup, success and missing-data states remain distinct, connections/tasks cleaned up, client input routed to `roblox-networking`.
> Details: [references/full.md](references/full.md)