JETLS configuration
JETLS supports various configuration options. This documentation uses TOML format to describe the configuration schema.
JSON Schema files for all configuration surfaces are also available.
Configuration schema
The following schema lists all the available options. An entry that is not commented out shows the option's default value, while a commented-out entry is a form without a default value (an alternative form, an array entry, or an option whose default is unset), shown with an example value.
The leading #:schema directive is honored by TOML language servers such as tombi, which use it to validate and complete .JETLSConfig.toml against the JSON Schema.
#:schema https://github.com/aviatesk/JETLS.jl/releases/latest/download/config-toml.schema.json
formatter = "Runic" # "Runic"/"JuliaFormatter", default: "Runic"
# [formatter.custom] # table, alternative to the string preset form above
# executable = "/path/to/formatter" # string, required
# executable_range = "/path/to/range-formatter" # string, optional
[full_analysis]
debounce = 1.0 # number (seconds), default: 1.0
auto_instantiate = "prompt" # "always"/"prompt"/"never", default: "prompt"
concretization_patterns = [] # array of tables, default: []
concretization_timeout = 10.0 # positive finite number (seconds) or "inf", default: 10.0
# [[full_analysis.concretization_patterns]] # table, an entry of the concretization patterns array above
# pattern = "RandomType = x_" # Julia expression pattern, required
# path = "scripts/random-type.jl" # string (glob), optional
[diagnostic]
enabled = true # boolean, default: true
all_files = true # boolean, default: true
allow_unused_underscore = true # boolean, default: true
patterns = [] # array of tables, default: []
# [[diagnostic.patterns]] # table, an entry of the patterns array above
# pattern = "lowering/unused-.*" # string, required
# match_by = "code" # "code"/"message", required
# match_type = "regex" # "literal"/"regex", required
# severity = "hint" # "error"/"warning"/"info"/"hint"/"off" or 0-4, required
# path = "test/**/*.jl" # string (glob), optional
[completion.latex_emoji]
# strip_prefix = true # boolean, default: unset (auto-detect based on client)
[code_lens]
references = false # boolean, default: false
testrunner = true # boolean, default: true
[inlay_hint.block_end]
enabled = true # boolean, default: true
min_lines = 25 # integer, default: 25
[inlay_hint.types]
enabled = true # boolean, default: true
[testrunner]
env = {} # table of strings, default: {}
julia_args = [] # array of strings, default: []Configuration reference
[full_analysis]
[full_analysis] debounce
- Type: number (seconds)
- Default:
1.0
Debounce time in seconds before triggering full analysis after a file save. JETLS performs type-aware analysis using JET.jl to detect potential errors. The debounce prevents excessive analysis when you save files frequently. Higher values reduce analysis frequency (saving CPU) but may delay diagnostic updates.
[full_analysis]
debounce = 2.0 # Wait 2 seconds after save before analyzing[full_analysis] auto_instantiate
- Type: string (
"always","prompt", or"never") - Default:
"prompt"
Controls what JETLS does when the package environment of an analyzed file needs instantiation, i.e. when its manifest is missing or out of date, or some dependency has not been downloaded yet (e.g., freshly cloned repositories). Environments that are already instantiated with an up-to-date manifest are never touched.
"prompt"asks for confirmation before instantiating, once per environment per server session. Clients that support work-done progress show "Waiting for environment instantiation" until the prompt is answered. full analysis of the files in that environment is deferred until then, so if the notification is left unanswered (e.g. tucked away in VSCode's notification center), those files get no save-time diagnostics until you respond. Alternatively, you can resolve and instantiate the environment manually while the prompt is open, then choose "Skip" after the operation finishes. JETLS rechecks the environment before analysis and uses the updated environment without runningPkg.resolve()orPkg.instantiate()itself. Choosing "Skip" while the environment still needs instantiation analyzes the code against it as is, in which case package-loading failures show up astopleveldiagnostics."always"runsPkg.resolve()(only when the manifest is missing or out of date) andPkg.instantiate()without asking. This can download packages and artifacts, run build scripts, precompile dependencies, and modifyManifest.toml, so enable it only for projects you trust."never"leaves the environment untouched and shows a warning instead.
The CLI has no client to ask, so under "prompt" jetls check resolves and instantiates the environment just like "always" does. Set auto_instantiate = "never" in .JETLSConfig.toml to analyze against the environment as is.
For backward compatibility, JETLS still accepts the legacy values true and false at runtime as aliases of "always" and "never". Configuration schemas intentionally accept only the string values above, so schema validation reports legacy booleans as invalid and prompts migration to the new form.
[full_analysis]
auto_instantiate = "always" # Instantiate without asking[full_analysis] concretization_patterns
- Type: array of tables
- Default:
[]
During script analysis, JETLS analyzes top-level code without evaluating every expression. If it needs the value of a global binding to define a later type or method, JETLS may report toplevel/missing-concretization.
By contrast, when analyzing package source code under src/, JETLS uses the catch-all concretization pattern :(x_) and evaluates all top-level code. Additional concretization patterns are therefore needed only for script analysis.
For example, suppose scripts/random-type.jl contains:
RandomType = rand((Bool, Int))
struct Container
value::RandomType
endTo analyze Container, JETLS must know whether RandomType is Bool or Int. Declaring the binding as const can sometimes resolve this diagnostic: if JETLS infers a concrete value for the right-hand side, it can safely reuse that value later in the analysis. This does not help when the right-hand side cannot be inferred as a single concrete value.
In this example, JETLS cannot infer a single concrete result for rand((Bool, Int)), so the diagnostic's quick fix can add the following entry to .JETLSConfig.toml:
[[full_analysis.concretization_patterns]]
pattern = "RandomType = x_"
path = "scripts/random-type.jl"This tells JETLS to evaluate an assignment to RandomType while processing scripts/random-type.jl. In the pattern, x_ matches any right-hand-side expression, including rand((Bool, Int)) in this example.
Each table contains:
pattern(required): A Julia expression pattern using MacroTools.jl expression matching syntax.path(optional): A glob restricting the pattern to matching source files. Paths are relative to the workspace root. Each included file is matched using its own path, not the path of the file that included it. Ifpathis omitted, the pattern applies to every analyzed file inside the workspace. For example,path = "src/**/*.jl"applies the pattern to Julia files undersrc.
Configured patterns apply only to files inside the workspace. Included files outside the workspace use only JET's built-in patterns. These entries supplement the built-in patterns; they do not replace them.
Concretization causes the JETLS analysis process to execute each matching top-level expression instead of only analyzing it. Any side effects of that expression, such as writing files, accessing the network, starting external processes, or mutating global state, can therefore occur during analysis. full analysis may run again after a file is saved, so these effects may occur more than once. Keep both pattern and path as specific as possible.
[full_analysis] concretization_timeout
- Type: positive finite number (seconds) or the exact string
"inf" - Default:
10.0
Limits concrete execution of each top-level statement during full analysis of both scripts and packages. This is not a time limit for the overall analysis. Positive integers and floating-point values are accepted; 0, negative values, booleans, numeric NaN/Inf, and strings other than "inf" are rejected.
When the limit is exceeded, JETLS reports toplevel/concretization-timeout and stops the full analysis without analyzing that statement or any code after it. Timing starts after statement selection and interpreter frame setup. Time spent in includes and module-loading statements handled by JET is excluded from the caller's limit; each top-level statement in an included file has its own timeout.
[full_analysis]
concretization_timeout = 120.0 # Allow up to 120 seconds per statement
# concretization_timeout = "inf" # Disable the timeout (risks hangs)Timeout checks occur between interpreted statements, including recursively interpreted callees and code passed to Core.eval (e.g. by @eval) during normal script analysis. In blocks selected by concretization_patterns, calls execute natively, so checks occur only at interpreted top-level statement boundaries. Package source analysis uses the catch-all pattern :(x_), so its callees also run natively.
Native calls, including ccall, builtins, and the __init__ functions of modules evaluated by Core.eval, cannot be interrupted. If they never return, analysis can still hang despite a finite timeout. Disabling the timeout with "inf" also risks indefinite hangs.
formatter
- Type: string or table
- Default:
"Runic"
Formatter configuration. Can be a preset name or a custom formatter object.
Preset options:
"Runic"(default): Uses Runic.jl ("runic"or"runic.bat"on Windows)"JuliaFormatter": Uses JuliaFormatter.jl ("jlfmt"or"jlfmt.bat"on Windows)
Custom formatter configuration:
formatter.custom.executable(string, optional): Path to custom formatter executable for document formatting. The formatter should read Julia code from stdin and output formatted code to stdout.formatter.custom.executable_range(string, optional): Path to custom formatter executable for range formatting. Should accept--lines=START:ENDargument.
Examples:
# Use JuliaFormatter preset
formatter = "JuliaFormatter"
# Or use custom formatter (both fields optional)
[formatter.custom]
executable = "/path/to/custom-formatter"
executable_range = "/path/to/custom-range-formatter"See the formatter integration section for detailed configuration instructions and setup requirements.
[diagnostic]
Configure how JETLS reports diagnostic messages (errors, warnings, infos, hints) in your editor. JETLS uses hierarchical diagnostic codes in the format "category/kind" (following the LSP specification) to allow fine-grained control over which diagnostics to show and at what severity level.
See the Diagnostic section for complete diagnostic reference including all available codes, their meanings, and examples.
[diagnostic] enabled
- Type: boolean
- Default:
true
Enable or disable all JETLS diagnostics. When set to false, no diagnostic messages will be shown.
[diagnostic]
enabled = false # Disable all diagnostics[diagnostic] all_files
- Type: boolean
- Default:
true
Enable or disable diagnostics for unopened files. When enabled, JETLS reports diagnostics for all Julia files in the workspace that full analysis covers (see How each file is analyzed), as well as for the .JETLSConfig.toml. When disabled, diagnostics are only reported for files currently open in the editor.
This setting affects all diagnostic sources. For JETLS/live, lowering-based analysis for unopened files is skipped when disabled (though the performance impact is minimal since lowering analysis is usually pretty fast). For JETLS/save, full analysis still runs; only reporting is suppressed. The same goes for JETLS/extra. Disabling this can be useful to reduce noise when there are many warnings across the workspace.
[diagnostic]
all_files = false # Disable diagnostics for unopened files[diagnostic] allow_unused_underscore
- Type: boolean
- Default:
true
When enabled, unused variable diagnostics (lowering/unused-argument and lowering/unused-local) are suppressed for names starting with _ (underscore). This follows the common convention in many programming languages where _-prefixed names indicate intentionally unused variables.
[diagnostic]
allow_unused_underscore = false # Report all unused variables[[diagnostic.patterns]]
Fine-grained control over diagnostics through pattern matching against either diagnostic codes or messages.
See the diagnostic reference section for a complete list of all available diagnostic codes, their default severity levels, and detailed explanations with examples.
Configuration syntax
Each pattern is defined as a table array entry with the following fields:
[[diagnostic.patterns]]
pattern = "pattern-value" # string: the pattern to match
match_by = "code" # string: "code" or "message"
match_type = "literal" # string: "literal" or "regex"
severity = "hint" # string or number: severity level
path = "src/**/*.jl" # string (optional): restrict to specific filespattern(Type: string): The pattern to match. For code matching, use diagnostic codes like"lowering/unused-argument". For message matching, use text patterns like"Macro name .* not found". This value is also used as the key when merging configurations from different sources.match_by(Type: string): What to match against"code": Match against diagnostic code (e.g.,"lowering/unused-argument")"message": Match against diagnostic message text
match_type(Type: string): How to interpret the pattern"literal": Exact string match"regex": Regular expression match
severity(Type: string or number): Severity level to applypath(Type: string, optional): Glob pattern to restrict this configuration to specific files. Patterns are matched against file paths relative to the workspace root. Supports globstar (**) for matching directories recursively. If omitted, the pattern applies to all files.
Severity values
Severity level to apply. Can be specified using either string or number values:
"error"or1: Critical issues that prevent code from working correctly"warning"or"warn"or2: Potential problems that should be reviewed"information"or"info"or3: Informational messages about code that may benefit from attention"hint"or4: Suggestions for improvements or best practices"off"or0: Disable the diagnostic
String values are case-insensitive. The numeric values correspond to the LSP specification, while "off"/0 is a JETLS-specific extension for disabling diagnostics.
Pattern matching priority
When multiple patterns match the same diagnostic, more specific patterns take precedence. The priority order (highest to lowest) is:
messageliteral matchmessageregex matchcodeliteral matchcoderegex match
This priority strategy allows message-based patterns to override code-based patterns, enabling fine-grained control for specific diagnostic instances. When multiple matching patterns have the same priority, the later entry takes precedence.
Example showing priority:
# Lower priority: matches all lowering diagnostics
[[diagnostic.patterns]]
pattern = "lowering/.*"
match_by = "code"
match_type = "regex"
severity = "error"
# Higher priority: matches specific message
[[diagnostic.patterns]]
pattern = "Unused argument `x`"
match_by = "message"
match_type = "literal"
severity = "off"
# Highest priority among code patterns: exact code match
[[diagnostic.patterns]]
pattern = "lowering/unused-argument"
match_by = "code"
match_type = "literal"
severity = "hint"When diagnostic.enabled is false, all diagnostics are disabled regardless of pattern settings.
[diagnostic] configuration examples
[diagnostic]
enabled = true
# Pattern matching against diagnostic code
[[diagnostic.patterns]]
pattern = "lowering/.*"
match_by = "code"
match_type = "regex"
severity = "warning"
# Disable inference diagnostic entirely
[[diagnostic.patterns]]
pattern = "inference/.*"
match_by = "code"
match_type = "regex"
severity = "off"
# Show unused arguments as hints (overrides category setting)
[[diagnostic.patterns]]
pattern = "lowering/unused-argument"
match_by = "code"
match_type = "literal"
severity = "hint"
# Completely disable unused local variable diagnostics using integer value
[[diagnostic.patterns]]
pattern = "lowering/unused-local"
match_by = "code"
match_type = "literal"
severity = 0
# Pattern matching against diagnostic message
[[diagnostic.patterns]]
pattern = "Macro name `@interface` not found"
match_by = "message"
match_type = "literal"
severity = "off"
# Suppress all macro not found errors using regex
[[diagnostic.patterns]]
pattern = "Macro name `.*` not found"
match_by = "message"
match_type = "regex"
severity = "off"
# File path-based filtering: downgrade unused arguments in test files
[[diagnostic.patterns]]
pattern = "lowering/unused-argument"
match_by = "code"
match_type = "literal"
severity = "hint"
path = "test/**/*.jl"
# Disable all diagnostics for generated files
[[diagnostic.patterns]]
pattern = ".*"
match_by = "code"
match_type = "regex"
severity = "off"
path = "gen/**/*.jl"See the configuring diagnostics section for additional examples and common use cases.
[completion]
Configure completion behavior.
[completion.latex_emoji] strip_prefix
- Type: boolean
- Default: (unset) auto-detect based on client
Controls whether to strip the \ or : prefix from LaTeX/emoji completion item labels.
Some editors (e.g., Zed) don't handle backslash characters in the LSP sortText field, falling back to sorting by label. This can cause the expected completion item to not appear at the top when typing sequences like \le for ≤.
When set to true, JETLS strips the prefix from the label (e.g., \le becomes le), allowing these editors to sort completions correctly.
When set to false, JETLS keeps the full label with the prefix, which works correctly in editors (e.g., VSCode) that properly handle backslash characters in the sortText field.
When not set (default), JETLS auto-detects based on the client name and applies the appropriate behavior. Note that the auto-detection only covers a limited set of known clients, so if you experience LaTeX/emoji completion sorting issues (e.g., expected items not appearing at the top), try explicitly setting this option.
[completion.latex_emoji]
strip_prefix = true # Force prefix stripping for clients with sortText issuesIf explicitly setting this option clearly improves behavior for your client, consider submitting a PR to add your client to the auto-detection logic.
[code_lens]
Configure code lens behavior.
[code_lens] references
- Type: boolean
- Default:
false
Enable or disable the reference-count code lens. When enabled, JETLS displays a code lens above each top-level symbol (functions, structs, constants, abstract/primitive types, modules) showing how many times it is referenced in the codebase.
[code_lens]
references = true # Enable reference count code lenses[code_lens] testrunner
- Type: boolean
- Default:
true
Enable or disable TestRunner code lenses. When enabled, JETLS shows "Run" and "Debug" code lenses above @testset blocks for running individual tests.
Some editors (e.g., Zed) display code lenses as code actions, which can cause duplication when both code lenses and code actions are shown for the same functionality. In such cases, you may want to disable this setting.
[code_lens]
testrunner = false # Disable TestRunner code lenses[inlay_hint]
Configure inlay hint behavior.
[inlay_hint.block_end]
Inlay hints displayed at block end keywords. See Block-end hints for details.
[inlay_hint.block_end] enabled
- Type: boolean
- Default:
true
Enable or disable block-end inlay hints.
[inlay_hint.block_end]
enabled = false # Disable block-end inlay hints[inlay_hint.block_end] min_lines
- Type: integer
- Default:
25
Minimum number of lines a block must span before its end-tag inlay hint is displayed.
[inlay_hint.block_end]
min_lines = 10 # Show hints for blocks with 10+ lines[inlay_hint.types]
Inferred-type inlay hints displayed next to expressions. See Type hints for details.
[inlay_hint.types] enabled
- Type: boolean
- Default:
true
Enable or disable type inlay hints.
[inlay_hint.types]
enabled = false # Hide type hints; keep `end`-tag hints[testrunner]
Configure the Julia process that runs tests for the TestRunner integration and jetls test.
[testrunner] env
- Type: table of strings
- Default:
{}
Environment variables for the Julia process that runs tests. By default, tests run with the Julia running JETLS. The following variables select another Julia, in the same way as the managed installations of the VSCode and Zed extensions do:
JULIA_APPS_JULIA_CMD: path to the Julia executable to run tests withJULIAUP_CHANNEL: juliaup channel to run tests with; this takes effect when thejuliacommand resolves to the juliaup launcher, and is ignored whenJULIA_APPS_JULIA_CMDis set
[testrunner]
env = { JULIAUP_CHANNEL = "1.12", JULIA_NUM_THREADS = "4" }JULIA_DEPOT_PATH, JULIA_LOAD_PATH, and JULIA_PROJECT cannot be set, since JETLS uses them to load TestRunner.jl. The environment of the tests is the nearest Project.toml of the test file, which can be overridden with julia_args.
The first test run with a Julia other than the one running JETLS precompiles TestRunner.jl and its dependencies for that Julia, which may take a while. TestRunner.jl requires Julia 1.12 or later. Julia versions not supported by JETLS itself, such as nightly, can be selected as well, but running tests with them may break.
The --julia option of jetls test takes precedence over the Julia selected by these variables.
[testrunner] julia_args
- Type: array of strings
- Default:
[]
Additional command-line options for the Julia process that runs tests. These take precedence over the options set by JETLS; for example, --project=/path/to/env overrides the environment detected from the test file.
[testrunner]
julia_args = ["--threads=4", "--project=/path/to/env"]Options that affect precompilation, such as --check-bounds=yes, make the first test run precompile TestRunner.jl and its dependencies for them.
The --project option of jetls test takes precedence over --project given here.
How to configure JETLS
Method 1: File-based configuration
Create a .JETLSConfig.toml file in your project root. This configuration method works client-agnostically, thus allows projects to commit configuration to VCS without writing JETLS configurations in various formats that each client can understand.
Example
.JETLSConfig.toml:
# Use JuliaFormatter instead of Runic
formatter = "JuliaFormatter"
# Wait 2 seconds after save before running full analysis
[full_analysis]
debounce = 2.0
# Suppress unused argument warnings
[[diagnostic.patterns]]
pattern = "lowering/unused-argument"
match_by = "code"
match_type = "literal"
severity = "off"
[testrunner]
# Run tests with Julia 1.12 via juliaup
env = { JULIAUP_CHANNEL = "1.12" }
# Run tests with 4 threads
julia_args = ["--threads=4"]Method 2: Editor configuration via LSP
If your client supports workspace/configuration, you can configure JETLS in a client-specific manner. As examples, we show the configuration methods for the VSCode extension jetls-client, and the Zed extension JuliaEditorSupport/zed-julia.
VSCode (jetls-client extension)
Configure JETLS in VSCode's settings.json file with jetls-client.settings section:
Example
.vscode/settings.json:
{
"jetls-client.settings": {
// Wait 2 seconds after save before running full analysis
"full_analysis": {
"debounce": 2.0
},
// Use JuliaFormatter instead of Runic
"formatter": "JuliaFormatter",
// Change the severity of specific diagnostics
"diagnostic": {
"patterns": [
// Suppress toplevel/inference warnings in test folder
{
"pattern": "(toplevel|inference)/.*",
"match_by": "code",
"match_type": "regex",
"severity": "off",
"path": "test/**/*.jl"
}
]
},
"testrunner": {
// Run tests with Julia 1.12 via juliaup
"env": {
"JULIAUP_CHANNEL": "1.12"
},
// Run tests with 4 threads
"julia_args": ["--threads=4"]
}
}
}See package.json for the complete list of available VSCode settings and their descriptions.
Zed (JuliaEditorSupport/zed-julia extension)
Configure JETLS in Zed's settings.json file with the lsp.jetls.settings section:
Example
.zed/settings.json:
{
"lsp": {
"jetls": {
"settings": {
// Wait 2 seconds after save before running full analysis
"full_analysis": {
"debounce": 2.0,
},
// Use JuliaFormatter instead of Runic
"formatter": "JuliaFormatter",
// Change the severity of specific diagnostics
"diagnostic": {
"patterns": [
// Suppress toplevel/inference warnings in test folder
{
"pattern": "(toplevel|inference)/.*",
"match_by": "code",
"match_type": "regex",
"severity": "off",
"path": "test/**/*.jl",
},
],
},
"testrunner": {
// Run tests with Julia 1.12 via juliaup
"env": {
"JULIAUP_CHANNEL": "1.12",
},
// Run tests with 4 threads
"julia_args": ["--threads=4"],
},
},
},
},
}Server-agnostic clients (e.g., neovim, emacs lsp-mode, helix)
Settings should be placed under the "jetls" key, such that a request for the "jetls" section produces an instance of the JETLS configuration schema. For example, neovim's built-in LSP client may be configured as follows:
vim.lsp.config("jetls", {
settings = {
jetls = {
-- Wait 2 seconds after save before running full analysis
full_analysis = {
debounce = 2.0,
},
-- Use JuliaFormatter instead of Runic
formatter = "JuliaFormatter",
-- Change the severity of specific diagnostics
diagnostic = {
patterns = {
-- Suppress toplevel/inference warnings in test folder
{
pattern = "(toplevel|inference)/.*",
match_by = "code",
match_type = "regex",
severity = "off",
path = "test/**/*.jl",
},
},
},
testrunner = {
-- Run tests with Julia 1.12 via juliaup
env = { JULIAUP_CHANNEL = "1.12" },
-- Run tests with 4 threads
julia_args = { "--threads=4" },
},
},
},
})Configuration priority
When multiple configuration sources are present, they are merged in priority order (highest first):
- File-based configuration (
.JETLSConfig.toml) - Editor configuration via LSP (
workspace/configuration) - Built-in defaults
File-based configuration (.JETLSConfig.toml) takes precedence as it provides a client-agnostic way to configure JETLS that works consistently across all editors.
Configuration merging
For array-of-tables configuration fields (such as diagnostic.patterns), entries from both LSP config and file config are merged rather than one completely overriding the other. Entries with same keys are merged with file config taking precedence, while entries unique to either source are preserved. Other values, including [testrunner] env and [testrunner] julia_args, are overridden as a whole.
JSON schema
JETLS ships pre-generated JSON Schema files for all configuration surfaces. These can be used to enable IDE validation and auto-completion when editing configuration files or editor settings.
| Schema | Description |
|---|---|
config-toml.schema.json | Complete schema for .JETLSConfig.toml |
settings.schema.json | Settings schema (LSP workspace/configuration) |
init-options.schema.json | Initialization options schema |
You can also print any schema to stdout using the jetls schema CLI command:
Command reference
jetls schema --help
jetls schema - Print JSON schema for JETLS configuration
Usage: jetls schema [--settings | --init-options | --config-toml]
Options:
--settings Print the workspace settings schema
--init-options Print the initialization options schema
--config-toml Print the .JETLSConfig.toml configuration schema
--help, -h Show this help message
Examples:
jetls schema --config-toml # .JETLSConfig.toml schema
jetls schema --settings # settings schema
jetls schema --init-options # initialization options schema