Use Nimbus for the inner loop — the runs you trigger on every save, dozens of times an hour. Use sf apex run test where org execution is what you're actually asking about: the final validation before production, and anything that depends on org configuration Nimbus doesn't replicate. The two run the same @isTest classes from the same repo, so nothing has to be maintained twice.
What each one actually is
sf apex run test
The Salesforce CLI enqueues a test run in a real org and polls for the result. The org executes against real platform hardware, real org configuration, and real governor limits. Because it runs where your code will eventually live, its verdict is the authoritative one — and the same mechanism backs the test execution inside a deployment. The cost is structural: your changed code has to be in the org first, so a deploy precedes the run, and the run itself waits in the org's queue behind whatever else that org is doing.
nimbus test
Nimbus runs a complete Apex interpreter on your machine against an embedded PostgreSQL. SOQL is translated to real SQL, DML persists, triggers fire in order, flows run from your .flow-meta.xml files, and each test runs in an isolated transaction that is rolled back afterwards. It reads your existing sfdx-project.json and source in place. No org, no credentials, no network.
Feedback latency
This is the dimension that changes how the day feels. An org run is deploy time plus queue time plus execution time plus polling; the queue portion is outside your control and varies with what else the org is doing. A local run is execution only.
- Nimbus, single test: a typical Apex test completes in tens of milliseconds, SOQL and DML included.
- Nimbus, full suite: suites of thousands of tests finish in seconds. In published open-source suite runs, Nimbus completes 321/321 apex-recipes tests and 1351/1351 Nebula Logger tests in seconds.
- Org run: deploy the change, enqueue, wait for the queue, then poll for results. Execution time is only one part of it, and usually not the largest one.
The blog post running Apex tests with the Salesforce CLI walks through the flags in detail — test levels, --synchronous, --wait, and recovering a run with sf apex get test — rather than repeating them here.
Org dependency
sf apex run test needs an org to point at: a scratch org from your DevHub, a sandbox, or a developer edition — plus authentication for it, and source deployed into it. That's a reasonable requirement for a tool whose job is org execution, but it means the test loop inherits DevHub limits, sandbox refresh cycles, and org availability.
Nimbus needs none of it. It runs on a plane, on a laptop with no credentials configured, and on a CI runner that was never granted org access. See Nimbus vs scratch orgs for where that trade stops being free — full platform fidelity is exactly what you give up.
Debugging a failure
After an org run fails, you read what the run left behind: the failure message, the stack trace, and a debug log if you had the right trace flags set. The Apex Replay Debugger can step through that log after the fact.
Nimbus executes the test on your machine, so a debugger can attach to the live execution: real breakpoints, step in and over, inspect variables with full type information, in VS Code or IntelliJ. Details are on the debugger page, and the model difference is covered in Nimbus vs the Apex Replay Debugger.
Coverage
An org run with --code-coverage reports line coverage — that's what the platform measures, and it's the number the 75% deployment requirement is checked against. Nimbus measures line, method, and branch coverage locally during the same test run, and writes HTML, JSON, and Cobertura XML reports plus JUnit XML results.
Branch coverage is the part the org doesn't give you: a line can be covered while one side of its condition has never executed. See local Apex code coverage for the report formats and nimbus coverage diff for PR deltas.
CI
Running tests through sf apex run test in CI means the pipeline holds org credentials — a JWT key and connected app, or a scratch org pool provisioned per run — and every job is exposed to org availability and DevHub limits.
A Nimbus job needs a binary and your repo. The JUnit XML and Cobertura XML it emits are the formats your CI already understands, so the reporting plugs into GitHub Actions, GitLab, SonarQube, or Codecov unchanged. The CI setup page has ready pipeline configs.
What sf does that Nimbus does not replace
- The final org validation. Before production, the tests have to pass where the code will run, against real org configuration and real governor-limit accounting. Nimbus does not claim that verdict — it just wants to be the reason you rarely fail it. Nimbus builds this step into assured deploys: local gates first, then a real Salesforce check-only validation of the exact payload.
- Deployment itself. Metadata deploys, packaging, org authentication, and data commands are the Salesforce CLI's job, and stay that way.
- Org-configuration-dependent behaviour. Complex sharing rules, approval processes, and UI rendering need the platform. The comparison matrix is explicit about the gaps.
Both, in one toolchain
You don't have to choose a CLI. nimbus sf passes any current or future sf command through unchanged — arguments, interactive prompts, and exit codes preserved — so every Salesforce task can start with nimbus without losing anything sf can do. If you'd rather keep sf as the entry point, Nimbus installs as a native Salesforce CLI plugin.
# Inner loop — local, no org
nimbus test "InvoiceServiceTest.*"
# The org run, unchanged, through Nimbus
nimbus sf apex run test --tests InvoiceServiceTest --result-format human --wait 20
# Or the other way round: Nimbus as an sf plugin
sf plugins install @nimbus-solution/nimbus-sf-plugin
sf nimbus apex run testHow the loop ends up looking
- While editing:
nimbus test, or watch mode re-running affected tests on save. No deploy, no queue. - On the pull request: Nimbus runs the full suite as the merge gate, publishing JUnit and Cobertura XML.
- Before production: the org validates the exact payload — the step that was always the real gate, now the only place an org is required.
Try it against a suite you already run in an org
Point Nimbus at the same repo you run sf apex run test against and run the same test classes. What passes locally is what you no longer need an org round-trip for. What doesn't tells you precisely which tests depend on the platform — useful information either way.