Dockerfile for Typescript

Using docker for local development and deployment makes it easy to get away from the "it works on my machine" problem. By having an artifact that can be rebuild in the same way each time will greatly add to the stability of any application.


Create a dockerfile

For a typescript project, I'm using my Typescript for CommonJS example.

├── .gitignore
├── .nvmrc
├── package.json
├── src
│   └── index.ts
├── tsconfig.json
└── yarn.lock

tree -a --gitignore -I .git

The package.json has a build and start script

  "scripts": {
    "build": "rimraf ./dist && tsc",
    "start": "node dist/index.js",
    "dev": "tsx src/index.js"
  }

Here is a sample Dockerfile

FROM node:22-bookworm

WORKDIR /app

COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile --ignore-scripts

# Copy the rest of the application
COPY . .

# build the code
RUN yarn build

CMD [ "npm", "start" ]

Dockerfile

Don't forget to include a .dockerignore file to keep your context small, see my article on Your Docker Build Context Is Bigger Than You Think about why.

node_modules
dist
.env
.vscode
*.log

.dockerignore

Build and Run

Now build it

docker build -t dockerfile-typescript-example:latest .

And run it. Use -it to make sure it doesn't exit. To exit press ctrl-c.

docker run -it dockerfile-typescript-example:latest

> prisma-typescript-example@0.1.0 start
> node dist/index.js

hello world!!
^C
Goodbye!

Local Development

Docker compose is a great way to do local development. Let's look at adding this app and utilizing the watch feature to update the running app when it is changed or rebuilt due to new packages being added.

The docker-compose.yml file. Note that the tty is set to true as the example is a cli app. If you are using a web app, such as express, then this isn't necessary.

services:
  app:
    build: .
    tty: true
    develop:
      watch:
        - action: sync+restart
          path: src/
          target: /app/src
        - action: rebuild
          path: package.json
    command: yarn dev

docker-compose.yml

Make sure it builds:

docker compose build

Run it with:

docker compose up --watch

        ⦿ Watch enabled
Attaching to app-1
yarn run v1.22.22
$ tsx src/index.js
app-1   | hello world!!
        ⦿ Syncing service "app" after 1 changes were detected
        ⦿ service(s) ["app"] restarted
app-1 exited with code 0
yarn run v1.22.22
$ tsx src/index.js
app-1   | hello world, again!!

And when I edit src/index.ts it will resync and restart the service.

If I add a package to the package.json file it will rebuild.

        ⦿ Rebuilding service(s) ["app"] after changes were detected...
[+] Building 0.0s (0/0)
        ⦿ service(s) ["app"] successfully built
app-1 exited with code 1
app-1 has been recreated
yarn run v1.22.22
$ tsx src/index.js
app-1   | hello world, again!!

I've shared this project on github as an example https://github.com/markcallen/dockerfile-typescript-example


Now we have created a Dockerfile and a docker-compose.yml file, allowing us to use the Dockerfile for both local development and deployment to production.

Now let's create a devcontainer to help with an easy-to-use development environment.