Skip to content

Configuration

wowlua-ls is configured via .wowluarc.json files placed in your project directories. No configuration is required to get started — the defaults work for most addons.

File placement

Config files are hierarchical, like .gitignore. Place one at your workspace root for project-wide settings:

MyAddon/
├── .wowluarc.json         ← project-wide config
├── Core/
│   └── Core.lua
├── Libs/
│   ├── .wowluarc.json     ← directory override (e.g., ignore everything)
│   └── LibStub/
└── Tests/
    ├── .wowluarc.json     ← enable strict diagnostics for tests
    └── TestSuite.lua

Settings merge across the hierarchy:

  • ignore patterns are relative to the config file's directory
  • Disabled diagnostics and allowed globals are unioned across ancestors
  • diagnostics.enable applies after diagnostics.disable at each level (a child can re-enable what a parent disabled)
  • Severity overrides from deeper configs take precedence
  • framexml uses the nearest (deepest) config value

Full reference

json
{
  "ignore": ["Libs/", "External/"],
  "framexml": false,
  "flavors": ["retail", "classic"],
  "globals": {
    "read": ["LibStub", "AceDB"],
    "write": ["MyAddonDB", "SLASH_MYADDON1"]
  },
  "inference": {
    "backward_param_types": true,
    "correlated_return_overloads": true,
    "implicit_protected_prefix": false
  },
  "diagnostics": {
    "disable": ["unused-local", "inject-field"],
    "enable": ["need-check-nil"],
    "severity": {
      "unused-local": "warning",
      "unused-function": "warning"
    }
  }
}

ignore

Array of path prefixes to exclude from scanning. Relative to the config file's directory. Patterns ending with / match directory prefixes.

json
{ "ignore": ["Libs/", "External/", "scratch.lua"] }

Use this for vendored libraries, generated code, or anything you don't want diagnostics on.

Files starting with a shebang (#!/usr/bin/lua) are always skipped automatically — no ignore entry needed.

framexml

Whether FrameXML API globals are available. Default: true.

json
{ "framexml": false }

Set to false to treat FrameXML-specific globals (e.g. SetUIPanelAttribute) as undefined. Useful for library code that shouldn't depend on FrameXML.

flavors

Array of WoW flavor names the project targets. Enables the wrong-flavor-api diagnostic. See Flavor Filtering.

json
{ "flavors": ["retail", "classic"] }

When omitted or empty, flavor filtering is disabled.

globals

Declare external globals that shouldn't trigger diagnostics:

json
{
  "globals": {
    "read": ["LibStub", "AceDB", "AceLocale"],
    "write": ["MyAddonDB", "SLASH_MYADDON1"]
  }
}
  • read — global names that may be accessed without undefined-global
  • write — global names that may be created/assigned without create-global

Use read for globals provided by other addons or libraries not in stubs. Use write for globals your addon intentionally exports.

SavedVariables and SavedVariablesPerCharacter from .toc files are automatically added to both lists — you don't need to configure them manually.

inference

Control the LS's type inference behavior:

SettingDefaultDescription
backward_param_typestrueInfer parameter types from body usage (arithmetic, concatenation, typed-function args)
correlated_return_overloadstrueInfer correlated return patterns for sibling narrowing
implicit_protected_prefixfalseTreat _-prefixed data fields as implicitly protected
json
{
  "inference": {
    "backward_param_types": false
  }
}

Set backward_param_types to false in strict-typing projects where you want unannotated parameters to stay visible as unknown types.

Set correlated_return_overloads to false if the inferred narrowing suppresses need-check-nil warnings you actually want.

Set implicit_protected_prefix to true if your project follows the _-prefix convention for internal fields and you want access-protected diagnostics on external access. See Implicit protected for _ prefixes.

diagnostics

Fine-grained control over which diagnostics fire and at what severity:

json
{
  "diagnostics": {
    "disable": ["unused-local", "inject-field"],
    "enable": ["need-check-nil", "implicit-nil-return"],
    "severity": {
      "unused-local": "warning",
      "unused-function": "warning"
    }
  }
}
  • disable — suppress these diagnostic codes
  • enable — opt into diagnostics that are off by default, or override a parent's disable
  • severity — override severity: "warning", "info", "hint"

Diagnostics disabled by default

These diagnostics are off unless you explicitly enable them:

CodeWhy it's off by default
need-check-nilNoisy on unannotated codebases
implicit-nil-returnStylistic — bare return in optional-return functions
unused-varargMany Lua functions accept ... by convention
incomplete-signature-docOnly useful for teams enforcing documentation standards
unknown-param-typeRequires thorough annotation coverage
unknown-return-typeRequires thorough annotation coverage
unknown-local-typeRequires thorough annotation coverage
unknown-field-typeRequires thorough annotation coverage

For a typical WoW addon:

json
{
  "ignore": ["Libs/"],
  "diagnostics": {
    "enable": ["need-check-nil"]
  }
}

For a multi-flavor addon:

json
{
  "ignore": ["Libs/"],
  "flavors": ["retail", "classic"],
  "diagnostics": {
    "enable": ["need-check-nil"]
  }
}

For strict typing:

json
{
  "ignore": ["Libs/"],
  "diagnostics": {
    "enable": [
      "need-check-nil",
      "unknown-param-type",
      "unknown-return-type",
      "unknown-local-type"
    ]
  }
}

Inline suppression

Any diagnostic can be suppressed on a per-line basis with @diagnostic:

lua
---@diagnostic disable-next-line: unused-local
local unused = computeSomething()

Or for a block:

lua
---@diagnostic disable: undefined-global
MY_GLOBAL = true
OTHER_GLOBAL = false
---@diagnostic enable: undefined-global

Auto-reload

Config files are automatically reloaded when saved. No need to restart the language server.