TypeStrong/ts-node

Should I use it in production?

aayushkapoor206 opened this issue Β· 32 comments

I couldn't find any mention about it in the readme

No, not really. In production you'd want to only be in transpile mode (you should have already type checked). If someone wants to contribute some PRs for this functionality, we can get it in. Otherwise I'd wait for #44.

So @blakeembrey, can we now use it in production? As in

$ ts-node -F server.ts

I currently do tsc && node build/server.js, but the very succinctness and beauty of the above is totally worth it if I'll get no significant overheads over the second option.

Definitely your choice, go ahead πŸ˜„ There's no heavy overheads.

using ts-node -F . to run ts code missing metadata. reflect-metadata can't get field's type.

tsc && node . is OK

That make sense to me. Fast mode isn’t using type information, it’s just plain transpiling files on the fly. That’s not equivalent to tsc. Use the regular mode that is if you want type information. It’s a good point though and I can document that.

So, should I use in production?
ts-node . or tsc && node .

That's not something I can tell you. I can tell you that loading type information has a larger overhead, but it shouldn't impact performance (only memory once started).

Hey, FYI there still no documentation mention about the --fast or -F option. I just found it here. That's something worth adding to the readme along with a basic intro about what it does, if its still a valid option. I saw somewhere that it's enabled by default, is that true?

leotm commented

The release note mentions use --type-check for type checking behaviour, but its not mentioned again in the docs?

That’s because it was three major releases ago and the behaviour was reverted. It confused other people to not type check by default.

So the --transpileOnly works similar to previous --fast?

The same, yes.

So the --transpileOnly works similar to previous --fast?

Except its --transpile-only or -T

So, the summary of this thread is that "If i use ts-node server.ts in production, that is completely okay, as it is transpile only mode by default so dont need to pass --fast or --transpile-only flags.

correct me if something is missed.

So, the summary of this thread is that "If i use ts-node server.ts in production, that is completely okay, as it is transpile only mode by default so dont need to pass --fast or --transpile-only flags.

correct me if something is missed.

https://github.com/TypeStrong/ts-node#cli-and-programmatic-options says --transpile-only is false by default.

That’s correct. There was a period of time it was the default for performance reasons, but I received a lot of issues because it differed from typescript. You’ll need the flag or use the register file for it.

So the new summary of this thread is:

Go ahead and use ts-node in production; just set the --transpile-only flag.

Is that correct?

For anyone wondering how to pass in --transpile-only when requiring ts-node in a node call:

node -r ts-node/register/transpile-only src/index.ts

A little bit about transpileModule for the curious: https://github.com/microsoft/TypeScript/blob/master/src/services/transpile.ts#L17

In this mode, files are only transpiled without typechecking, greatly improving compilation speed. All this means is your console won't spit out TypeError warnings, but if you use VSCode you already get realtime warnings within the editor.

A user early in this thread said that reflect-metadata broke when using this in -T (at the time it was -F) mode. Is this still the case?

EDIT: It looks like this is still a problem according to #873

Yes, it’s not possible to get type information if your compiling without type information - which is what transpile only does.

I haven't seen any issues with sequelize-typescript – the current limitation may be specifically limited to the enum issue described in #873.

iiian commented

General query to this thread: Out of curiosity, what are the arguments for not using ts-node in production ? Is there a good, important reason?

@iiian I don't think there is one, as long as you pass the correct flag disabling type checking. The one mentioned above may be outdated and I recommend you to check manual for the exact name.

rrrix commented

Thumbs up if you're using ts-node in Production 😁

I am! πŸ‘

Sad face if you're too afraid 😒

Thumbs up and sad face because going to production and afraid

Thumbs up and sad face because going to production and afraid

Same! Been migrating a node.js app to typescript. I tried running "tsc && node dist/app.js" but kept getting cannot find module from a local ts file. This is the only resort unfortunately, fingers crossed.

I deployed the other day and broke things :/ I build a video editor https://storycreatorapp.com and recently migrated my node server to TypeScript.

The reason it broke is that I was trying to get it to work with pm2.

Are you guys running your node.js servers in production without https://pm2.keymetrics.io/? That seems scary to me.

Has anyone gotten it to work with pm2?

@bluematter you'll probably have better luck in the TypeScript Community Discord: https://discord.com/invite/typescript
It's very active, with plenty of people answering questions. Be prepared to ask your question with sufficient detail, and you should get a good answer.

It's an old topic but I want to share a code I wrote for testing purposes and its results. I wrote a simple function that calculates Fibonacci numbers for the code that uses both CPU and memory, and I print out the time required for the calculation and how much RAM it uses in that time, you can try it yourself. I am attaching the results below.

It seems that there is not much difference in speed but there is a difference in memory usage and "--transpile-only" doesn't change much about it

  • node app.js => 5.33MB Ram, 15.48 sec
  • ts-node app.ts => 100.63MB Ram, 15.54 sec
  • ts-node app.ts --transpile-only => 95.79MB Ram, 15.67 sec
let operations = 0;

// Fibonacci calculation function
function fibonacci(num: number): number {
    operations++;
    if (num <= 1) return 1;
    return fibonacci(num - 1) + fibonacci(num - 2);
}

// Start the time
const start = Date.now();

// You can set the parameter value depending on your hardware capacity.
// Be careful, this number exponentially increases the number of operations required
const fibNum = fibonacci(45);

// Calculate elapsed time
const elapsedSeconds = (Date.now() - start) / 1000;
const used = process.memoryUsage().heapUsed / 1024 / 1024;

console.log(`Time elapsed: ${elapsedSeconds} seconds`);
console.log(`Memory used: ${Math.round(used * 100) / 100} MB`);

It seems that there is not much difference in speed but there is a difference in memory usage and "--transpile-only" doesn't change much about it

We actually just faced an outage because of this as the max size of the heap in Node.js by default is 512mb. We were getting very close to it before, but we moved some packages around in our monorepo and that made ts-node hit that limit. Thankfully we didn't have --transpile-only set, so setting it did alleviate the issue slightly, but the amount of memory being used is still absurdly close to the limit.

Obviously we can increase the limit using --max-old-space-size, but another more demanding service is running with less memory (it's only using node) so we do want to make sure ts-node is our only option before we increase the size of the memory footprint.

@leventkaragol thanks for sharing your benchmark and results.
I've pasted your code into src/index.ts and ran it on my machine (m1 mac) with both node 18 (v18.17.1) and node 20 (v20.10.0) and I noticed some differences in the results:

node 18

  • node dist/index.js => 4.92 MB and 16.321 seconds
  • npx ts-node src/index.ts => 102.26 MB and 15.538 seconds
  • npx ts-node --transpile-only src/index.ts => 31.21 MB and 15.547 seconds

node 20

  • node dist/index.js => 3.37 MB and 16.284 seconds
  • npx ts-node src/index.ts => 109.67 MB and 15.646 seconds
  • npx ts-node --transpile-only src/index.ts => 23.77 MB and 15.529 seconds

Tests report the memory footprint is reduced significantly when using --transpile-only both on node 18 and node 20.

However, the most interesting result that tests report comes from Node20, when switching from CommonJS to ESM (by adding "type": "module" in package.json).

You'll have to ditch the ts-node executable and replace it with node --loader ts-node/esm because of this #1997 , and cope with a warning that's there since node14 (but I think there's a newer flag or api to get rid of that)

node 20 ESM

  • node dist/index.js => 3.92 MB and 16.569 seconds
  • node --loader ts-node/esm src/index.ts => 3.63 MB and 16.46 seconds
  • node --loader ts-node/esm/transpile-only src/index.ts => 3.62 MB and 16.599 seconds

So, for this last test, it looks like the memory usage is not affected at all by the ts-node/esm loader.

Hope this can be helpful to people researching on the same topic.