Editor setup

Type-checked JavaScript in Neovim

  • Neovim
  • nvim-lspconfig + a language server

Neovim has an LSP client built in. Since Neovim 0.11, vim.lsp.config() and vim.lsp.enable() set up a server in a few lines, and the nvim-lspconfig plugin supplies ready-made configs named ts_ls (for typescript-language-server) and vtsls. Both servers wrap TypeScript's own tsserver, so the errors in a .js file are the ones tsc reports, given the same TypeScript and the same jsconfig.json.

Install one server globally with npm, enable it, and the rest comes from your project: tsserver finds the nearest jsconfig.json above each file, so checkJs, strict and the other options apply as they do on the command line.

At a glance

EditorNeovim
What to installnvim-lspconfig + a language server
What checks the codeNeovim's built-in LSP client talking to typescript-language-server (ts_ls) or vtsls, both of which run TypeScript's own server
Where its TypeScript comes fromDecided by the language server: typescript-language-server can use the workspace's TypeScript; vtsls uses its bundled copy unless told to use the workspace's
Readsjsconfig.json, tsconfig.json
How this page was checkedNot run in Neovim for this page. The configuration is from Neovim's documentation (:help lsp) and the nvim-lspconfig ts_ls and vtsls configs linked below; what the servers report comes from TypeScript's language service, which the site's tests run.

Enable a TypeScript language server

With nvim-lspconfig installed (it provides the server definitions), one line in init.lua starts ts_ls for JavaScript and TypeScript buffers. Install the server first: nvim-lspconfig's ts_ls config gives npm install -g typescript typescript-language-server, and its vtsls config gives npm install -g @vtsls/language-server.

init.lua
-- Neovim 0.11+, with nvim-lspconfig installed for its server definitions
vim.lsp.enable('ts_ls')

Use the project's TypeScript

The version matters because each TypeScript release adds and changes checks; the editor should run the version in your project's node_modules, which is what npm run lint runs. typescript-language-server reports where its TypeScript came from (the workspace, a configured tsserver.path, or its bundled copy), and the ts_ls config starts a project-local typescript-language-server from node_modules/.bin when there is one.

vtsls uses the TypeScript it bundles unless you set vtsls.autoUseWorkspaceTsdk, per its README:

init.lua
vim.lsp.config('vtsls', {
  settings = {
    -- use node_modules/typescript instead of the copy vtsls ships with
    vtsls = { autoUseWorkspaceTsdk = true },
  },
})
vim.lsp.enable('vtsls')

How the config is found

nvim-lspconfig decides the workspace root from lockfiles and .git, not from jsconfig.json. That is only the LSP workspace: inside it, TypeScript's server still looks for the nearest jsconfig.json or tsconfig.json above each file, so a project with several configs is checked with the right one per file.

What differs from tsc

Neovim shows the diagnostics for the buffers you open, through vim.diagnostic (configure how with vim.diagnostic.config()). Servers also pass on TypeScript's suggestions, such as unused names when noUnusedLocals is off and names marked @deprecated; tsc never prints those. Quick fixes come through code actions (the default gra mapping).

Make sure it matches tsc

Run npm run lint (or npx tsc -p jsconfig.json --pretty false) in a terminal, open one of the files it lists, and compare the codes. Errors in files you have not opened appear only in that output.

Gotchas

  • ts_ls and vtsls are alternatives; enabling both runs two servers and shows each error twice.
  • The nvim-lspconfig ts_ls notes say it needs a TypeScript version below 7 for now.

Sources

Last reviewed 20 October 2026.