Skip to main content
EmmyLua Analyzer is built with Rust for exceptional performance, but large projects can benefit from optimization. This guide covers performance tuning, memory management, and best practices.

Performance Overview

Workspace Scanning

Efficient file indexing and incremental updates

Memory Usage

Optimized memory allocation with mimalloc

Incremental Analysis

Only re-analyze changed files

Workspace Configuration

Ignoring Unnecessary Files

Exclude directories and files that don’t need analysis:
.emmyrc.json
{
  "workspace": {
    "ignoreDir": [
      "build",
      "dist",
      "output",
      "node_modules",
      ".git",
      "vendor",
      "third_party"
    ],
    "ignoreGlobs": [
      "*.log",
      "*.tmp",
      "**/test/**/*.lua",
      "**/*_generated.lua",
      "**/vendor/**"
    ]
  }
}
Ignoring unnecessary files can reduce initial indexing time by 50-80% in large projects.
  • Build outputs: build/, dist/, output/, bin/
  • Dependencies: node_modules/, vendor/, third_party/
  • Version control: .git/, .svn/, .hg/
  • IDE files: .vscode/, .idea/
  • Generated code: Auto-generated Lua files
  • Test fixtures: Large test data files
  • Documentation: docs/, documentation/

File Size Limits

Control which files are preloaded:
.emmyrc.json
{
  "workspace": {
    "preloadFileSize": 100000
  }
}
preloadFileSize
number
default:0
Maximum file size in bytes to preload during startup. Files larger than this are analyzed on-demand. Set to 0 to preload all files.
Setting preloadFileSize too low may cause delays when opening large files for the first time.

Workspace Roots

Define multiple workspace roots for better organization:
.emmyrc.json
{
  "workspace": {
    "workspaceRoots": [
      "src/",
      "scripts/",
      "addons/"
    ]
  }
}
This helps the analyzer:
  • Focus on relevant directories
  • Improve module resolution
  • Reduce memory usage

Incremental Analysis

Reindexing Configuration

Control automatic reindexing:
.emmyrc.json
{
  "workspace": {
    "reindexDuration": 5000,
    "enableReindex": false
  }
}
reindexDuration
number
default:5000
Time in milliseconds to wait before reindexing after file changes. Higher values reduce CPU usage but delay updates.
enableReindex
boolean
default:false
Enable automatic reindexing. Disable for large projects where manual reindexing is preferred.
For very large projects (10,000+ files), disable automatic reindexing and use manual refresh when needed.

Diagnostic Intervals

Control diagnostic update frequency:
.emmyrc.json
{
  "diagnostics": {
    "enable": true,
    "diagnosticInterval": 500
  }
}
Increase diagnosticInterval to reduce CPU usage:
  • 500ms - Default, responsive for most projects
  • 1000ms - Better for large projects
  • 2000ms - Best for very large projects or slower machines

Memory Optimization

Built-in Optimizations

EmmyLua Analyzer includes several memory optimizations:

Mimalloc Allocator

Fast memory allocator providing ~50% startup performance improvement

Incremental Parsing

Only re-parse changed portions of files

Smart Caching

Cache frequently accessed type information

Lazy Loading

Load library definitions on-demand

Library Management

Optimize library loading:
.emmyrc.json
{
  "workspace": {
    "library": [
      "/usr/local/share/lua/5.4",
      "./libs/common"
    ]
  }
}
Only include necessary library paths. Each library directory adds to memory usage and startup time.

Resource Paths

Limit resource path scanning:
.emmyrc.json
{
  "resource": {
    "paths": [
      "assets/",
      "resources/"
    ]
  }
}

Feature-Specific Optimization

Completion Performance

.emmyrc.json
{
  "completion": {
    "enable": true,
    "autoRequire": true,
    "callSnippet": false
  }
}
  • autoRequire: false - Slightly faster completion, but less convenient
  • callSnippet: false - Reduces completion overhead
  • baseFunctionIncludesName: false - Smaller completion lists

Hints and Inlays

.emmyrc.json
{
  "hint": {
    "enable": true,
    "paramHint": true,
    "indexHint": false,
    "localHint": false,
    "overrideHint": true,
    "metaCallHint": true
  }
}
Disable hints you don’t use to reduce computation:
  • indexHint - Most expensive, disable for large files
  • localHint - Can be noisy in large functions
.emmyrc.json
{
  "references": {
    "enable": true,
    "fuzzySearch": false,
    "shortStringSearch": false
  }
}
fuzzySearch: true and shortStringSearch: true significantly increase search time in large codebases.

Semantic Tokens

.emmyrc.json
{
  "semanticTokens": {
    "enable": true
  }
}
Disable semantic tokens if you don’t use semantic highlighting - saves CPU on large files.

Diagnostic Optimization

Selective Diagnostics

Disable expensive diagnostics:
.emmyrc.json
{
  "diagnostics": {
    "disable": [
      "unused",
      "undefined-field",
      "code-style-check"
    ]
  }
}
High impact (consider disabling in large files):
  • unused - Requires full scope analysis
  • undefined-field - Checks all table accesses
  • code-style-check - Additional parsing pass
Medium impact:
  • param-type-not-match - Type checking overhead
  • return-type-mismatch - Control flow analysis
Low impact:
  • syntax-error - Fast to check
  • deprecated - Simple lookup

File-Specific Diagnostics

Disable diagnostics in specific files:
---@diagnostic disable

-- Large generated file or third-party code
-- No diagnostics will run on this file
Or disable specific diagnostics:
---@diagnostic disable: undefined-field, unused

-- Rest of file...

Large Project Strategies

Strategy 1: Workspace Splitting

Split large monorepos into multiple workspaces:
project/
├── backend/
│   └── .emmyrc.json  # Backend workspace
├── frontend/
│   └── .emmyrc.json  # Frontend workspace  
└── shared/
    └── .emmyrc.json  # Shared workspace
Each workspace configures its own:
  • Library paths
  • Ignore patterns
  • Diagnostic settings

Strategy 2: Progressive Analysis

Analyze code incrementally:
1

Start with core modules

Configure analyzer for core modules only
2

Add dependencies

Gradually include dependent modules
3

Include tests last

Add test directories when core is stable

Strategy 3: Lazy Loading

Configure lazy loading for libraries:
.emmyrc.json
{
  "workspace": {
    "preloadFileSize": 50000,
    "library": [
      "./core"  // Only core libs preloaded
    ]
  }
}
Other libraries load on first use.

Benchmarking

Measuring Startup Time

time emmylua_ls --check .

Measuring Analysis Time

emmylua_ls --check --verbose .
Look for timing information in output:
[INFO] Workspace loaded in 1.2s
[INFO] Initial analysis completed in 3.5s
[INFO] Analyzed 1,523 files

Memory Profiling

Monitor memory usage:
/usr/bin/time -v emmylua_ls --check .

Performance Monitoring

LSP Metrics

Enable LSP logging to track performance:
{
  "emmylua.misc.parameters": [
    "--log-level=info",
    "--log-file=emmylua.log"
  ]
}
Check log for slow operations:
[WARN] Type inference took 1.2s for file.lua:245
[WARN] Reference search took 800ms

Performance Regression Detection

Track performance over time:
benchmark.sh
#!/bin/bash

echo "Benchmarking EmmyLua Analyzer..."
echo "Date: $(date)"
echo "Commit: $(git rev-parse HEAD)"
echo ""

echo "Startup time:"
time emmylua_ls --version

echo "\nAnalysis time:"
time emmylua_ls --check .

echo "\nFile count:"
find . -name "*.lua" | wc -l
Run regularly and compare results.

Troubleshooting Performance Issues

High CPU Usage

Symptoms: Editor feels sluggish, fan spinning Solutions:
  1. Increase diagnosticInterval:
    { "diagnostics": { "diagnosticInterval": 1000 } }
    
  2. Disable expensive diagnostics:
    { "diagnostics": { "disable": ["unused", "code-style-check"] } }
    
  3. Disable automatic reindexing:
    { "workspace": { "enableReindex": false } }
    

High Memory Usage

Symptoms: System running out of memory, swap usage high Solutions:
  1. Ignore large directories:
    { "workspace": { "ignoreDir": ["build", "vendor"] } }
    
  2. Set file size limit:
    { "workspace": { "preloadFileSize": 50000 } }
    
  3. Reduce library paths:
    { "workspace": { "library": [] } }
    

Slow Completion

Symptoms: Completion takes >500ms Solutions:
  1. Disable auto-require:
    { "completion": { "autoRequire": false } }
    
  2. Disable call snippets:
    { "completion": { "callSnippet": false } }
    
  3. Check for circular dependencies in requires

Slow References

Symptoms: “Find References” takes >2s Solutions:
  1. Disable fuzzy search:
    { "references": { "fuzzySearch": false } }
    
  2. Disable short string search:
    { "references": { "shortStringSearch": false } }
    

Hardware Recommendations

Minimum Requirements

  • CPU: 2 cores, 2.0 GHz
  • RAM: 4 GB
  • Storage: SSD recommended
  • Projects: Up to 1,000 files
  • CPU: 4+ cores, 3.0+ GHz
  • RAM: 8+ GB
  • Storage: NVMe SSD
  • Projects: Up to 10,000 files

Large Project Configuration

  • CPU: 8+ cores, 3.5+ GHz
  • RAM: 16+ GB
  • Storage: Fast NVMe SSD
  • Projects: 10,000+ files
EmmyLua Analyzer benefits from fast single-core performance more than many cores.

Comparison with Other Tools

MetricEmmyLua Analyzer (Rust)lua-language-server
Startup time (10k files)1-2s5-10s
Memory usage200-400 MB500-800 MB
Incremental analysisYesYes
Type inference speedFastModerate
Completion latency<100ms<200ms
Benchmarks vary by project structure and hardware. Your results may differ.

Best Practices Summary

Ignore Aggressively

Exclude all non-source directories

Tune Diagnostics

Only enable diagnostics you actively use

Monitor Performance

Track metrics to catch regressions early

Split Large Projects

Use multiple workspaces for better isolation

Next Steps

Type Checking

Optimize type checking performance

CLI Tools

Use CLI for batch analysis

Build docs developers (and LLMs) love