462

I'm trying to run a dev server with TypeScript and an Angular application without transpiling ts files every time.

What I found is that I can run .ts files with ts-node but I want also to watch .ts files and reload my app/server. An example of this is the command gulp watch.

SecretAgentMan
  • 2,856
  • 7
  • 21
  • 41
Ieltxu Algañarás
  • 4,654
  • 3
  • 10
  • 7

21 Answers21

957

You can now simply npm install --save-dev ts-node nodemon and then run nodemon with a .ts file and it will Just Work:

nodemon app.ts

Previous versions:

I was struggling with the same thing for my development environment until I noticed that nodemon's API allows us to change its default behaviour in order to execute a custom command.

For example, for the most recent version of nodemon:

nodemon --watch "src/**" --ext "ts,json" --ignore "src/**/*.spec.ts" --exec "ts-node src/index.ts"

Or create a nodemon.json file with the following content:

{
  "watch": ["src"],
  "ext": "ts,json",
  "ignore": ["src/**/*.spec.ts"],
  "exec": "ts-node ./src/index.ts"      // or "npx ts-node src/index.ts"
}

and then run nodemon with no arguments.

By virtue of doing this, you'll be able to live-reload a ts-node process without having to worry about the underlying implementation.


And with even older versions of nodemon:

nodemon --watch 'src/**/*.ts' --ignore 'src/**/*.spec.ts' --exec 'ts-node' src/index.ts

Or even better: externalize nodemon's config to a nodemon.json file with the following content, and then just run nodemon, as Sandokan suggested:

{
  "watch": ["src/**/*.ts"],
  "ignore": ["src/**/*.spec.ts"],
  "exec": "ts-node ./index.ts"
}
starball
  • 20,030
  • 7
  • 43
  • 238
HeberLZ
  • 12,715
  • 4
  • 22
  • 24
  • 2
    if `index.ts` is a express instance, how can i kill it and restart – hjl Aug 23 '16 at 08:41
  • @elaijuh in theory this same command should do the trick, when nodemon is configured to execute a custom command (in this case ts-node) instead of the default node command, it will shut down the process and start a new one each time it finds a change on the watch expression minus the ignore expression :) – HeberLZ Aug 24 '16 at 08:21
  • 30
    you can also create a nodemon.json file with all the mentioned options in it like this: `{ "watch": ["src/**/*.ts"], "ignore": ["src/**/*.spec.ts"], "exec": "ts-node ./app-server.ts" }` and just type `nodemon` – Sandokan El Cojo Oct 27 '16 at 08:27
  • 4
    I made the mistake of adding `./` before the folder names and it broke. This worked for me: `{ "verbose": true, "watch": ["server/**/*.ts"], "ext": "ts js json", "ignore": ["server/**/*.spec.ts"], "exec": "ts-node index.ts" }`. And command line: `nodemon --watch server/**/*.ts --ignore server/**/*.spec.ts --verbose --exec ts-node index.ts` – Adrian Moisa Mar 11 '17 at 10:26
  • 4
    I would just like mention, that you also have to set the `ext` in the config file, so its look for ts changes. My config file look like this: `{ "watch": ["src/**/*.ts"], "ignore": ["src/**/*.spec.ts"], "ext": "ts js json", "_exec": "node dist/startup.js", "exec": "ts-node src/startup.ts" }` – Lasse D. Slot Mar 28 '17 at 08:45
  • For windows users you will need to make the exec command an array for pathing issues: `"exec": "ts-node ./src/index.ts"` becomes => `"exec": ["ts-node", "src/index.ts"]` – Armeen Moon Sep 10 '17 at 18:34
  • I'm using grunt-ts with nodemon, what is the difference?.. Should I use grunt-ts or ts-node..? – Melroy van den Berg May 15 '18 at 18:15
  • @HeberLZ `nomdemon.json` should be `nodemon.json`, i think – Simon Meusel Jun 02 '18 at 17:23
  • nodemon.json file makes things easier, thanks for sharing. – darul75 Feb 15 '19 at 11:16
  • still the best practice? – SuperUberDuper Jun 07 '19 at 16:21
  • I am getting (function (exports, require, module, __filename, __dirname) { import * as express from 'express'; SyntaxError: Unexpected token * looks like it is not taking es6 code, how can I add es6? – Pritam Bohra Aug 06 '19 at 14:32
  • I have the same config as you but it only refreshes when i update index.ts and not any of the javascript files in src. – Batman Aug 19 '19 at 17:44
  • `nodemon` and t`s-node` will become very slow if the typescript project goes too big. `ts-node-dev` can not reload when a ts file only contains interfaces got changes. – Ling Oct 17 '19 at 07:50
  • 2
    On Windows machines, DON'T use single quotes in your package.json. Replacing those with `\"` makes the script run fine: `"nodemon --watch \"./src/**/*.ts\" -r dotenv/config --exec \"ts-node\" src/index.ts"` – TJBlackman Mar 11 '20 at 15:27
  • with first `nodemon.json` version I had to run `nodemon -e ts`, now with updated config file this option is not required. – humkins Mar 17 '20 at 14:07
  • I've tried running `npm install --save-dev ts-node nodemon` then `nodemon src/index.ts` but still get the error: `ts-node is not recognized as an internal or external command...`. Is there a reason it's still not? – m3.b May 20 '22 at 18:19
  • This doesn't seem to work for me out of the box. Fortunately, nodemon can be easily configured. Try `npx nodemon -h` for a list of options. This is what worked for me: `nodemon --watch src --ext ts,js` – Mike Jul 19 '23 at 01:14
292

I've dumped nodemon and ts-node in favor of a much better alternative, ts-node-dev https://github.com/whitecolor/ts-node-dev

Just run ts-node-dev src/index.ts

[EDIT] Since I wrote this answer, nodemon has improved a lot, the required config is much lighter now and performance is much better. I currently use both (on different projects, obviously), and am satisfied with both.

Mikael Couzic
  • 12,283
  • 5
  • 22
  • 16
  • 26
    And why is this better? – Deilan May 31 '18 at 20:18
  • 61
    It's faster, and automatically detects which files need to be watched, no config needed. – Mikael Couzic Jun 05 '18 at 08:36
  • 7
    This is the best (if not the only) option for ts-node, especially for larger projects. It doesn't recompile all files from scratch, but does an incremental compilation, like `tsc --watch`. – Angelos Pikoulas Mar 10 '19 at 22:35
  • for me, I have to add "ts-node-dev": "ts-node-dev" in the script array of package.json and then do npm run ts-node-dev server.ts to make it work – bormat May 15 '19 at 12:56
  • 5
    in my case, this literally 10 times faster than `nodemon` with `ts-node`. Thank you! – Florian Ludewig Jan 16 '20 at 18:06
  • 4
    So I literally just have `"start": "ts-node-dev src"`. No need for babel, nodemon, or any of the config that comes with it. Everything is handled for you. – JMadelaine Apr 15 '20 at 04:45
  • 3
    Unfortunately, no longer maintained and stopped working for me. Had to revert to `nodemon`. – Nikola Mihajlović Apr 20 '20 at 22:35
  • 2
    It is very fast. I just added it as follows: "start": "ts-node-dev --respawn --transpileOnly src/index.ts" – varad_s Apr 22 '20 at 14:23
  • 1
    This litereally made me went from 5-6 seconds to reload to ~0.5 seconds, changed my whole experience – Mauro Insacco Jul 07 '20 at 07:09
  • very fast and seems to work really well, however it seems to ignore all environment variables and has some hidden behavior handling env for you. – Bejasc Aug 13 '20 at 09:07
  • 1
    nodemon + ts-node without config worked for me. Simple command: `nodemon src/index.ts` – Rafael Pizao Sep 09 '20 at 21:24
  • fast is an understatement for this... thanks a lot bro... I was using the shi**y nodemon for so long – Saksham Khurana May 23 '21 at 08:05
  • the debugger wont attach with ts-node-dev, is there a fix? – Ali80 May 25 '21 at 18:41
  • 1
    Somethings wrong with this package, I highly advise that no one downloads this globally. When I installed it globally, I could no longer run react native with expo. Something like that shouldn't happen. – ICW Jun 30 '21 at 18:10
  • 13
    `ts-node-dev` is a nice idea but it has a *lot* of problems. It's really just not reliable enough for real-world use. The maintainer seems underequipped to deal with the issues, unfortunately. Back to `nodemon` I go... – forresthopkinsa Jul 23 '21 at 20:37
  • Went from nodemon to ts-node-dev on Windows, as a reload after file changes always crashed the ts-node process, with "port already in use". – ThomasH Jul 29 '21 at 10:14
  • Its better because works like nodemon and has others setup. Theoretically, is faster too. – Akostha Oct 05 '21 at 14:28
  • 6
    I used this, but eventually I realized it's having major issues with picking up changed files. Saving a file, process is restarted, but somehow old files are still being used. Super annoying. Not an issue with accepted answer.‍♂️ – Svish Nov 04 '21 at 00:30
76

Here's an alternative to the HeberLZ's answer, using npm scripts.

My package.json:

  "scripts": {
    "watch": "nodemon -e ts -w ./src -x npm run watch:serve",
    "watch:serve": "ts-node --inspect src/index.ts"
  },
  • -e flag sets the extenstions to look for,
  • -w sets the watched directory,
  • -x executes the script.

--inspect in the watch:serve script is actually a node.js flag, it just enables debugging protocol.

im.pankratov
  • 1,768
  • 1
  • 19
  • 19
  • 2
    Also be sure to have typescript locally installed for the project. Otherwise the error you might get is not very clear. – Aranir Jul 05 '17 at 10:46
  • I think it should be `ts-node --inspect -- src/index.ts` now due to [this](https://github.com/TypeStrong/ts-node/issues/552). – bluenote10 Apr 01 '18 at 22:19
  • 1
    This approach seems to generate considerable superfluous output. – Freewalker Jun 28 '19 at 21:12
  • `-e ts -w ./src` did the trick for me - this worked with a loopback4 CLI generated project – Jonathan Cardoz Jan 06 '20 at 08:45
  • I get `Error: Unknown or unexpected option: --inspect`. It seems that `ts-node` does not have the flag. – Timo Feb 19 '22 at 11:04
  • 1
    @Timo looks like starting from [v5.0.0](https://github.com/TypeStrong/ts-node/releases/tag/v5.0.0) for advanced node.js flags (like `--inspect` in this case) you need to run ts-node as `node -r ts-node/register` command. – im.pankratov Feb 19 '22 at 11:30
  • I also had to use the `--legacy-watch` flag to make autoreload possible. Any idea why? – Timo Feb 19 '22 at 18:36
72

Summary of options from other answers

Note that tsx (which uses ESBuild under the hood) and swc don't do type checking; this should be acceptable since most editors have type checking built-in, and type checking should still be part of your build process. You can also do type checking separately alongside your tests or as a pre-push hook via tsc --noEmit.

(Recommended) tsx

ⓘ TL;DR: fastest with minimal configuration

As of 2023-02-01, tsx seems to be the best combination of speed and minimal configuration:

  1. Install tsx

    npm install --save-dev tsx
    
  2. Update your package.json, e.g.

    "scripts: {
      "dev": "tsx watch src/index.ts",
    
  3. Run it

    npm run dev
    

    (Adjust these steps if you just want to install tsx globally and run it directly)

Alternative 1: nodemon/node-dev + ts-node + swc

ⓘ TL;DR: as fast as tsx but with more configuration

An alternative option that combines the reliability of nodemon/node-dev with the speed of ts-node-dev is to use ts-node with swc, a TypeScript-compatible transpiler implemented in Rust which is an "order of magnitude faster" than the TypeScript transpiler.

  1. Install nodemon or node-dev (whichever you prefer)

    • nodemon

      npm install --save-dev nodemon 
      
    • node-dev

      npm install --save-dev node-dev 
      
  2. Set up ts-node with swc integration

    https://github.com/TypeStrong/ts-node#swc-1

    1. Install necessary packages

      npm install --save-dev ts-node @swc/core @swc/helpers regenerator-runtime
      
    2. Add this to tsconfig.json

        "ts-node": {
          "swc": true
        }
      
  3. Run nodemon or node-dev, e.g

    nodemon --watch src src/index.ts
    

    or:

    node-dev src/index.ts
    

Alternative 2: nodemon/node-dev + ts-node transpileOnly

ⓘ TL;DR: fast, reliable

Here's an alternative that's slower than the previous option because it uses the standard TypeScript transpiler, but in my testing it's still faster than nodemon/node-dev + ts-node.

Basically it's the same as the previous option but without swc. It's faster than out-of-the-box ts-node by disabling type checking (see notes above regarding why this should be acceptable).

  1. Install nodemon/node-dev as above

  2. Install ts-node

    npm install --save-dev ts-node
    
  3. Modify your tsconfig.json to enable transpileOnly for ts-node

      "ts-node": {
        "transpileOnly": true
      }
    
  4. Call nodemon/node-dev as above

Alternative 3: nodemon + tsc --incremental

ⓘ TL;DR: fast, reliable, type checking, more finicky

This is nearly the same speed as the previous alternative. The only real advantage of this over the other options is that it does type checking.

In terms of downsides, it can be a bit more finicky; in my testing, I'm using dotenv to pick up my .env file for local development. But depending how your tsc build is configured in tsconfig.json, you may have to do some acrobatics to get it working.

But it's good to have options, so here it is:

  1. Install nodemon as above

    (It's possible that this may work with node-dev as well, but I didn't see an exec option for node-dev)

  2. Configure tsconfig.json to transpile your TypeScript to JavaScript

    In particular, noEmit should not be set to true

  3. Configure nodemon to run the TypeScript compiler to do an incremental transpilation any time a TypeScript file is changed, e.g.

    "dev": "nodemon -e ts --watch src .env --exec \"tsc --incremental && node src/index.js\"",
    

    You can even remove --incremental to further simplify it, but it will end up being much slower, comparable to nodemon/node-dev + ts-node.

bmaupin
  • 14,427
  • 5
  • 89
  • 94
  • If you install `nodemon` locally, you cannot run `nodemon` on cmd. Instead, install it `globally` with `-g`. – Timo Feb 19 '22 at 10:46
  • 6
    You can still run it without it being installed globally (e.g. `node_modules/.bin/nodemon`), but given that I almost always need to provide flags to nodemon, it's much more convenient to add a script in package.json that runs nodemon with all the flags I need (as in the example in *Alternative 3*). That also makes it more convenient when working with multiple projects; you can just call `npm run dev` and not have to remember how each project needs to be configured. Of course you're more than welcome to install it globally if that suits your fancy. – bmaupin Feb 22 '22 at 14:17
  • What do you mean by "type checking should still be part of your build process". And how would I include type checking in my build process? – thegoodhunter-9115 Feb 03 '23 at 02:40
  • @thegoodhunter-9115 The tools recommended by the answers on this page are for local development. But for production, it's generally recommended to transpile the TypeScript to JavaScript, which is the "build" step. If you're using the TypeScript compiler (`tsc`), it does type checking by default ([actually I don't think there's any way to turn it off](https://github.com/microsoft/TypeScript/issues/29651)). Since you might not want to wait until build time to find out if there are any type errors, you could also use `tsc` to do type checking as part of your testing process or as a pre-push hook. – bmaupin Feb 03 '23 at 14:39
  • Life saver answer – Kashif Nazar Feb 16 '23 at 11:28
  • `tsx` doesn't support `emitDecoratorMetadata` for now – Filip Seman Jun 25 '23 at 15:33
55

This works for me:

nodemon src/index.ts

Apparently thanks to since this pull request: https://github.com/remy/nodemon/pull/1552

DLight
  • 1,535
  • 16
  • 20
  • 2
    This works for me too but how? Seems kind of magical. What's compiling the typescript? I don't have `ts-node` installed. – d512 Dec 11 '19 at 21:18
  • 2
    @d512 Are you sure it's not in your `node_modules/`? For me it fails if I don't have it. – DLight Dec 11 '19 at 21:41
  • 3
    This indeed does require `ts-node` to be installed. Running this command without `ts-node` will result in an `failed to start process, "ts-node" exec not found` error. You likely had this as a leftover artifact in `node_modules`. That being said, this solution is much nicer since it doesn't require additional config. – Brandon Clapp May 25 '20 at 20:45
  • 1
    Install ts-node globally: `npm install -g ts-node` – Rafael Pizao Sep 09 '20 at 21:26
21

you could use ts-node-dev

It restarts target node process when any of required files changes (as standard node-dev) but shares Typescript compilation process between restarts.

Install

yarn add ts-node-dev --dev

and your package.json could be like this

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "tsc": "tsc",
  "dev": "ts-node-dev --respawn --transpileOnly ./src/index.ts",
  "prod": "tsc && node ./build/index.js"
}
jsina
  • 4,433
  • 1
  • 30
  • 28
20

Specifically for this issue I've created the tsc-watch library. you can find it on npm.

Obvious use case would be:

tsc-watch server.ts --outDir ./dist --onSuccess "node ./dist/server.js"

Eliasz Kubala
  • 3,836
  • 1
  • 23
  • 28
gilamran
  • 7,090
  • 4
  • 31
  • 50
  • How would this work in the case of an express or koa server since it doesn't actually kill the previous node instance? – brianestey Nov 27 '18 at 03:55
  • 'tsc-watch' kills and restarts the process for you. – gilamran Nov 28 '18 at 17:10
  • This is exactly what I was looking for. Not sure what the purpose of ts-node-dev is, but I couldn't get it to report typescript errors. After spending hours trying to get it working, I tried tsc-watch, and it worked like a charm! – Charles Naccio Jan 16 '20 at 08:04
  • @gilamran in the documentation of your package there is a typo: `"[...] similar to nodemon but for TypeCcript."`:) – Massimiliano Kraus Jan 27 '20 at 22:26
13

Add "watch": "nodemon --exec ts-node -- ./src/index.ts" to scripts section of your package.json.

takasoft
  • 1,228
  • 15
  • 15
9

i did with

"start": "nodemon --watch 'src/**/*.ts' --ignore 'src/**/*.spec.ts' --exec ts-node src/index.ts"

and yarn start.. ts-node not like 'ts-node'

9

I would prefer to not use ts-node and always run from dist folder.

To do that, just setup your package.json with default config:

....
"main": "dist/server.js",
"scripts": {
  "build": "tsc",
  "prestart": "npm run build",
  "start": "node .",
  "dev": "nodemon"
},
....

and then add nodemon.json config file:

{
  "watch": ["src"],
  "ext": "ts",
  "ignore": ["src/**/*.spec.ts"],
  "exec": "npm restart"
}

Here, i use "exec": "npm restart"
So all ts file will re-compile to js file and then restart the server.

To run while in dev environment,

npm run dev

Using this setup I will always run from the distributed files and no need for ts-node.

Paul-Marie
  • 874
  • 1
  • 6
  • 24
Raja P.B.
  • 151
  • 2
  • 4
6

The first step - Install the below packages in deDependencies

npm i -D @types/express @types/node nodemon ts-node tsc typescript

or using yarn

yarn add -D @types/express @types/node nodemon ts-node tsc typescript

The second step - using this configuration in your tsconfig.json file

{
  "compilerOptions": {
    "target": "es6" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */,
    "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
    "lib": [
      "DOM",
      "ES2017"
    ] /* Specify library files to be included in the compilation. */,
    "sourceMap": true /* Generates corresponding '.map' file. */,
    "outDir": "./dist" /* Redirect output structure to the directory. */,
    "rootDir": "./src" /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */,

    "strict": true /* Enable all strict type-checking options. */,
    "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
    "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */,
    "skipLibCheck": true /* Skip type checking of declaration files. */,
    "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
  },
  "exclude": ["node_modules"],
  "include": ["./src"]
}

The third step - using these scripts in your package.json file

"scripts": {
    "start": "node ./dist/server.js",
    "dev": "nodemon -L ./src/server.ts && tsc -w"
},
RS Shonjoy
  • 245
  • 3
  • 2
5

add this to your package.json file

scripts {
"dev": "nodemon --watch '**/*.ts' --exec 'ts-node' index.ts"
}

and to make this work you also need to install ts-node as dev-dependency

yarn add ts-node -D

run yarn dev to start the dev server

princebillyGK
  • 2,917
  • 1
  • 26
  • 20
5

Another way could be to compile the code first in watch mode with tsc -w and then use nodemon over javascript. This method is similar in speed to ts-node-dev and has the advantage of being more production-like.

 "scripts": {
    "watch": "tsc -w",
    "dev": "nodemon dist/index.js"
  },
3

STEP 1: You can simple install nodemon and ts-node (skip if you already done)

npm install --save-dev nodemon ts-node

STEP 2: You can configure the start script in package.json

"start": "nodemon ./src/app.ts"

As now nodemon automatically identify the typescript from the project now and use ts-node command by itself. Use npm start and it will automatically compile/watch and reload.

If you get any errors like typescript module not found in the project. simple use this command in the project folder.

npm link typescript
MBK
  • 2,589
  • 21
  • 25
2

I got this error : code: 'ERR_UNKNOWN_FILE_EXTENSION' i needed the esm support, so if you want ES6 support you can try bellow commands

npm i -D ts-node nodemon

in package.json add below script :

"dev": "nodemon --exec ts-node-esm ./src/index.ts"

Samyar
  • 387
  • 3
  • 15
1

Just update these 3 packages

nodemon, ts-node, typescript
yarn global add nodemon ts-node typescript

or

npm install -g nodemon ts-node typescript

and now you can run this, problem solved

nodemon <filename>.ts
marsh-wiggle
  • 2,508
  • 3
  • 35
  • 52
Raghav Rathi
  • 187
  • 2
  • 7
  • Please add your comments or instructions outside of your code. That will be more understandable and readable. – vijayP Dec 28 '21 at 13:15
1

Clear logs of the console after changing

Javascript:

"start": "nodemon -x \"cls && node\" index.js",

Typescript:

"start": "nodemon -x \"cls && ts-node\" index.ts",
Masih Jahangiri
  • 9,489
  • 3
  • 45
  • 51
1

ts-node with standard nodejs

Added in Node: v18.11.0, v16.19.0 you can use --watch, no need for nodemon

Added in ts-node: v10.9.1 you can use native integration option for swc compiler. The application starts faster, but your experience may vary.

example

// package.json
{
    "scripts": {
        "dev": "node --watch --loader=ts-node/esm ./src/app.ts"
    },
    "devDependencies": {
        "ts-node": "~10.9.0",
        "@swc/core": "~1.3.0"
    }
}
// tsconfig.json
{
    "ts-node": {
        "swc": true
    },
    "compilerOptions": {
        // ...
    }
}

tsx

Overall, using tsx is a good choice, but it currently does not support emitDecoratorMetadata, which is a dealbreaker for many projects.

Filip Seman
  • 1,252
  • 2
  • 15
  • 22
0

If you are having issues when using "type": "module" in package.json (described in https://github.com/TypeStrong/ts-node/issues/1007) use the following config:

{
  "watch": ["src"],
  "ext": "ts,json",
  "ignore": ["src/**/*.spec.ts"],
  "exec": "node --loader ts-node/esm --experimental-specifier-resolution ./src/index.ts"
}

or in the command line

nodemon --watch "src/**" --ext "ts,json" --ignore "src/**/*.spec.ts" --exec "node --loader ts-node/esm --experimental-specifier-resolution src/index.ts"
fernandopasik
  • 9,565
  • 7
  • 48
  • 55
0

add --poll options on your package.json

The --poll option in ts-node-dev tells it to check the source code files for changes by periodically looking at them, instead of waiting for the file system to report changes. This ensures that changes to the files are always detected, even on file systems that don't report changes reliably.

   "start": "ts-node-dev --poll src/index.ts"
elias-soykat
  • 100
  • 1
  • 8
-1

With nodemon and ts-node:

nodemon --watch source --ext ts,json --exec "node --loader ts-node/esm ./source/index.ts"
Richie Bendall
  • 7,738
  • 4
  • 38
  • 58