zed icon indicating copy to clipboard operation
zed copied to clipboard

Typescript server is slow on Zed when compared to VSCode

Open baptisteArno opened this issue 1 year ago • 19 comments

Check for existing issues

  • [X] Completed

Describe the bug / provide steps to reproduce it

The coding experience in a large Typescript monorepo (https://github.com/baptisteArno/typebot.io) is still an issue for me even though it now uses the vtsls, I still don't get the same speed as VSCode or even NeoVim (with vtsls lsp)

I'm just helpless, what is doing Zed that could cause this code error refresh so slow?

This also can be linked with:

  • https://github.com/zed-industries/zed/issues/18621

Environment

Zed: v0.156.0 (Zed Preview) OS: macOS 15.0.0 Memory: 16 GiB Architecture: aarch64

If applicable, add mockups / screenshots to help explain present your vision of the feature

VSCode:

https://github.com/user-attachments/assets/82b329fc-e36d-4dca-ad89-9b8091198839

Zed:

https://github.com/user-attachments/assets/df83d644-848d-45e6-9da1-ce6ddf824030

If applicable, attach your Zed.log file to this issue.

No response

baptisteArno avatar Oct 03 '24 15:10 baptisteArno

Could you also record a comparison with Neovim + VTSLS? VSC uses tsserver directly.

osiewicz avatar Oct 03 '24 17:10 osiewicz

https://github.com/user-attachments/assets/265ac38b-45e9-41c8-90fd-4b8e4ed68321

LazyVim distro with that lsp config override:

return {
  "neovim/nvim-lspconfig",
  opts = function(_, opts)
    opts.inlay_hints.enabled = false
    opts.servers.vtsls.settings.typescript.tsserver = {
      experimental = {
        enableProjectDiagnostics = false,
      },
    }

    opts.servers.vtsls.autoUseWorkspaceTsdk = true

    return opts
  end,
}

baptisteArno avatar Oct 03 '24 18:10 baptisteArno

But as you can see in Zed, I'm hovering my mouse over the sessionState variable and it gives me the proper type so I guess that the LSP is up to date but Zed decides not to update the diagnostic overlay directly?

baptisteArno avatar Oct 03 '24 18:10 baptisteArno

Same issue here, I'm running zed on fedora linux

juanmarin-co avatar Oct 24 '24 17:10 juanmarin-co

Been facing the same issue for the past few months. The only workaround right now is to restart the LSPs once in a while.

chungweileong94 avatar Nov 07 '24 09:11 chungweileong94

I found this PR from vtsls. It seems Electron came with an unofficial Node version that came with pointer compression, which is also what VSCode is using. I played with it for a while. It does seem like the memory is relatively smaller, but I haven't really started coding with it.

https://github.com/user-attachments/assets/00178251-7b3d-4d2a-996c-e35023840996

[UPDATE] After trying to open files from at least 10 different sub-repos, I can see the tsserver memory usage cut nearly half, from 3GB~ down to 1GB~.

chungweileong94 avatar Nov 07 '24 14:11 chungweileong94

I'm not sure if this is good enough to reproduce the problem, but if you have a really large monorepo, try opening multiple files from multiple different sub-repos, and you will start noticing that the node memory usage will start to build up, which I think tsserver will likely get slow and unusable like the issue described.

chungweileong94 avatar Nov 07 '24 14:11 chungweileong94

Also happening for me

wesguirra avatar Feb 17 '25 18:02 wesguirra

I wanted to give it another shot. New Zed install, dumb example but it's like this everywhere:

https://github.com/user-attachments/assets/f2c8aa00-a8b2-41ed-9e7b-73024fbb0c0b

Compared with Cursor (or VSCode):

https://github.com/user-attachments/assets/5b218320-9e26-4960-8e15-8b3a5a3bdf61

Guys... How is it not a priority? The reproduction is dead simple. Too bad Zed is so fast but the LSP refresh is total garbage??

@osiewicz, did you manage to reproduce? Clone this https://github.com/baptisteArno/typebot.io (or any non-toy typescript project)

baptisteArno avatar Feb 23 '25 15:02 baptisteArno

Further discussion / debugging here: https://discord.com/channels/869392257814519848/873293828805771284/1343251336778743940

baptisteArno avatar Feb 23 '25 19:02 baptisteArno

ok, i found what was wrong in my case, zed's default memory limit is different for vtsls and typescript-language-server you can test if it's works for your case by setting lsp settings to:

"lsp": {
  "vtsls": {
      "settings": {
        "tsserver": {
          "maxTsServerMemory": 8092
        }
      }
    }
}

I'd offer that we set vtsls memory limit same as typescript-language-server https://github.com/zed-industries/zed/pull/25442

aevsai avatar Feb 24 '25 07:02 aevsai

ok, i found what was wrong in my case, zed's default memory limit is different for vtsls and typescript-language-server you can test if it's works for your case by setting lsp settings to:

"lsp": {
  "vtsls": {
      "settings": {
        "tsserver": {
          "maxTsServerMemory": 8092
        }
      }
    }
}

I'd offer that we set vtsls memory limit same as typescript-language-server #25442

Interesting, I always though that Zed default the vtsls max memory to 8092, but it doesn't seems to be the case according to your PR🤔 https://zed.dev/docs/languages/typescript#large-projects

[EDIT] Actually, I think the max memory is set correctly for vtsls, which is 8092 (https://github.com/zed-industries/zed/pull/17354/files). You probably got confuse by the Zed LSP settings hierarchy.

chungweileong94 avatar Feb 24 '25 08:02 chungweileong94

then

ok, i found what was wrong in my case, zed's default memory limit is different for vtsls and typescript-language-server you can test if it's works for your case by setting lsp settings to:

"lsp": {
  "vtsls": {
      "settings": {
        "tsserver": {
          "maxTsServerMemory": 8092
        }
      }
    }
}

I'd offer that we set vtsls memory limit same as typescript-language-server #25442

Interesting, I always though that Zed default the vtsls max memory to 8092, but it doesn't seems to be the case according to your PR🤔 https://zed.dev/docs/languages/typescript#large-projects

[EDIT] Actually, I think the max memory is set correctly for vtsls, which is 8092 (https://github.com/zed-industries/zed/pull/17354/files). You probably got confuse by the Zed LSP settings hierarchy.

then i actually not sure what and where went wrong 😵‍💫, bc i tested locally and performance on my repo become great after i edited settings. And that worked in both cases: when it set as defaults in zed and when i edit settings

aevsai avatar Feb 24 '25 08:02 aevsai

Based on my experience, I don't think memory is the problem here, where one of my monorepos(about 20+ sub-repos) always uses about 5GB at max, which it doesn't even hit the VTSL server max memory. And there is no problem with inspect types, go to definition, etc., not until I start changing some code, where the LSP will slowly fall apart.

chungweileong94 avatar Feb 24 '25 08:02 chungweileong94

Memory is not the issue. On nvim with vtsls with default memory limit (4Go), there is no issue.

baptisteArno avatar Feb 24 '25 09:02 baptisteArno

Memory is not the issue. On nvim with vtsls with default memory limit (4Go), there is no issue.

maybe my issue was not related from the beginning 😅

aevsai avatar Feb 24 '25 10:02 aevsai

I believe its related, on my case type changes takes much longer to take effect in other packages in a small monorepo compared to vscode. If the change is in something like generated code (prisma), it takes forever, restarting tsserver/zed works but it becomes a headache very fast.

It doesnt happen in vscode, which could be be because vscode's watchers are more aggressive? Its a wild guess but my system watcher limit gets maxed out only when vscode is running alongside my programs, not with zed.

laneme avatar May 02 '25 05:05 laneme

maybe it's a good time to consider whether just looking into supporting typescript's upcoming go version? The VSCode extension already supports this

https://github.com/microsoft/typescript-go?tab=readme-ov-file#running-lsp-prototype

jpike88 avatar May 04 '25 05:05 jpike88

I experience the same issue in larger codebase. The autocompletion for component props or component lookup takes more than 5 seconds to show on CTRL+Space

dohomi avatar May 14 '25 00:05 dohomi

maybe it's a good time to consider whether just looking into supporting typescript's upcoming go version? The VSCode extension already supports this

https://github.com/microsoft/typescript-go?tab=readme-ov-file#running-lsp-prototype

I guess, zed should should focus and improve the LSP stuff, instead of AI bubble, it's clear that zed still not compete with even the Neovim.

PATEL7VISHAL avatar May 21 '25 18:05 PATEL7VISHAL

We now have an extension for tsgo: https://github.com/zed-extensions/tsgo#

osiewicz avatar May 22 '25 19:05 osiewicz

I have a fairly large project (about a gigabyte of ts files) and until recently zed was doing great, even faster than vscode. However, the speed of ts degraded over time to the point where it eventually became slower to register for type changes than vscode, and later it became so slow that it became annoying.

Perhaps my problem is a bit different - first of all everything was fine initially, secondly increasing memory for vtsls, as well as switching to tsgo did not give any noticeable changes in speed

Akiyamka avatar Jun 24 '25 15:06 Akiyamka

I use Zed on a quite large monorepo project. Unfortunately, I can also experience performance issues with TypeScript code navigation. The major pain point for me is the "Find All References" command. Sometimes it freezes for so long that I need to restart the editor. It works OK after the restart, but then as time goes by it starts to freeze again and again. The autocomplete snappiness doesn't feel great either.

I must admit that Zed is run on a rather outdated MacBook Pro in my case. It's not a vintage one though. And the main thing is that I don't experience these issues in VS Code (which is much more bloated than Zed in my opinion) on the same machine.

I use vtsls for TypeScript (and JavaScript). I also tried to adjust the memory dedicated to the TypeScript server (up to 10 GB), but it didn't help. The extra setting that I have configured for TypeScript is source.fixAll.eslint. Here's the part of my configuration related to JavaScript and TypeScript:

{
  "languages": {
    "JavaScript": {
      "code_actions_on_format": {
        "source.fixAll.eslint": true
      },
      "language_servers": ["vtsls"]
    },
    "TSX": {
      "code_actions_on_format": {
        "source.fixAll.eslint": true
      }
    },
    "TypeScript": {
      "code_actions_on_format": {
        "source.fixAll.eslint": true
      }
    },
  },
  "lsp": {
    "vtsls": {
      "settings": {
        "javascript": { "tsserver": { "maxTsServerMemory": 10240 } },
        "typescript": { "tsserver": { "maxTsServerMemory": 10240 } }
      }
    }
  }
}

It feels to me that the problem has something to do with the binding between the editor and the LSP.

grushetsky avatar Jul 04 '25 15:07 grushetsky

I think the zed docs are wrong, or rather show settings that don't work.

when i switch from:

{
  "lsp": {
    "vtsls": {
      "settings": {
        // For TypeScript:
        "typescript": { "tsserver": { "maxTsServerMemory": 16184 } },
        // For JavaScript:
        "javascript": { "tsserver": { "maxTsServerMemory": 16184 } }
      }
    }
  }
}

to

{
  "lsp": {
    "vtsls": {
      "settings": {
        "tsserver": {
          "maxTsServerMemory": 16184
        }
      }
    }
}

it's a complete night and day difference. i haven't dug in, but have to assume that the above settings formulation doesn't actually stick.

thempatel avatar Jul 25 '25 18:07 thempatel

I think the zed docs are wrong, or rather show settings that don't work.

when i switch from:

{ "lsp": { "vtsls": { "settings": { // For TypeScript: "typescript": { "tsserver": { "maxTsServerMemory": 16184 } }, // For JavaScript: "javascript": { "tsserver": { "maxTsServerMemory": 16184 } } } } } } to

{ "lsp": { "vtsls": { "settings": { "tsserver": { "maxTsServerMemory": 16184 } } } } it's a complete night and day difference. i haven't dug in, but have to assume that the above settings formulation doesn't actually stick.

whoever is reading this can ignore my previous comment, i think it was likely a fluke. when i look at the top output, i can see that max-old-space-size is correctly set to the value defined in settings, and that there are two tsserver processes (1 for js and ts each).

thempatel avatar Jul 27 '25 23:07 thempatel

This vastly improved my speeds:

Update tsconfig's "include array" so that it is from the perspective of the root of the project, not the folder it is in.

Example:

  "include": [
    "frontend/**/*.ts",
    "frontend/**/*.tsx",
    "frontend/webpack.config.js",
    "frontend/tailwind.config.js",
  ],

skylovescoffee avatar Aug 30 '25 06:08 skylovescoffee

This vastly improved my speeds:

Update tsconfig's "include array" so that it is from the perspective of the root of the project, not the folder it is in.

Example:

  "include": [
    "frontend/**/*.ts",
    "frontend/**/*.tsx",
    "frontend/webpack.config.js",
    "frontend/tailwind.config.js",
  ],

Tried this for a couple of days. It does not help. Also my observation is that the LSP's message at the bottom of Zed is quick to print. I think the problem is that the popup, with actions/sugeestions, is waiting for something to complete making it feel slow.

DarkFluid avatar Sep 23 '25 22:09 DarkFluid

Solution for TypeScript LSP Performance Issues in Zed

I was experiencing significant TypeScript lag in Zed on my macbook air when working with a large monorepo. The main issue was that when the AI agent modified code, tsserver couldn't keep up with the analysis, leading to memory leaks and slow LSP performance.

Solution: Using Bun runtime for typescript-language-server

This dramatically improved performance and significantly reduced RAM usage.

Step-by-step instructions:

  1. Install Bun:

    curl -fsSL https://bun.sh/install | bash
    
  2. Get Bun path:

    which bun
    
  3. Install typescript-language-server globally via Bun:

    bun add -g typescript-language-server
    
  4. Configure Zed (settings.json):

    {
      "languages": {
        "TSX": {
          "language_servers": ["typescript-language-server", "!vtsls"],
          "formatter": "prettier",
          "code_actions_on_format": {
            "source.addMissingImports.ts": true,
            "source.organizeImports": false,
            "source.fixAll.eslint": true
          }
        },
        "TypeScript": {
          "language_servers": ["typescript-language-server", "!vtsls"],
          "formatter": "prettier",
          "code_actions_on_format": {
            "source.addMissingImports.ts": true,
            "source.removeUnusedImports": true,
            "source.organizeImports": false,
            "source.fixAll.eslint": true
          }
        }
      },
      "lsp": {
        "typescript-language-server": {
          "binary": {
            "path": "/Users/<USER>/.bun/bin/bun",
            "arguments": [
              "--bun",
              "/Users/<USER>/.bun/bin/typescript-language-server",
              "--stdio"
            ]
          }
        }
      }
    }
    

Caveats and workarounds:

  • Downside: Auto-import doesn't appear in the context menu
  • Workaround: Use Ctrl + Space for autocomplete or set "source.addMissingImports.ts": true for automatic imports on format

Now Zed performs much better in large monorepositories. I'm looking forward to the final typescript-go release, but this solution effectively addresses the performance issues in the meantime.

qwexs avatar Oct 13 '25 08:10 qwexs

sorry to say but above solution still seems to be not work for me, feels like default vtsls perform faster then above solution for large project as well, so still zed both typescript LSPs are still slow and feels leggy. Neovim typescript LSPs still faster.

PATEL7VISHAL avatar Oct 13 '25 08:10 PATEL7VISHAL

Solution: Using Bun runtime for typescript-language-server

This dramatically improved performance and significantly reduced RAM usage.

That one of the things that I tried awhile back, unfortunately using bun runtime actually generates more memory usage to me. Probably because of my codebase sizes.

So far the best result that gets is from using NodeJS instance from electron, but tedious to setup.

But there's nothing Zed can do other than waiting tsgo to be released.

chungweileong94 avatar Oct 13 '25 12:10 chungweileong94