Open-source project
EmmyLua/VSCode-EmmyLua avatar
EmmyLua/VSCode-EmmyLua

EmmyLua gives VS Code a Rust-backed Lua language server and debugger

Lua IDE/Debugger Plugin for VSCode

755 stars112 forksTypeScriptLicense varies

At a glance

What is it?
The VSCode-EmmyLua extension adds Lua completion, diagnostics and debugging to Visual Studio Code by driving a language server written in Rust that lives in a separate repository. Configuration lives in a project-level .emmyrc.json file, and the same server can be used from any editor that speaks LSP.
Who is it for?
Lua developers who want completion, diagnostics and a debugger in Visual Studio Code, or who want the same analysis in another editor, should use EmmyLua, because the language server is a standard LSP implementation and the configuration file travels with the project rather than living in one editor's settings.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 72 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A TypeScript extension wrapped around a Rust language server

EmmyLua is a Lua language support extension for Visual Studio Code, providing intelligent code completion, debugging and analysis capabilities. The README lists the feature set as smart code completion with type inference, real-time diagnostics with error detection and warnings as you type, advanced debugging with attach, launch and remote support, cross-platform operation on Windows, macOS and Linux, and an LSP-based architecture.

The architecture is the interesting part, and the README is candid about it. The extension itself is written in TypeScript, and the repository listing shows the pieces of a normal VS Code extension: src for the extension code, build for the build scripts, debugger for the debugger side, syntaxes for the grammar, l10n for localisation with package.nls.json and package.nls.zh-cn.json, a language-configuration.json, and an .eslintrc.json, .prettierrc and tsconfig.json for tooling.

The analysis engine is not in this repository. The README links the language server, Rust, at the emmylua-analyzer-rust repository, and the documentation link points into that same repository's docs directory. The FAQ explains why it was written that way: the Rust implementation provides better performance, memory safety and cross-platform compatibility compared to the previous .NET and Java versions.

So the division is clear. This repository is the editor integration, the command surface and the debugger glue. The Rust project is the analyzer that parses Lua, infers types and produces diagnostics. Any change to analysis behaviour is made there, not here, which is worth knowing before you file an issue about a false positive.

The package manifest describes the extension's shape in concrete terms. The name is emmylua with a display name of EmmyLua, the version is 0.9.41, the publisher is tangzx, the categories are Programming Languages and Debuggers, and the entry point is ./out/extension. The engine requirement is VS Code ^1.89.0.

Two capability declarations are worth noting because they close doors. Untrusted workspaces are not supported, and virtual workspaces are not supported. The extension is also declared as extensionKind workspace, meaning it runs in the workspace rather than the UI side of a remote setup.

The repository is not archived, the default branch is master, and the last push was on 2026-08-14.

The command surface, and what the server does when it misbehaves

The commands the extension registers are in the package manifest, and they are worth reading as the operator's control panel.

There is a restart command, emmy.restartServer, shown as EmmyLua: Restart Lua Server. There is a stop command, emmy.stopServer, shown as EmmyLua: Stop EmmyLua Language Server. There is a diagnostics command, emmy.showServerDiagnostics, shown as EmmyLua: Open Server Diagnostics, with a heart-pulse icon in the palette. And there is emmy.insertEmmyDebugCode, shown as EmmyLua: Insert Emmy Debugger Code, which is the one that inserts the snippet the debugging section talks about.

That set of four tells you what the extension expects to go wrong. Language servers do not crash often, but they do get into a state where completion stops, where a configuration change is not picked up, or where the diagnostics are stale. Being able to restart the server without reloading the window, and to open the server's own diagnostics output, is what you need when that happens.

The activation event list in the manifest contains only onDebug, which tells you the extension's heaviest work starts when you debug rather than when you open a Lua file. The language server itself is started on demand for the analysis features.

The related extensions are separate, and their split is by concern. EmmyLuaCodeStyle handles code formatting and style enforcement, and EmmyLuaUnity handles Unity3D integration. Keeping formatting out of the language extension avoids two tools rewriting the same file, and keeping Unity support out means the core extension is not tied to a particular engine.

Configuration lives in .emmyrc.json, not in editor settings

Project configuration goes in a file called .emmyrc.json in the project root. The README's example turns off one diagnostic:

json
{
  "diagnostics": {
    "undefined-global": false
  }
}

For detailed configuration options the README links the English documentation and a Chinese version, both in the docs/config directory of the language server repository, with the file name emmyrc_json_EN.md.

The FAQ gives a second form of the same setting, using a disable list rather than a boolean:

json
{
  "diagnostics": {
    "disable" : [
      "undefined-global"
    ]
  }
}

Two different shapes for the same diagnostic, which suggests the configuration schema accepts more than one style of declaration and that the documentation is where you settle which to use.

The FAQ also explains why the configuration is a file rather than editor settings. Project-specific configuration files work across different editors and platforms without requiring IDE-specific setup. That is the same reason the server is a standard LSP implementation: the point is that a team can commit one configuration file and one set of annotations and have every editor, on every machine, agree about the project.

This also means the extension inherits whatever language the project uses for annotations. EmmyLua's analysis is annotation-driven, and a project that annotates its types gets far better completion and diagnostics than one that relies on inference alone, which is a real difference in daily use and not something the README discusses in detail.

Attaching the debugger over TCP on port 9966

The debugging setup has three steps, and the mechanics are unusual enough to be worth reading closely.

First, insert the debugger code. The command EmmyLua: Insert Emmy Debugger Code does it for you, or you can add it by hand:

lua
package.cpath = package.cpath .. ";path/to/emmy/debugger/?.dll"
local dbg = require('emmy_core')
dbg.tcpListen('localhost', 9966)
dbg.waitIDE()

The snippet extends the Lua module search path so that the native debugger module can be found, then loads it as emmy_core and starts listening on localhost, port 9966. The waitIDE call blocks until an IDE connects, which is why the program does not continue until the debugger attaches.

Second, set breakpoints. The README offers two ways: add dbg.breakHere() where you want execution to pause, or use VS Code's built-in breakpoint system.

Third, start debugging. You run your Lua application and launch the EmmyLua New Debug configuration in VS Code, and the README says the debugger will connect automatically. The TCP listener on 9966 is what makes that automatic connection work.

Three debug configurations are offered. EmmyLua New Debug is described as modern debugging with better performance. EmmyLua Attach attaches to running processes. EmmyLua Launch is direct launch debugging.

The attach mode has a documented precondition, and the FAQ states it plainly: the debugger needs access to Lua symbols from the target process, so your executable must export Lua symbols. That is the single most common reason attach debugging does not work, and it is a property of how your Lua program was built rather than something the extension can work around.

Using the analyzer outside VS Code

The FAQ on using EmmyLua analysis in other editors answers yes, because EmmyLua uses a standard Language Server Protocol implementation and any LSP-compatible editor can use it.

That is the most portable thing about the project, and it is worth understanding what it depends on. The Rust language server is a separate repository with its own configuration format, and the .emmyrc.json file is part of that format rather than part of the VS Code extension. The VS Code extension adds the debugging side, the commands and the editor integration on top of a server that is not tied to VS Code.

Two consequences follow. A team that mixes editors can share the same analysis configuration and the same type annotations. And a team that only wants completion and diagnostics, without the debugger, does not need VS Code at all, which makes the server a candidate for editor-agnostic CI checks as well.

The related extensions underline the editor-specific nature of this repository. EmmyLuaCodeStyle and EmmyLuaUnity are published as Visual Studio Marketplace items, and the language server documentation is the shared part.

One structural note about the repository: the top level also carries a .vscode directory, a .vscodeignore and a build directory, which is the standard scaffolding for a VS Code extension that is packaged and published, and a yarn.lock rather than a package-lock, so the build uses Yarn.

Where EmmyLua is the wrong tool

The limits are concrete and worth stating before you commit a team to it.

Attach debugging requires a process that exports its Lua symbols. If your Lua code runs inside a host application that was not built to expose them, the attach path simply will not work, and no amount of configuration changes that.

Untrusted and virtual workspaces are marked as unsupported in the package manifest. That excludes opening a repository in a VS Code window that treats the folder as untrusted, and it excludes virtual workspace environments such as remote repository browsing. The extension also declares itself as workspace kind, so it does not run on the local UI side of a remote connection.

The debugging story is also Windows-shaped in one visible place. The snippet that extends the module search path points at a .dll, which is the Windows native library extension, so the path you are expected to adjust for other platforms is not spelled out in the README.

On versions, the record is unusual. The package manifest is at version 0.9.41, while the tagged releases in the repository are 0.2.1 from 2019-01-13, 0.1.0 from 2018-10-08 and 0.0.8-preview from 2018-09-11. The GitHub release tags therefore do not track the published extension version, so you cannot use the tag list to work out what a given marketplace build contains, and the CHANGELOG.md, with a Chinese counterpart in CHANGELOG_CN.md, is the version record that actually corresponds to the extension.

On the licence, the README states that the project is licensed under the MIT License, while the licence is not identified in the repository metadata. The README statement is the one to rely on, and it is worth checking the licence file in the tree before redistributing anything.

Editorial conclusion

Lua developers who want completion, diagnostics and a debugger in Visual Studio Code, or who want the same analysis in another editor, should use EmmyLua, because the language server is a standard LSP implementation and the configuration file travels with the project rather than living in one editor's settings. It is the wrong tool for attaching to a process that does not export its Lua symbols, and it is the wrong tool for untrusted or virtual workspaces, which the package manifest marks as unsupported. Before adopting, read the emmyrc_json_EN.md configuration reference linked from the README, run the EmmyLua: Open Server Diagnostics command when analysis looks wrong, and note that the version in package.json is 0.9.41 while the newest tagged GitHub release is 0.2.1 from 2019.

Frequently asked questions

How do I configure EmmyLua for a project?

Create a .emmyrc.json file in your project root, for example with a diagnostics section that sets undefined-global to false. The detailed options are documented in emmyrc_json_EN.md in the docs/config directory of the language server repository.

Why does attach debugging not work with EmmyLua?

The debugger needs access to the Lua symbols in the target process, so the executable you are attaching to must export its Lua symbols. The README's FAQ states this as the condition for the attach mode.

Can I use EmmyLua in an editor other than VS Code?

Yes. The FAQ says EmmyLua uses a standard Language Server Protocol implementation, so any LSP-compatible editor can use the analyzer, and the project-level .emmyrc.json configuration works across editors and platforms without IDE-specific setup.

Why was the EmmyLua language server rewritten in Rust?

The README's FAQ gives three reasons: better performance, memory safety and cross-platform compatibility, compared to the previous .NET and Java versions. The Rust server lives in its own repository, emmylua-analyzer-rust, and this repository holds the VS Code extension around it.

Official sources

  1. EmmyLua/VSCode-EmmyLua on GitHub
  2. Issues
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/emmylua-vscode-emmylua.svg)](https://hysenlabs.com/projects/emmylua-vscode-emmylua)

Was this useful?