Hello Luaunauts, we're continuing into the second release of the year at
a brisk pace! We've got a number of improvements for both native code
generation and the new type solver, as well as some other assorted
changes, that keep us moving towards the goal of making the best
possible scripting language!
# Analysis
- Refinements against a union of tables would sometimes erroneously
refine to a narrower type than intended. The root cause here was a bug
in the logic that determines how to "simplify" types (for example
knowing that `true | false` is the same as `boolean`).
```luau
export type States = "Closed" | "Closing" | "Opening" | "Open"
export type MyType<A = any> = {
State: States,
IsOpen: boolean,
Open: (self: MyType<A>) -> (),
}
local value = {} :: MyType
function value:Open()
if self.IsOpen == true then
elseif self.State == "Closing" or self.State == "Opening" then
-- Prior, this line errored as we were erroneously refining
-- `self` with `{ State: "Closing" | "Opening" }` rather
-- than `{ read State: "Closing" | "Opening" }
self:Open()
end
end
```
- Adds an option in `ToString.cpp` to disable the use of synthetic
names, which can be used to improve the quality of hover type.
- Fixes a bug where `table.freeze` would incorrectly error on arguments
of `any` type (fixes #2181)
- Subtyping mistakenly did not allow for us to covariantly check tables
with missing properties against table types that gave those properties
optional types. This release should fix these issues, including fixes
#2164.
- Type functions have a global environment that defines all of the type
aliases present in the environment around the type function definition,
and the API of type functions also allows you to mutate types,
specifically table types and function types. Though we never supported
the type functions _actually_ mutating the aliases present in the
environment around them, the mutable API allowed for users to author
type functions that _appeared_ to do so, which could be confusing when
they later discover that their mutation did not take place. This release
introduces new errors for type functions that attempt to call mutable
APIs on types from their environment, e.g.
```luau
type myType = {}
type function create_table_with_key()
myType:setproperty(types.singleton "key", types.optional(types.number))
-- this errors now!
return myType
end
local my_tbl: create_table_with_key<> = {key = "123"}
```
- Bidirectional inference for lambdas on extern types with generic
parameters should work more consistently.
- #2166 fixes a bug with `findBindingAtPosition` that should enable LSP
tools to better support finding references for local functions and their
parameters.
- This release also includes a broad-strokes improvement to error
suppression handling. The New Type Solver should now be more consistent
about not reporting (or re-reporting) errors involving `any` or
`*error-type*` or directly downstream of an existing type error.
- This release removes the experimental
`DebugLuauStringSingletonBasedOnQuotes` flag that trialed basing
singleton type inference solely on the usage of different quote styles.
We do not think we will be proceeding with this approach at this time.
# Native Code Generation
- Fixes a crash in `getOffsetBase` when the passed in IrOp is not an
IrInst.
- Improves inlining support by passing the argument value as the
initializer for the temporary being allocated in cases like anonymous
function arguments or referring to upvalues in a function body.
- Fixes the function end byte offset value, along side a number of other
internal values that could lead to incorrect code size values.
- Adds a more direct implementation of code generation for `vector`
equality and inequality that leads to fewer instructions in the IR and a
smaller number of produced basic blocks.
- Adds a more optimized code generation flow for situations where we're
indexing a table with keys that have unexpected type tags.
- Fixes a bug where NCG would sometimes mistakenly optimize away
necessary entry tag checks.
- Introduces a customizable per-VM storage for use from "execution
callbacks" system, with NCG as its first consumer for extra spill
spaces. This adds 32x 8-byte spill slots on arm64 (on top of existing
22) and 64x 8-byte spill slots on x64 (on top of existing 12*).
- Changes codegen for bit32 operations to use guards, rather than normal
control flow, leading to significant (~30%) performance improvements in
some benchmarks that heavily leverage these operations.
- Adds a combined instruction `UINT_TO_FLOAT` to replace instances where
we needed to emit `UINT_TO_NUM` and `NUM_TO_FLOAT` paired up. This leads
to some very modest performance improvements.
# Runtime
- We previously added constant string constant folding with the results
stored in AST allocator. This release also moves interpolation
formatting strings to AST allocator to resolve #1965.
- #2069 adds support for using `os.clock` in Emscripten build targets,
like the [Luau Playground](https://play.luau.org).
- #2149 extends the C++ Require library to support constructing aliases
with tags associated with them.
- #2054 fixes a bugged comparison in `api_update_top` that would cause
an unnecessary runtime error if the API was used in a way that should be
a noop.
# Internal Contributors
Co-authored-by: Andy Friesen <afriesen@roblox.com>
Co-authored-by: Annie Tang <annietang@roblox.com>
Co-authored-by: Ariel Weiss <arielweiss@roblox.com>
Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com>
Co-authored-by: James McNellis <jmcnellis@roblox.com>
Co-authored-by: Sora Kanosue <skanosue@roblox.com>
Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
---------
Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com>
Co-authored-by: Varun Saini <61795485+vrn-sn@users.noreply.github.com>
Co-authored-by: Alexander Youngblood <ayoungblood@roblox.com>
Co-authored-by: Menarul Alam <malam@roblox.com>
Co-authored-by: Aviral Goel <agoel@roblox.com>
Co-authored-by: Vighnesh <vvijay@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
Co-authored-by: Andy Friesen <afriesen@roblox.com>
Co-authored-by: Ilya Rezvov <irezvov@roblox.com>
|
||
|---|---|---|
| .github | ||
| Analysis | ||
| Ast | ||
| bench | ||
| CLI | ||
| CodeGen | ||
| Common | ||
| Compiler | ||
| Config | ||
| extern | ||
| fuzz | ||
| Require | ||
| tests | ||
| tools | ||
| VM | ||
| .clang-format | ||
| .gitignore | ||
| CMakeLists.txt | ||
| CMakePresets.json | ||
| CONTRIBUTING.md | ||
| LICENSE.txt | ||
| lua_LICENSE.txt | ||
| Makefile | ||
| README.md | ||
| SECURITY.md | ||
| Sources.cmake | ||
Luau

Luau (lowercase u, /ˈlu.aʊ/) is a fast, small, safe, gradually typed embeddable scripting language derived from Lua.
It is designed to be backwards compatible with Lua 5.1, as well as incorporating some features from future Lua releases, but also expands the feature set (most notably with type annotations and a state-of-the-art type inference system). Luau is largely implemented from scratch, with the language runtime being a very heavily modified version of Lua 5.1 runtime, with completely rewritten interpreter and other performance innovations. The runtime mostly preserves Lua 5.1 API, so existing bindings should be more or less compatible with a few caveats.
Luau is used by Roblox game developers to write game code, and by Roblox engineers to implement large parts of the user-facing application code as well as portions of the editor (Roblox Studio) as plugins. Roblox chose to open-source Luau to foster collaboration within the Roblox community as well as to allow other companies and communities to benefit from the ongoing language and runtime innovation. More recently, Luau has seen adoption in games like Alan Wake 2, Farming Simulator 2025, Second Life, and Warframe.
This repository hosts source code for the language implementation and associated tooling. Documentation for the language is available at https://luau.org/ and accepts contributions via site repository; the language is evolved through RFCs that are located in rfcs repository.
Usage
Luau is an embeddable programming language, but it also comes with two command-line tools by default, luau and luau-analyze.
luau is a command-line REPL and can also run input files. Note that REPL runs in a sandboxed environment and as such doesn't have access to the underlying file system except for ability to require modules.
luau-analyze is a command-line type checker and linter; given a set of input files, it produces errors/warnings according to the file configuration, which can be customized by using --! comments in the files or .luaurc files. For details, please refer to our type checking and linting documentation. Our community maintains a language server frontend for luau-analyze called luau-lsp for use with text editors.
Installation
You can install and run Luau by downloading the compiled binaries from a recent release; note that luau and luau-analyze binaries from the archives will need to be added to PATH or copied to a directory like /usr/local/bin on Linux/macOS.
Alternatively, you can use one of the packaged distributions (note that these are not maintained by Luau development team):
- macOS: Install Homebrew and run
brew install luau - Arch Linux: Luau has been added to the official Arch Linux packages repository under the extras repository (see
luau), simply install usingpacman:pacman -Syu luau - Alpine Linux: Enable community repositories and run
apk add luau - Gentoo Linux: Luau is officially packaged by Gentoo and can be installed using
emerge dev-lang/luau. You may have to unmask the package first before installing it (which can be done by including the--autounmask=yoption in theemergecommand).
After installing, you will want to validate the installation was successful by running the test case here.
Building
On all platforms, you can use CMake to run the following commands to build Luau binaries from source:
mkdir cmake && cd cmake
cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build . --target Luau.Repl.CLI --config RelWithDebInfo
cmake --build . --target Luau.Analyze.CLI --config RelWithDebInfo
Alternatively, on Linux and macOS, you can also use make:
make config=release luau luau-analyze
To integrate Luau into your CMake application projects as a library, at the minimum, you'll need to depend on Luau.Compiler and Luau.VM projects. From there you need to create a new Luau state (using Lua 5.x API such as lua_newstate), compile source to bytecode and load it into the VM like this:
// needs lua.h and luacode.h
size_t bytecodeSize = 0;
char* bytecode = luau_compile(source, strlen(source), NULL, &bytecodeSize);
int result = luau_load(L, chunkname, bytecode, bytecodeSize, 0);
free(bytecode);
if (result == 0)
return 1; /* return chunk main function */
For more details about the use of the host API, you currently need to consult Lua 5.x API. Luau closely tracks that API but has a few deviations, such as the need to compile source separately (which is important to be able to deploy VM without a compiler), and the lack of __gc support (use lua_newuserdatadtor instead).
To gain advantage of many performance improvements, it's highly recommended to use the safeenv feature, which sandboxes individual scripts' global tables from each other, and protects builtin libraries from monkey-patching. For this to work, you must call luaL_sandbox on the global state and luaL_sandboxthread for each new script's execution thread.
Testing
Luau has an internal test suite; in CMake builds, it is split into two targets, Luau.UnitTest (for the bytecode compiler and type checker/linter tests) and Luau.Conformance (for the VM tests). The unit tests are written in C++, whereas the conformance tests are largely written in Luau (see tests/conformance).
Makefile builds combine both into a single target that can be run via make test.
Dependencies
Luau uses C++ as its implementation language. The runtime requires C++11, while the compiler and analysis components require C++17. It should build without issues using Microsoft Visual Studio 2017 or later, or gcc-7 or clang-7 or later.
Other than the STL/CRT, Luau library components don't have external dependencies. The test suite depends on the doctest testing framework, and the REPL command-line depends on isocline.
License
Luau implementation is distributed under the terms of MIT License. It is based on the Lua 5.x implementation, also under the MIT License.
When Luau is integrated into external projects, we ask that you honor the license agreement and include Luau attribution into the user-facing product documentation. Attribution making use of the Luau logo is also encouraged when reasonable.