ts-node RAM consumption

Amir B
Aspecto
Published in
3 min readOct 14, 2020

TL;DR — if you use ts-node or ts-node-dev and care about RAM usage, use --tranpileOnly or tsc directly to reduce it by X6.

Photo by Harrison Broadbent on Unsplash

It turns out that runningts-node-dev / ts-node is constantly consuming hundreds of megabytes of RAM even for small and simple applications. In development, it is usually not a big concern, but it can be if your application is running inside a docker container with limited resources (for example, with Docker Desktop on Mac which allocates by default only 2GB of RAM to all the containers in total).

TypeScript code should be transpiled to Javascript. This can be done before running the process (tsc) or in runtime (ts-node). The most efficient way is transpiling before running, however, this is very not developer-friendly as it takes forever.ts-node-devloads everything into memory, watches the changes the developer is making and transpiles the project fast on every change.

I encountered the issue while building a demo application to showcase our product at Aspecto. I run multiple typescript services with docker-compose, and begun to see arbitrary ts-node-dev processes exiting without even running the application with the message “Done in 79.06s”. This was due to a lack of memory - each typescript service was using ~600MB of RAM out of the total 2GB available for all containers.

After digging a bit, I found a few possible solutions and wanted to share them:

Run ts-node-dev with option --transpile-only

In my case, adding the --transpile-only option to ts-node-dev reduced the consumed RAM from ~600MB to ~170MB.

The price is that, well, the typescript code will only be transpiled, and typechecking will be skipped. Most modern IDEs (vscode, web storm), has built-in typescript IntelliSense which highlights errors, so for me, it was a fair price to pay.

If you use ts-node to run code in production which was already successfully compiled and tested in the CI, you can only benefit from setting this option.

Compile the code with tsc and monitor file changes with nodemon

Instead of using ts-node-dev which consumes a lot of memory, it is possible to compile the application directly with tsc and then run it from dist/build like this: node dist/index.js . For automatic reload on source file changes, nodemon / node-dev can be used. This is my “start” script in package.json:

This approach reduced the RAM on my service from ~600MB to ~95MB (but there is still a spike in RAM to 600Mb for few seconds while tsc is compiling).

Unlink the previous option, this approach WILL check for typescript errors and warnings, and the service will not start if errors exist in the code.

The price to pay here is a longer compilation time. In my setup, it’s about 10 seconds from saving the file until the service restarts.

Increase Docker Desktop Available RAM

This is the easiest fix. Just allocate more Memory to Docker Desktop by going to Preferences => Resources => Memory, and increase the value.

While it fixes the immediate problem, the containers will still consume a lot of memory, and if you have plenty of them, it might be a problem soon enough.

Also, changing the default configuration should be done by every user that wants to run the system with docker-compose, which introduces complexity in installation and usage.

Summary

  • If memory consumption is not an issue for you (most cases), just use ts-node in production and ts-node-dev in development.
  • If you care about memory, then you have a tradeoff between fast restart time after modifications but typechecking only in the IDE (set --transpileOnly), or have typechecking in compilation, but slower restart on each modification (directly use tsc and nodemon / node-dev )

--

--