Docs/Editors

Editors

Connect Nimbus to VS Code, JetBrains, or any editor that speaks LSP and DAP.

Commands

nimbus dev

Launch the interactive Dev UI in your default browser. Provides a visual interface for running tests, viewing coverage, exploring schema, and inspecting traces.

bash
nimbus dev           # Launch Dev UI on default port
nimbus dev --port 9000  # Launch on custom port

nimbus lsp

Start the Nimbus Language Server on stdio. Any editor that speaks LSP — VSCode, JetBrains IDEs, Neovim, Zed, Helix, Emacs — can launch this command to get Apex completion, hover, go-to-definition, inline coverage hints, mutation-score annotations, and live SOQL-column validation, all backed by the same parser, schema cache, and test data that powers nimbus test.

See the Language Server section for per-editor setup and a full capability list. This page covers only the CLI entry point.

bash
nimbus lsp                           # Start on stdio (what editors launch)
nimbus lsp --log /tmp/nimbus-lsp.log # Write a protocol trace to a file
nimbus lsp --stdio                   # Accepted for client compatibility (stdio is the default)
FlagDefaultDescription
--log-Write LSP protocol trace to this file. stderr-safe — stdout is reserved for JSON-RPC.
--stdiofalseAccepted for compatibility with clients that inject this flag. No-op; stdio is the only transport.

The server reads JSON-RPC 2.0 messages with Content-Length framing from stdin and writes responses to stdout. Never invoke this directly in an interactive shell — there is no TUI, just protocol bytes.

nimbus dap Pro

The debugger is Pro, in every mode: a live test or method session, a flow session, and replay — a recorded trace, an org debug log, or an anonymous-Apex run — are the same breakpoints and the same stepping. Recording is not: any run may write a trace, and nimbus trace timeline, the trace viewer, the editor timeline and coverage all stay free.

Start a Debug Adapter Protocol server on stdio. Any editor that speaks DAP — VSCode, IntelliJ, Neovim DAP — can launch this command to step through Apex tests with real breakpoints, a call stack view, and expandable local-variable inspection. This is the debug transport both first-party editors use automatically: the VSCode extension launches it as a DebugAdapterExecutable, and the IntelliJ plugin drives it through LSP4IJ's DAP integration. You don't need to configure either editor to get it — it's the default.

bash
nimbus dap   # Editors launch this; don't run in a shell

Supported DAP requests: initialize, launch, setBreakpoints, setExceptionBreakpoints, exceptionInfo, configurationDone, threads, stackTrace, scopes, variables, evaluate, setVariable, continue, next, stepIn, stepOut, stepBack, reverseContinue, pause, disconnect, terminate. Emits initialized, stopped, thread, output, and terminated events.

Beyond stepping and inspection, the server supports: conditional, hit-count, and log-point breakpoints (evaluated in the paused frame); caught/uncaught exception breakpoints, each optionally filtered to a comma-separated list of Apex exception types; expression evaluation for the debug console, watch expressions, and hovers; and editing a variable's value in place from the Variables pane (live sessions only — a replay session has nothing to write to).

Launch arguments (set in .vscode/launch.json, an IntelliJ run configuration, or equivalent) select one of four session kinds via mode:

FlagDefaultDescription
modelaunch"launch" runs a test live; "method" calls one method directly; "replay" steps a recorded trace; "flow" (Pro) debugs one record-triggered flow
program-mode "launch": test pattern, e.g. "CalculatorTest.addsPositive" or "*Test". A launch that names no target is rejected — it is never widened to the whole suite
test-mode "launch": synonym for program
pattern-mode "launch": synonym for program
testClass-mode "launch": the class to debug; joined with testMethod when both are given
testMethod-mode "launch": the method to debug, alongside testClass
method-mode "method": target in "ClassName.methodName" form. Setting it selects method mode on its own
isStaticfalsemode "method": call the method statically instead of constructing the class first
returnTypevoidmode "method": declared return type; a non-void type reports the result
parameters[]mode "method": argument list, each {name, type, value} with value as an Apex expression
traceFile-mode "replay": path to a trace.jsonl (or its run dir); implies replay mode. Omit to use the newest trace
flow-mode "flow": the flow’s API name (the .flow-meta.xml basename)
record-mode "flow": field map for $Record, e.g. {"Name": "Acme"}
triggerTypebeforeInsertmode "flow": "beforeInsert", "afterInsert", "beforeUpdate", or "afterUpdate"
projectPathCWDProject root containing sfdx-project.json
orgAliasdefaultSalesforce org alias
stopOnEntryfalsePause at the first statement of the program

Breakpoints

Breakpoints may be sent at any point in the configuration phase — before launch, between launch and configurationDone, or after both. A launch parks until the client says it has finished configuring, so the complete set is armed before the first Apex statement executes whichever order they arrive in.

A source may be spelled any way the client holds it: an absolute path, a path relative to the project, a file:// URI, or a bare source.name such as AccountService.cls. All of them resolve to the same file. A breakpoint on a source the project does not contain comes back verified: false with a message saying so, rather than verifying and never firing.

Calling one method directly, without a wrapping test:

json
{
  "type": "nimbus-apex",
  "request": "launch",
  "name": "Debug Method",
  "mode": "method",
  "method": "Calculator.add",
  "isStatic": true,
  "returnType": "Integer",
  "parameters": [
    { "name": "a", "type": "Integer", "value": "2" },
    { "name": "b", "type": "Integer", "value": "3" }
  ]
}

Trace replay (time-travel)

Replay mode steps through a recorded test run instead of executing anything. Record once with tracing on, then scrub through the captured execution — forwards and backwards — with the same breakpoints, call stack, and variable panels as a live session. Because nothing re-runs, a replay session is instant and perfectly deterministic.

First, record a trace. --trace records at verbose, which is the level that captures the statement-level steps replay walks; a run recorded with --trace-level below that loads but cannot be stepped.

bash
nimbus test "CalculatorTest.*" --trace

Then point a DAP launch config at it:

bash
{
  "type": "nimbus",
  "request": "launch",
  "name": "Replay last trace",
  "mode": "replay",
  "traceFile": ".nimbus/traces/2026-07-03T02-11-09_da70fda6/trace.jsonl"
}

A replay session announces supportsStepBack in a DAP capabilities event right after launchinitialize is answered before the launch mode is known, so that is the only place the per-session truth can go. A live session announces the same capability as false there, and refuses stepBack and reverseContinue with an error response, so a client that ignores the event still never waits on a request that cannot be served.

In replay mode stepBack and reverseContinue walk the timeline in reverse; breakpoints stop the cursor at the next matchingfile:line. next, stepIn, and stepOut each advance one recorded step (the trace is line-granular). Variable values come straight from the trace, so fidelity depends on the level you recorded at — verbose captures locals; a trace recorded below verbose has no steppable events and replay returns a clear error asking you to re-record.

Flow debugging Pro

Breakpoints work in .flow-meta.xml files: a flow element is defined at a concrete place in its XML, and a breakpoint set on — or anywhere inside — an element's block stops the session before that element executes. While paused, the stack shows a flow frame (flow name · current element), and its scopes expose $Record (plus $Record__Prior on updates), the flow's variables, and the current element's metadata. next advances to the next element — a decision's taken branch is the element you land on — stepIn on an Apex-action element enters the method, and stepOut runs the flow to completion.

This works in the default launch mode — a test whose DML fires a record-triggered flow stops at flow breakpoints mid-DML — and in the dedicated flow mode, which runs one record-triggered flow against a single in-memory record in a rolled-back database context, no Apex test required:

json
{
  "type": "nimbus-apex",
  "request": "launch",
  "name": "Debug Flow",
  "mode": "flow",
  "flow": "Account_Set_Rating",
  "record": { "Name": "Acme", "Industry": "Tech" },
  "triggerType": "beforeInsert"
}

Language Server (LSP)

Overview

Nimbus ships an LSP 3.17 server for Apex. Any editor that speaks the Language Server Protocol — VSCode, JetBrains IDEs, Neovim, Zed, Helix, Emacs — gets the same experience: schema-aware completion, hover documentation, go-to-definition, live SOQL column validation, per-line coverage hints, mutation score annotations, and code lenses that let you run or debug any @IsTest method inline.

Unlike Salesforce's stock Apex Language Server, which makes network round-trips to an org for metadata, Nimbus's LSP runs fully offline against the local .nimbus/schemas/ cache and surfaces platform truth — coverage %, surviving mutants, test flakiness — from your last nimbus test run.

The server is a thin layer over the same parser, schema provider, and test-data infrastructure that powers the CLI. Reparsing a file takes a few milliseconds; diagnostics land before your hand leaves the keyboard.

bash
# Start the server (editors launch this for you)
nimbus lsp

# Debug: write every JSON-RPC message to a log
nimbus lsp --log /tmp/nimbus-lsp.log

Features

The server advertises these LSP capabilities at initialize. Exactly what shows up in your editor depends on the client — VSCode renders everything; leaner clients may render a subset.

Member completion, hover and signature help cover the Apex standard library — full curated signatures and one-line documentation for the core types, and name-level completion for the long tail — plus your own classes, including chained calls, generics and inherited members. The same server also serves LWC templates and modules inside lwc/ folders: c- component tags and attributes from the workspace inventory, template directives, {binding} completion from the component's own class, and @salesforce/apex import completion sourced from the workspace's actual @AuraEnabled methods. Completing a member of one of your own classes carries the first sentence of its ApexDoc as the item's documentation.

lightning-* base components complete too, from a catalog generated from the same lightning-base-components release the org-free component preview compiles against and shipped inside nimbus — no node_modules needed, because a Salesforce project does not install one. Tags, their @api attributes with the types the package declares, and their event handlers (onclick, onchange). If a project has installed the package, that is read instead, so you always see the version you build against. A lightning- tag the catalog does not know is a warning naming the catalog version, never an error.

A component's class may be JavaScript or TypeScript, and the whole LWC surface reads either: a <name>.ts class supplies the same {binding} completions, the same @api attribute list to a parent's template, the same LWC003 unknown-binding diagnostic, and the same @salesforce/apex import completion inside the module. Type annotations, accessibility modifiers, optional (recordId?: string) and definite-assignment (label!: string) members, typed getters and generic signatures all read as the members they declare. A template completing against a TypeScript child, or a TypeScript component composing a JavaScript sibling, is the same lookup either way.

It serves Visualforce too — .page and .component files, wherever they live. Component tags and their attributes (required first, with types), attribute values where the domain is closed (mode, layout, booleans, action targets), and {!expression} completion resolved from the page's own controller stack — controller, every extensions class, getter conventions (getTotal() completes as {!Total}), standardController merge fields from the synced schema, and globals whose contents nimbus can actually see on disk: $Label from your .labels-meta.xml, $Resource from staticresources/, $Page from your other pages, $Component from the id= values in the buffer. Every item says where it came from. Components are split into the ones nimbus's own renderer composes locally — the same table nimbus app previews from — and the org-only long tail, labelled so a completion list is never mistaken for a promise that a preview will render it. Diagnostics (nimbus/visualforce) flag an unknown apex: component, an attribute a component does not have, and a {!binding} the controller stack provably does not declare — each one silent unless it can prove the case, and scored at zero findings across 288 real Visualforce files.

Editing intelligence

CapabilityWhat you see
DiagnosticsRed squiggles on parse errors. Yellow squiggles on SOQL column typos ([SELECT Namee FROM Account]), including relationship fields (Owner.Namee) once the chain resolves to a synced object. Faded-text hints on dead code (methods with zero references and zero coverage). Faded-text hints on unused local variables (nimbus/unused) — a name is only flagged when it appears nowhere else in the file, and a variable read from a dynamic-SOQL :bind inside a string counts as used. Red squiggles on the compile errors nimbus validate reports (nimbus/sema) — a construct the org refuses to compile is an error in the editor, not a warning — including, once the server has parsed every file in your package directories cleanly, the ones whose verdict needs the rest of the project: an undefined variable, an unknown type, an unknown method, a field the SObject does not have. Those switch on the moment that project-wide registry is complete (the server re-checks every open file when it lands, so you do not have to type again to see them) and stay off while it is not, because judging a name against half a project is how an editor invents defects. When they are off for a reason that will not fix itself — a file in the project that nimbus cannot parse, or a class outside your declared packageDirectories — you get one informational note at the top of the file saying so, instead of silence. Set nimbus.sema.projectWide: false to keep them off. Source labels nimbus/parse, nimbus/soql, nimbus/dead-code, nimbus/unused, or nimbus/sema.
CompletionAfter a. where a is an Account: 71+ real fields from .nimbus/schemas/Account.json. Inside a SOQL literal: the target SObject's columns; relationship traversal — typing Owner. or Account.Parent. resolves the relationship chain and completes the related object's columns; child subqueries ((SELECT … FROM Contacts)) complete the child object's columns; and SOSL RETURNING Account(…) completes that object's fields. Also: stdlib (System.*, Test.*, Database.*, UserInfo.*, Limits.*, Assert.*), keywords, in-file classes, and 12 Apex snippets (test, debug, soql, trycatch, …) with Tab-through placeholders.
HoverMethod signatures with return types, SObject field metadata, class mutation scores, test flakiness rate — plus your own ApexDoc: @description (or a plain lead paragraph), a parameter list matched against the real signature, @return, @throws, @see, @example as a code block, and tags like @author/@group verbatim. Works cross-file — the documented class doesn't have to be open. A @param naming a parameter the signature no longer has is marked as such rather than rendered as if it were real. Below a rule, hovering any line a recorded run touched adds Executed by: TestA.m1 ✓, TestB.m2 ✗ (last run 2m ago), or says the line was never executed in any recorded run. Nothing is added when no run covers the file at all — “we have no idea” and “no test covers this” are different answers and the editor never rounds one into the other.
Signature helpFloating parameter tooltip while typing a method call. Active parameter bolded, comma-counted even through generics like List<Map<String, Object>>. For your own methods, each slot carries its @param text.
Semantic tokensTheme-aware highlighting: annotations, keywords, stdlib namespaces, types, numbers, comments, strings. Custom required modifier reserved for <required>true</required> fields.
FormattingWhole-document, range (format selection) and on-type (closing-brace re-indent). Indentation, spacing, blank lines and inline SOQL layout, configured per project. See Formatting.

Navigation & refactoring

CapabilityWhat you see
Go-to-definitionJumps from any identifier to its declaration. Cross-file lookup across force-app/, src/, and stubs/.
Type definitionJumps from a variable reference to the .cls of its declared type (Account aAccount.cls).
ImplementationFrom an interface or base class name, returns every class that extends/implements it across the workspace.
Find all referencesWorkspace-wide caller lookup for any symbol. Powered by a reference index rebuilt incrementally on every keystroke.
RenameWorkspace-wide rename applied as a single atomic WorkspaceEdit. Keyword guard prevents renaming to reserved words. Renaming a top-level class, interface, enum or trigger also renames its .cls and .cls-meta.xml — Salesforce couples the two, and a file left under the old name is a project that no longer deploys. The file rename is sent only to editors that advertise workspace.workspaceEdit.resourceOperations; the rest get the references-only edit, and only an editor that will actually move the files is told so. prepareRename is advertised as RenameOptions{prepareProvider: true}, so the rename box opens pre-filled with the identifier under the caret and nothing else; when a rename cannot proceed the server refuses with a sentence naming both the reason and the symbol, rather than leaving the editor to say The element can’t be renamed.
Workspace symbol searchCmd+T finds any class, method, field, or enum across the repo. Ranks exact match → prefix → substring, capped at 500 results.
Document symbolsFull outline tree: classes → methods, fields, properties, inner classes, enums. Powers the editor's sidebar outline and sticky scroll.
Document highlightSame-symbol highlighting of every occurrence of the identifier under the cursor.
Folding rangesBrace-based code folds for classes, methods, and block comments.
Selection rangesExpand-selection (Ctrl+W in JetBrains, Shift+Alt+→ in VSCode): word → line → file.
Call hierarchyMethod-level caller tree. Incoming and outgoing calls resolved through the workspace symbol index.

Code actions (quick fixes and refactors)

ActionWhere it shows
SOQL column auto-fixYellow bulb next to an unknown-field diagnostic — offers up to 3 Levenshtein-ranked candidates. Fix: 'Namee' → 'Name'.
Run nimbus syncOffered as the fix for an unknown-sobject diagnostic.
Remove unused variableOn an unused-local hint. Removes the declaration outright when the initializer can't do anything (a literal, a field read, an SObject or collection construction); strips it down to the bare call when the initializer is a call, so the call survives; offers nothing at all when neither is true.
Fix a modifier the platform rejectsOn nimbus/sema warnings whose repair is unambiguous: adds static to a @future/@InvocableMethod/@TestSetup/@IsTest/webservice/@RemoteAction/@Http* method; makes an @InvocableMethod public; removes static from a constructor, virtual from a static method, or an illegal modifier from a parameter; rewrites System.String to String; marks the defining type abstract when it holds an abstract method.
Qualify a static callOn a static method reached through an instance: rewrites the receiver to the type name. Only offered when exactly one call on the line matches.
Did you mean…On a member that doesn't exist on its receiver but has a near-neighbour that does. Only offered where the member list is provably complete — an SObject with a synced schema, or a user class whose whole inheritance chain resolves in the workspace.
Generate ApexDocOn an undocumented method or class: inserts a /** */ stub with @description, one @param per real parameter, and @return when something is returned. Lands above the annotations, indented with the member. Never offered on a declaration that already carries a comment.
Generate test stubOn any non-test method: scaffolds ClassNameTest.test_method() with schema-aware constructor calls (new Account(Name='Test') from the real required-fields set).
Extract to @TestSetupOn insert statements inside a test method.
Add @IsTest annotationOn classes whose name ends in Test but lack the annotation.
Generate constructorOn a class declaration line: emits a constructor assigning every uninitialised instance field from a like-named parameter.
Generate getters and settersOn a class declaration line: accessor methods for the instance fields that lack them (skips existing accessors and final-field setters).
Implement interface methodsOn a class declaration line with an implements clause: stubs every not-yet-implemented method. Resolves interfaces same-file, workspace-wide, and for common system interfaces (Queueable, Schedulable, Comparable, Database.Batchable).
Override superclass methodsOn a class declaration line with an extends clause: override stubs for the superclass's virtual/abstract methods not yet overridden (virtual delegates to super.x(), abstract gets a TODO).
Generate toString()On a class declaration line: a public override String toString() rendering every instance field. Declared with override, which the platform requires for this method and rejects for equals(). Not offered when the class already has one, or has no instance field to render.
Generate equals() and hashCode()On a class declaration line: the pair that makes a class usable as a Map key or Set member, over every instance field. Generated together and declined together — a hashCode() covering fields a hand-written equals() ignores makes a Map lose entries silently.
Extract variableOn a selected expression: hoists <Type> name = expr; above the statement and replaces the selection. The declared type is inferred from the surrounding slot first (a [SELECT …] assigned to Account acc is an Account) and from the expression's structure otherwise. Not offered when the type cannot be inferred, or when the hoist would change the program — a while / C-style for header re-evaluates, a when value must stay constant.
Extract constantOn a selected literal: private static final <Type> NAME = literal; at the top of the class body, named in SCREAMING_SNAKE from the literal's content. A separate N occurrences action replaces every copy in the same class.
Extract methodOn a selected run of complete statements: a new private method after the current one, static-ness inherited. Parameters are the locals the selection reads that were declared above it; the return value is the single local it produces that the code below still uses. Not offered when two locals would need returning (Apex has no tuples), when the selection contains a return, or when a break/continue's loop is outside it.
Inline variableOn a local's declaration or any use: substitutes the initialiser, parenthesised where precedence needs it, and removes the declaration. Not offered for a reassigned variable, for an effectful or allocating initialiser facing more than one use, or when anything the initialiser reads is mutated before that use.
Change signatureOn a method declaration: rewrites the parameter list and every call site — inserting the default value you give for an added parameter, dropping a removed one, following the mapping when the list is reordered, and renaming a kept parameter's uses in the body. Every declaration moves together, so an interface's implementors and a base class's overrides stay in step. Refuses whole, editing nothing, when any call site's receiver cannot be typed. Constructors are out of scope: new Foo(…) is not resolved back to the constructor it calls, so nimbus cannot promise to rewrite every caller.
Safe deleteOn a method, field or top-level class declaration: removes the declaration — annotations and ApexDoc included, and for a class its .cls and .cls-meta.xml. Refuses with the list of surviving references when anything still uses it. An occurrence nimbus could not resolve counts as a reference.
Move inner class to top levelOn an inner class declaration: extracts it into <Inner>.cls with a -meta.xml from the same generator nimbus new uses, rewrites Outer.Inner to Inner across the workspace, and qualifies references to the outer class's public statics and sibling types. private becomes public — Apex has no private top-level class — and the action title says so. Refuses when a top-level type of that name already exists, or when the class reads something a separate file cannot reach.
Rename a class with its testOn a top-level class declaration that has a <Name>Test beside it: renames both, and both sets of files. Opt-in and offered separately from Rename — the Test suffix is a convention, not a fact about your project.

Platform-data overlays (Nimbus-exclusive)

CapabilityWhat you see
Inlay hintsParameter names in front of each argument at a call site (tierFor(points: 2000)), for your own methods and the Apex stdlib alike — on by default, and available with no test run behind it. A hint is left out when the argument already says the name (tierFor(points)) or when a one-argument method name says it (setRegion('EU')), and when overloads disagree about what the argument is called. Turn them off with nimbus.inlayHints.parameterNames: false. Once a run has recorded them, ghost text next to each method also carries the hit count from coverage (, not covered), surviving mutant descriptions (☠ survived: Shifted loop bound +1), flaky-test warnings (⚠ flaky (12%)), and the per-class mutation score.
Code lensesInline buttons above every class and method: ▶ Run test, ◉ Debug, 🪄 Coverage, ≡ View Trace on @IsTest methods; ▶ Run class, ⏱ Bench class on test classes; ☣ Mutate on production classes.
Dead code detectorHint-severity diagnostic on methods with zero workspace references and zero coverage hits. Skips global, virtual, abstract to avoid false positives on public APIs.

Change signature, safe delete, move-inner-class and rename-with-test are also reachable as workspace/executeCommand(nimbus.changeSignature, nimbus.safeDelete,nimbus.moveInnerClass, nimbus.renameClass), which is how an editor drives the ones that need a dialog.

Still on the roadmap: inline values while debugging (blocked on LSP ↔ DAP co-hosting), coverage-filtered call hierarchy, inline- method, and long-tail protocol polish (pull-model diagnostics, completion resolve, cross-workspace monikers). SeeLSP_ROADMAP.md in the source for the full plan.

Formatting

Three LSP formatting capabilities: whole-document (textDocument/formatting), range — format-selection — (textDocument/rangeFormatting), and on-type re-indent of a closing brace (textDocument/onTypeFormatting, registered for the closing brace only).

What it guarantees

The formatter only ever changes whitespace. Every token it writes is a token it read, so the code after formatting parses to the same thing as the code before — including inside [SELECT …] literals, where whitespace is significant and a careless formatter would quietly rewrite 2024-01-01T00:00:00Z or LAST_N_DAYS:30. Formatting is also idempotent: running it twice gives the same result as running it once. Both properties are enforced on every release against the full open-source Apex corpus — 24,343 files.

Two things make it safe to leave on for format-on-save. A file that does not parse gets no edits at all, rather than a partial re-layout of a token stream you are halfway through typing. And any region between // nimbus-format:off and // nimbus-format:on comes back byte-identical:

bash
// nimbus-format:off
private static final Integer[][] KERNEL = new Integer[][]{
      new Integer[]{ -1, -1, -1 },
      new Integer[]{ -1,  8, -1 },
      new Integer[]{ -1, -1, -1 }
};
// nimbus-format:on

What it does not do

It does not move braces — Apex brace style is settled, and offering alternatives would only produce diff noise between teams. It does not re-flow your line breaks either: a statement you broke across lines stays broken, and a query you spread over five lines stays over five lines. The formatter adds line breaks (long queries, optionally long call chains) and fixes indentation and spacing; it does not overrule where you chose to breathe.

Configuration

Every key goes in nimbus.properties at the project root, so a team shares one answer and CI can check it. Project settings outrank your editor's own tab width on purpose: an editor configured for 2 spaces must not quietly reformat everyone else's 4-space code. Keys you leave out fall through to the editor's settings, then to the defaults below.

PropertyDefaultWhat it does
nimbus.format.indent-size4Width of one indent level, in spaces.
nimbus.format.use-tabsfalseIndent with one tab per level instead of spaces.
nimbus.format.max-blank-lines2Cap on consecutive blank lines. 0 removes them all.
nimbus.format.spaces-around-operatorstrueNormalises spacing: a=b+c becomes a = b + c, generics stay tight (Map<String, List<Id>>), casts get one space ((Integer) o), unary and postfix operators stay attached. Set false to reproduce your spacing exactly and fix only indentation, trailing whitespace and blank runs.
nimbus.format.soql.stylealignedaligned breaks a query at its clause keywords when it exceeds the width below, or when you already broke it. single-line always collapses to one line. preserve leaves queries byte-identical.
nimbus.format.soql.max-line-length120Width past which an aligned query breaks. A SELECT list still longer than this stacks one field per line.
nimbus.format.annotationspreserveown-line moves an annotation off its declaration (@TestVisible private String x; → two lines). preserve leaves it where you put it.
nimbus.format.chain-wrap-threshold0 (off)Width past which a method chain of two or more call links breaks before each link. Qualified names (Schema.SObjectType.Account) are never broken.
nimbus.format.trim-trailing-whitespacetrueStrip trailing spaces and tabs from every line.
nimbus.format.insert-final-newlinetrueEnd the file with exactly one newline.

SOQL layout

A query that fits stays on its line. One that does not is broken at clause keywords:

bash
// before
List<Account> found = [SELECT Id, Name, Industry, BillingCity, Phone FROM Account WHERE Name LIKE :term AND Id IN :ids ORDER BY Name LIMIT 100];

// after
List<Account> found = [
    SELECT Id, Name, Industry, BillingCity, Phone
    FROM Account
    WHERE Name LIKE :term AND Id IN :ids
    ORDER BY Name
    LIMIT 100
];

When the SELECT list alone is longer than soql.max-line-length, the fields stack:

bash
List<Account> found = [
    SELECT
        Id,
        Name,
        Industry,
        BillingCity,
        BillingCountry,
        Phone,
        Website
    FROM Account
];

Example

bash
# nimbus.properties
nimbus.format.indent-size=4
nimbus.format.max-blank-lines=1
nimbus.format.soql.max-line-length=100
nimbus.format.chain-wrap-threshold=100

# Reproduce the pre-1.x layout exactly
#nimbus.format.spaces-around-operators=false
#nimbus.format.soql.style=preserve

nimbus config properties lists these alongside every other supported key, and nimbus config init writes a commented example file.

VSCode

The Nimbus VSCode extension auto-starts the LSP when the extension activates on a Salesforce project. No extra configuration needed. Toggle it off with the nimbus.lsp.enabled setting if you want to fall back to Salesforce's stock Apex LSP.

json
// .vscode/settings.json
{
  "nimbus.lsp.enabled": true,      // default
  "nimbus.binaryPath": "nimbus"    // if 'nimbus' is not on PATH, point here
}

Check that the server is running: View → Output, pick Nimbus Apex Language Server from the dropdown. You should see JSON-RPC messages for each keystroke. The Nimbus LSP Trace channel has the protocol-level detail if you need to debug further.

Neovim

Neovim 0.11+ has native LSP support. Drop this into your config:

lua
-- ~/.config/nvim/init.lua (or any loaded file)
vim.lsp.config.nimbus = {
  cmd = { 'nimbus', 'lsp' },
  filetypes = { 'apex', 'apexcode' },
  root_markers = { 'sfdx-project.json' },
  -- Optional: write a protocol trace for debugging
  -- cmd = { 'nimbus', 'lsp', '--log', '/tmp/nimbus-lsp.log' },
}
vim.lsp.enable('nimbus')

-- .cls and .trigger don't have a built-in filetype; teach Neovim:
vim.filetype.add({
  extension = {
    cls = 'apex',
    trigger = 'apex',
  },
})

For older Neovim (0.8–0.10) using nvim-lspconfig:

lua
require('lspconfig.configs').nimbus = {
  default_config = {
    cmd = { 'nimbus', 'lsp' },
    filetypes = { 'apex' },
    root_dir = require('lspconfig.util').root_pattern('sfdx-project.json'),
    settings = {},
  },
}
require('lspconfig').nimbus.setup({})

Zed

Zed uses per-language server configuration in settings.json:

json
// ~/.config/zed/settings.json
{
  "lsp": {
    "nimbus": {
      "binary": { "path": "nimbus", "arguments": ["lsp"] }
    }
  },
  "languages": {
    "Apex": { "language_servers": ["nimbus"] }
  },
  "file_types": {
    "Apex": ["cls", "trigger"]
  }
}

Helix

Helix wires LSP via languages.toml:

toml
# ~/.config/helix/languages.toml
[language-server.nimbus-lsp]
command = "nimbus"
args = ["lsp"]

[[language]]
name = "apex"
scope = "source.apex"
file-types = ["cls", "trigger"]
roots = ["sfdx-project.json"]
language-servers = ["nimbus-lsp"]

JetBrains (IntelliJ, WebStorm, etc.)

The simplest path is the dedicated Nimbus JetBrains plugin — it wires up the language server, test running, debugging, coverage, and tool windows for you. Install Nimbus — Local Apex Runtime from the Marketplace and you’re done.

If you’d rather wire the language server by hand, JetBrains 2023.2+ supports generic LSP servers via the LSP4IJ plugin (or built-in LSP support in paid editions). After installing LSP4IJ:

  1. Settings → Languages & Frameworks → Language Servers → +
  2. Name: Nimbus Apex
  3. Command: nimbus lsp
  4. Mappings: file type *.cls and *.trigger

Code lenses, inlay hints, completion, and hover all render natively in the JetBrains UI. Go-to-definition uses the standard Cmd+B / Ctrl+B shortcut.

Emacs

With lsp-mode:

lisp
(use-package lsp-mode
  :hook ((apex-mode . lsp)))

(with-eval-after-load 'lsp-mode
  (lsp-register-client
    (make-lsp-client :new-connection (lsp-stdio-connection '("nimbus" "lsp"))
                     :major-modes '(apex-mode)
                     :server-id 'nimbus-lsp)))

With eglot (built-in since Emacs 29):

lisp
(with-eval-after-load 'eglot
  (add-to-list 'eglot-server-programs
               '(apex-mode . ("nimbus" "lsp"))))

Troubleshooting

The server fails to start

  • Run nimbus --version in a terminal to confirm the binary is on PATH.
  • Start the server manually: nimbus lsp --log /tmp/nimbus-lsp.log. Type a few characters and hit Ctrl+C. The log should show JSON-RPC messages; if the file is empty, the binary isn't being found by the editor.

Diagnostics don't appear

  • Check the editor's LSP status — most editors surface a connection indicator. In VSCode, View → Output → Nimbus Apex Language Server.
  • Verify the file extension is mapped to apex language. Neovim in particular doesn't auto-detect .cls.

Completion is empty after `a.`

  • The LSP needs the variable's declared type. If a is declared in a different file, cross-file type resolution isn't wired yet — declare it locally, or use the fully-qualified class name: Account.Name instead ofa.Name.
  • Custom SObjects appear after running nimbus sync once to populate .nimbus/schemas/.

Coverage / mutation inlay hints don't show

  • Parameter-name hints need no run at all; the coverage and mutation hints do.
  • Coverage inlay hints require a recent nimbus test --coverage run so .nimbus/coverage/latest.json exists. Mutation hints need nimbus mutate to have populated .nimbus/mutations/latest.json.
  • The flaky hint needs at least two comparable recorded runs — same sources, same worker count, same isolation. Every run refreshes .nimbus/history/flaky.json; with fewer than two comparable runs there is no evidence and no hint.
  • Some editors hide inlay hints by default — check the "Editor: Inlay Hints" toggle in your settings.

The Salesforce LSP and Nimbus LSP are both running in VSCode

The Salesforce Apex extension and the Nimbus extension can coexist, but you'll get duplicate completion entries. Set nimbus.lsp.enabled: false to fall back to Salesforce's LSP, or disable the Salesforce Apex extension to use only Nimbus.

VSCode Extension

Overview

The Nimbus VSCode extension brings the full test runner into your editor — inline results, coverage gutters, a debugger, execution traces, governor limit tracking, and more. It communicates with the nimbus daemon over a local JSON-RPC connection, so test runs feel instant: no cold-start, no reloading metadata on every run.

The extension also auto-starts the Nimbus Language Server for editing intelligence — completion, hover, go-to-definition, SOQL column validation, and coverage inlay hints. The LSP is a sibling subsystem to the test runner, independent of the daemon socket. Toggle it with nimbus.lsp.enabled in settings.

The extension activates automatically when it detects a Salesforce project (sfdx-project.json, force-app/, or any .cls file). Check the status bar — a Nimbus indicator shows whether the daemon is connected. If it shows a slash through it, run Nimbus: Restart Daemon from the command palette and check the Nimbus output channel for details.

New install? Open Help → Welcome → Get Started with Nimbus for a seven-step walkthrough covering the test runner, watch mode, coverage, the dependency graph, and the sidebar views. Common actions — run tests in file, validate, execute anonymous, dependency graph — are also on the right-click menu in any Apex file, and the dependency graph has a dedicated hierarchy icon in the editor title bar.

The daemon requires a Pro license. Free-tier users can still run tests from the CLI with full coverage and governor limit support, but the live editor integration (inline results, trace viewer, history) requires Pro.

Running Tests

Inline buttons (CodeLens)

Every @isTest class shows action buttons directly above the code — no menus needed.

LocationActions
Class declarationRun All Tests, Validate
Each @isTest methodRun Test, Debug Test, View Trace
Non-test class declarationValidate
Non-test public methodRun, Debug

Test Explorer

Nimbus integrates with VSCode's native Test Explorer. Tests are discovered automatically when the daemon connects — no configuration needed. Run, debug, and filter tests from the standard VSCode testing UI.

Understanding results

After a test run:

  • A notification shows the pass/fail summary and total time
  • The Nimbus output channel shows results grouped by class and method
  • Inline pass/fail decorations appear on executed lines in the editor
  • The status bar shows live progress during the run (3/10 tests...)

Debugging Pro

Nimbus supports the full VSCode debug protocol via nimbus dap — breakpoints, stepping, expression evaluation, variable inspection and editing, and the call stack. Debugging and replay are Pro; running tests, recording a trace and coverage are not.

Debug a test method

  1. Open a test class
  2. Set breakpoints by clicking the gutter on any line — right-click a breakpoint to add a condition, hit count, or turn it into a log point
  3. Click Debug Test above an @isTest method
  4. Use the debug toolbar: Step Over (F10), Step In (F11), Step Out (Shift+F11), Continue (F5)
  5. Inspect locals in the Variables panel — edit a value in place, or add expressions to Watch; view the call stack in Call Stack

The Breakpoints pane also lets you break on uncaught or caught exceptions, each independently filterable to specific Apex exception types.

Debug any public method

Not limited to tests. Click Debug above any public method in a non-test class. If the method has parameters, Nimbus prompts you to enter values before starting.

Launch configurations

You can also configure debug targets in .vscode/launch.json — see nimbus dap for the full argument reference, including method-mode and trace-replay sessions:

json
{
  "type": "nimbus-apex",
  "request": "launch",
  "name": "Debug My Test",
  "program": "MyTestClass.myTestMethod",
  "stopOnEntry": false
}

Coverage

Enable coverage collection by setting nimbus.coverage.enabled to true, or pass --coverage from the CLI. After a test run with coverage enabled:

Gutter icons

Colored icons appear in the editor gutter next to each line:

IconMeaning
Green circleLine was executed during the test
Red circleLine was not executed
Yellow circleBranch partially covered (e.g. only the true path of an if)

Toggle gutter icons with the nimbus.coverage.showGutterIcons setting.

Method coverage annotations

An inline annotation appears after each method signature:

apex
public static void processRecords(List<Account> accounts)  // 75% (3/4 lines)

Run Nimbus: Show Coverage from the command palette for the full coverage report in the output channel.

Trace Viewer Pro

The trace viewer shows a detailed execution trace for every method call, branch decision, and variable assignment during a test run. Click View Trace above any test method after running it, or run Nimbus: View Execution Trace from the command palette.

The trace viewer opens as a side panel with three tabs:

TabWhat it shows
Call TreeIndented tree of all method invocations. Each node shows name, duration, and pass/fail status. Click any node to inspect it.
TimelineHorizontal waterfall chart. Wider bars = slower methods. Useful for spotting bottlenecks at a glance.
LogFilterable list of all trace events with timestamps. Use the search box to filter by method name or event type.

Selecting any span in any tab updates the right sidebar with the captured local variables,System.debug() output, and span metadata (source file, line number, status).

Sidebar Views

Click the Nimbus icon in the activity bar to open the dedicated views.

Tools

A launcher at the top of the panel. One click opens the dependency graph, coverage, history trends, execute anonymous, or toggles watch mode — no command palette needed.

Test History

Shows past test runs sorted newest first. Each run shows a pass/fail icon and summary (e.g. 3/3 passed (250ms)). Expand any run to see results by class, then by method.

From the view title bar, Show History Trends opens a chart of pass rate over the last 30 days plus a flaky test table — tests that flip between pass and fail across runs.

Right-click any run and choose Compare With... to open a side-by-side diff of two runs. The diff highlights flipped tests, duration changes, and new or removed methods.

Governor Limits

Shows Salesforce governor limit consumption per test method, updated automatically after each run. Expand any method to see individual limits:

LimitColor coding
SOQL Queries, SOQL Query Rows, DML Statements, DML Rows, CPU Time, Heap Size, HTTP Callouts, Future Calls, Queueable Jobs, Email InvocationsGreen (<50%), Yellow (50–80%), Red (>80%)

Governor limit annotations also appear inline in the editor as CodeLens above each method. Toggle with the nimbus.governor.showCodeLens setting.

Schema Explorer

Browse the local PostgreSQL schema that Nimbus uses to store SObject data. Expand any table to see columns (name, type, constraints), outgoing foreign keys, and incoming references from other tables. Use the refresh button after importing new metadata.

Watch Mode Pro

Automatically re-run tests whenever Apex files change.

  1. Click the Watch: off button in the status bar, or run Nimbus: Toggle Watch Mode
  2. If your project has multiple package directories, choose All Packages or a specific package
  3. The status bar updates to show the active scope (e.g. Watch: force-app)
  4. Save any .cls or .trigger file — tests re-run automatically
  5. After each watch-triggered run the status bar briefly shows the result (Watch: all passed or Watch: 2 failed)
  6. Click the button again to disable

Diagnostics & Validation

Nimbus validates Apex syntax in real time and surfaces errors in the Problems panel (Cmd+Shift+M).

  • On save — when nimbus.validateOnSave is enabled (default: true), every .cls and .trigger file is checked automatically
  • Manual — run Nimbus: Validate Current File to check the active file
  • Quick fixes — some parse errors offer a lightbulb with suggested fixes (e.g. adding a missing semicolon)

Errors appear as red squiggles in the editor and as entries in the Problems panel.

Execute Anonymous & Run Any Method

Execute Anonymous Apex

Run arbitrary Apex without creating a class. Run Nimbus: Execute Anonymous Apexfrom the command palette. If text is selected, only the selection runs — otherwise the entire file runs. Output (including System.debug()) appears in theNimbus output channel.

Run any public method

Click Run above any public method in a non-test class. If the method has parameters, input boxes appear for each one with type hints. The return value and execution time appear as an inline annotation next to the method signature.

Auto-retrieve missing metadata

When tests fail due to missing SObjects, fields, or other metadata not in your local project, Nimbus detects what's missing and shows a warning notification. Choose:

OptionWhat happens
Fetch & Re-runRetrieves the missing metadata from your connected org and re-runs the failed tests
Show DetailsOpens the output channel with the missing items and the sf CLI commands to retrieve them manually
DismissIgnores for now

You can also trigger this manually with Nimbus: Fetch Missing Metadata & Re-run.

Commands

All commands are available from the command palette (Cmd+Shift+P) with the Nimbus: prefix.

CommandDescription
Run All TestsRun every @isTest class in the project
Run Tests in Current FileRun all tests in the active editor file
Run Test ClassRun all tests in a specific class by name
Run Test MethodRun a specific test method
Debug Test MethodStart a debug session for a test method
Cancel Test RunStop the currently running tests
Validate Current FileCheck Apex syntax, report errors to Problems panel
Execute Anonymous ApexRun selected or all Apex code in the active file
Show CoverageDisplay the full coverage report in the output channel
Toggle Watch ModeEnable or disable auto-run on file save
Show StatusShow daemon version, uptime, and database status
Restart DaemonRestart the background daemon process
View Execution TraceOpen the trace viewer for a test method
Show History TrendsOpen pass rate chart and flaky test table
Compare Test RunsDiff two historical runs side by side
Refresh SchemaReload the Schema Explorer
Fetch Missing Metadata & Re-runRetrieve missing metadata from the org and re-run failed tests

Settings

All settings are under the nimbus.* namespace in VSCode settings.

FlagDefaultDescription
nimbus.binaryPath"nimbus"Path to the nimbus CLI binary
nimbus.parallel4Number of parallel test workers
nimbus.lsp.enabledtrueRun the Nimbus Language Server for Apex editing (completion, hover, inlay hints, SOQL validation). Disable to fall back to Salesforce’s stock Apex LSP.
nimbus.coverage.enabledfalseCollect coverage data on test runs
nimbus.coverage.showGutterIconstrueShow green/red/yellow coverage icons in the editor gutter
nimbus.validateOnSavetrueValidate Apex syntax automatically on save
nimbus.autoRun.onOpenfalseAuto-run tests when a test file is opened
nimbus.autoRun.onSavefalseAuto-run tests when a test file is saved
nimbus.performance.showInlineTimingstrueShow method execution time annotations in the editor
nimbus.governor.showCodeLenstrueShow governor limit CodeLens above methods

JetBrains Plugin

Feature overview: Nimbus for JetBrains.

The Nimbus plugin brings the full local Apex runtime to IntelliJ IDEA — Community and Ultimate alike — and to any JetBrains IDE from 2024.2 that ships JCEF, the embedded browser Learn, the graph and the timeline render in. JCEF is a hard dependency, so an IDE built without it will not load the plugin. Nothing here needs a JDK of your own: the plugin runs on the IDE's own runtime, which is Java 21 on every supported build. It shares the same two engines as the VSCode extension: the nimbus lsp language server (completion, hover, navigation, rename, diagnostics, code lenses, inlay hints) and the nimbus daemon JSON-RPC server (test running, debugging, coverage, traces, history, schema, governor limits).

Editor intelligence is delivered through LSP4IJ, which the plugin pulls in automatically from the JetBrains Marketplace.

The plugin also bundles native Apex/SOQL live templates — type an abbreviation and press Tab to expand, then Tab through the placeholders. A few: sysdSystem.debug(), tm → an @IsTest method, tc → a test class, soqlf → a bulk-safe SOQL for-loop, bulkt → a 200-record test-data block, mapidMap<Id, SObject> from a list. The full set lives under Settings → Editor → Live Templates → Nimbus Apex.

Install

Install Nimbus — Local Apex Runtime from Settings → Plugins → Marketplace. The Marketplace resolves the LSP4IJ dependency for you. That is the whole install: on first open of a Salesforce project the plugin puts the nimbus runtime in ~/.nimbus/bin, starts the daemon, and warms the language server. It runs that binary by absolute path, so nothing in the IDE depends on your shell’s PATH, and a copy you installed yourself — via Homebrew, Scoop, or the script below — is always preferred and never replaced. Turn the automatic install off with Install the Nimbus runtime automatically under Settings → Tools → Nimbus, or point Nimbus binary path at an explicit one.

Installing the CLI yourself is optional, and only matters if you want the nimbus command in a terminal as well:

bash
curl -fsSL https://install.testnimbus.dev | sh

If a new terminal cannot find nimbus afterwards, put the install directory on your PATH — one line in ~/.zshrc or ~/.bashrc, or the User Path variable on Windows.

Running & Debugging

Code lenses appear above the declaration they act on, and only where they apply. Above an @IsTest method: Run test, Debug, Coverage, View Trace. Above an @IsTest class: Run class, Bench class, Coverage. Above a class that holds no tests: Mutate, and nothing else — mutation testing belongs on the code under test, not on the test. Results stream live into the standard IntelliJ test runner tree, with inline ✔ passed / ✖ failed markers and timings on each test method, return values, and coverage gutter bars in the editor. Bench class, Mutate and Debug are Pro, currently free.

Debugging and replay Pro The debugger is a native IntelliJ debug session, wired through LSP4IJ to nimbus dap: set line breakpoints in.cls/.trigger files — with conditions, hit counts, or as log points — then Debug a test. Step over/into/out, evaluate expressions in the console or as watches, inspect and edit variables, view the call stack, and break on caught/uncaught exceptions, all driven by the local runtime. Recorded traces can also be replayed — stepping forwards and backwards through a past run with no Apex re-executing — and so can an org debug log and an anonymous-Apex run. Replay is the debugger, so it carries the same gate; recording the trace, the run itself and the timeline do not. A default-off Use the legacy debugger setting falls back to the pre-DAP daemon bridge if needed.

Coverage delta. Run a coverage pass, then Set Coverage Baseline(Nimbus menu) to snapshot it. Toggle Coverage Delta overlays the change vs that baseline in the gutter — green for newly-covered lines, orange for regressions. The same overlay and commands ship in the VSCode extension.

You can also create a Nimbus Apex Test run configuration directly (Run → Edit Configurations) to run a glob pattern or an explicitClass.method list.

Performance Lens

Tick Record per-line evidence on a Nimbus Apex Test run configuration, then turn on Nimbus → Toggle Performance Lens. Lines the run reached carry a muted end-of-line reading of what they spent — executions, SOQL, DML and database time.

A line the run never reached shows nothing, and a project with no recording shows nothing anywhere. The lens never falls back to zeros: a line that ran and issued no queries and a line no test came near are different claims, and only the recording can tell them apart.

A recording run goes through the CLI rather than the resident daemon, so its test tree appears when the run finishes instead of filling in as tests complete, and coverage gutters are not refreshed by it. The console says so on every recording run. The same numbers are readable from a terminal with nimbus coverage lines.

Rename Field or Object

Right-click a *.field-meta.xml file or an object directory in the Project view, or open Nimbus → Metadata → Rename Custom Field or Object Everywhere…, and Nimbus plans the rename across Apex, SOQL, metadata XML, LWC, Aura and Visualforce before writing anything.

The preview dialog shows the same plan the CLI prints: edits grouped by kind, each one carrying the reason that occurrence was believed to mean your field, and a separate UNRESOLVED section listing every mention that could not be attributed. Those are never edited and never hidden. Apply writes the plan and refreshes the project tree.

This renames your source. It does not touch the org: after applying, deploy, and use Setup → Object Manager for the org-side rename that moves the data. It is also not wired into the IDE's own Refactor → Rename in this release — the explicit action is what can show the refusals honestly.

Tool Window

The Nimbus tool window (right dock) is four workspaces over fourteen panels. A workspace is a mode of work; the panels inside it are tabs.

  • Home — the runtime, the license and this project's setup: CLI install and update, runtime and database health, account state, and the actual Free/Pro boundary read from the installed CLI.
  • Verify — what a test run produces.
    • Tests — every discovered @IsTest class → method; double-click to jump to source, or run/debug the selection from the toolbar. A Run on selector sends the run to the local runtime, to an authorized org, or to both at once — Compare Pro, which runs the selection on both sides and reports a verdict per method.
    • Coverage — per-class line coverage from the last coverage-enabled run, with the baseline and delta actions.
    • History — past runs → classes → methods, with a Trends chart and run comparison.
    • Governor — per-method SOQL, DML, CPU and heap usage vs. limits from the last run.
  • Data — what this project's local database holds.
    • Schema — the local PostgreSQL tables, columns, and PK/FK relationships.
    • Workbench — the rows themselves, in an editable grid, with a SOQL box above it. See below.
    • Data Loader — a CSV rehearsed against local data, with triggers, flows and validation rules firing, before anything is sent to an org.
    • Org — what an authorized org contains, and pull any of it into this project.
    • Drift — what differs between this project's files and an org's.
    • Apex — an anonymous-Apex console, run locally, in an org, or both and diffed.
    • SOQL — a query console that also shows the PostgreSQL it translates to. With an org picked under Run on, a Tooling API checkbox puts the query to the org's Tooling API — ApexClass bodies, ApexLog, ApexTestResult, MetadataComponentDependency and the rest of the metadata a data query cannot see. A query whose object only exists there is routed there anyway, and the status line says which endpoint answered.
    • Events — every platform event and Change Data Capture event a local run publishes, as it happens.
    • Server — start nimbus serve on this machine without a terminal: a header saying where it listens, the connection snippets, every request it answers, and everything it prints.
  • ReleaseReleases: pick the org at the top (its kind is shown beside it, production in amber) and everything below belongs to it. Three steps follow: SOURCE — the project's package directories, only what differs from the org, or a committed release profile; CHECK — "Check with <org>", a nimbus release validate that changes nothing in the org; SHIP — "Deploy to <org>", enabled only while the newest receipt for that org is still deployable without re-running the tests. Below them, that org's receipts and the deploy queue.

A live preview keeps its own docked Nimbus App window rather than a tab here, so it can sit beside your source.

A graph button on the tool-window header opens the interactive dependency graph — also available from the Apex editor right-click menu and Nimbus → Show Dependency Graph.

Graph, trace, Trends, and run-diff visualizations open in embedded browser panels (JCEF), the same views shipped in the VSCode extension.

Data Workbench

The Workbench tab is the local database's rows in an editable grid: pick an object from the searchable list, page through its rows, sort by clicking a header, filter with the search box, and edit a cell in place — Enter commits, Escape reverts.

A cell edit is not a SQL update. Nimbus runs it as Apex DML on the same interpreter a test uses, so triggers fire, before-save flows run, and a validation rule that would have rejected the change rejects it here too, with the platform's own message. Each write is a single DML statement, so a refusal leaves the row exactly as it was and the grid reverts to it. Add Row and Delete Selected follow the same rule; deleting asks first and names what is not affected.

Save as Fixture… turns the rows in view — or just the selected ones — into an @IsTest Apex class beside your other classes: the same artifact nimbus fixture writes, and it opens in the editor once written. Lookup fields keep the Ids they have now, so they resolve on the branch they were captured from.

The header carries a branch control over the nimbus data branch family: switch the whole panel onto another copy of the local data, or create one from the current branch. A branch another nimbus process is mid-run on is reported as in use rather than as a failure — nimbus never severs somebody else's run. Switching is only offered when the project uses nimbus's own embedded database.

Settings

Settings live under Settings → Tools → Nimbus, stored per project in .idea/nimbus.xml — except Salesforce file ownership, which is IDE-wide because the file-type table is.

FlagDefaultDescription
Nimbus binary path"nimbus"Path to the nimbus CLI binary. Left alone, Nimbus resolves one itself and prefers a copy you installed over the one it manages in ~/.nimbus/bin.
Install the Nimbus runtime automaticallytrueInstall a runtime into ~/.nimbus/bin when a project opens with none. Turn off for machines where an unattended download is not allowed.
Node.js path""Node executable, or its bin directory, for the npm and Vite children behind LWC and React previews. A GUI-launched IDE does not reliably inherit a version manager’s choice.
Read object definitions from org""Which org Nimbus asks to describe standard objects while syncing. Blank means nimbus resolves the org itself. Tests still run on your machine.
Parallel test workers4Number of parallel test workers. More than one is Pro — currently free.
Run the Nimbus Language ServertrueCompletion, hover, inlay hints, diagnostics via nimbus lsp. Disable to fall back to Salesforce’s stock Apex support.
Defer language intelligence to another Apex pluginfalseKeep the code lenses and the runtime, but let another plugin own completion, hover and diagnostics so they are not doubled.
Salesforce file ownershipAutomaticWhether Nimbus claims .cls/.trigger/.apex, Visualforce, Aura and .soql. Automatic defers to another Salesforce plugin, extension by extension, when one is installed. IDE-wide, not per project.
Use the legacy debuggerfalseFall back to the pre-DAP daemon debug bridge instead of nimbus dap.
Collect coverage on test runsfalseOpt-in: coverage instrumentation slows large suites.
Show coverage gutter iconstrueShow covered/uncovered bars in the editor gutter.
Show coverage change since the baselinefalseOverlay the delta against the saved baseline instead of plain coverage.
Follow active Salesforce filetrueOpening or selecting recognized Salesforce source routes the matching Nimbus surface, without moving focus.
Reveal Nimbus App for UI sourcetrueWhether following UI source may show — never focus — the Nimbus App window. Off keeps target selection tracking with no reveal.
Check Apex on savetrueCheck the file for errors automatically on save.
Show inline method timing annotations after test runstruePer-method execution time at the declaration.
Show governor limit usage (SOQL/DML) inline after test runstruePer-method governor usage at the declaration.
Run tests when a test file is openedfalseAuto-run on open.
Run tests when a test file is savedfalseAuto-run on save.