Dockerize Your TypeScript Application with Multistage Build: A Comprehensive Guide

Memek SaviourMemek Saviour
3 min read

Table of contents

Hello all, it is another day to discuss something new and we will be looking at the Docker Multistage Build.

Docker Multistage Build, introduced in Docker 17.05, enables the utilization of multiple FROM statements within a single Dockerfile. Each FROM statement delineates a distinct build stage, facilitating the copying of files from one stage to another. This methodology culminates in a final image housing only essential artifacts, effectively minimizing the size of the Docker image and enhancing build efficiency.

Multi-stage builds allow you to create a leaner and more efficient Docker image by separating the build process into distinct stages. This approach keeps the final image free of unnecessary components, improving security and reducing download times.

Containerizing your TypeScript application using Docker offers numerous benefits, including portability, consistency, and simplified deployment. However, traditional single-stage builds can result in bulky images due to the inclusion of development dependencies and build tools. Multi-stage builds address this issue by creating a slimmed-down image for production environments.

Here's how to Dockerize your TypeScript application with a multi-stage build:

1. Project Setup:

  • Create a project directory and initialize a Node.js project using npm init -y.

  • Install necessary dependencies like typescript and your application dependencies using npm install typescript @types/your-dependency-name your-dependency-name.

  • Develop your TypeScript code in a src directory with an entry point (e.g., index.ts).

2. Dockerfile Creation:

  • Create a file named Dockerfile in your project directory.

  • Define the base image using FROM node:16-alpine (or a preferred Node.js version).

3. Build Stage:

  • Introduce a build stage using AS build. This stage handles building the application.

  • Set the working directory using WORKDIR /app.

  • Copy package.json and package-lock.json files using COPY package*.json ./.

  • Install dependencies using RUN npm install.

  • Copy the entire project code using COPY . ..

  • Build the TypeScript code using RUN npm run build (assuming your build script is defined in package.json).

4. Final Stage:

  • Define a final stage using FROM node:16-alpine (or the same base image).

  • Set the working directory using WORKDIR /app.

  • Copy the built artifacts from the build stage using COPY --from=build /app/dist /app.

  • Expose the port your application listens on using EXPOSE 3000 (replace with your actual port).

  • Define the command to start your application using CMD ["npm", "start"] (replace with your start script).

Complete Dockerfile Example:

Dockerfile

FROM node:16-alpine

AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

FROM node:16-alpine
WORKDIR /app
COPY --from=build /app/dist /app
EXPOSE 3000
CMD ["npm", "start"]

5. Building and Running the Image:

  • Build the image using docker build -t my-typescript-app . (replace my-typescript-app with your desired image name).

  • Run the container using docker run -p 3000:3000 my-typescript-app. This maps the container port (3000) to the host port (3000).

Benefits of Multi-Stage Builds:

  • Smaller Image Size: By separating build and runtime stages, development tools and dependencies are excluded from the final image, resulting in a smaller footprint.

  • Improved Security: A smaller image reduces the attack surface, making it less vulnerable to potential security threats.

  • Faster Startup Times: Smaller images download and start quicker, improving application responsiveness.

Additional Tips:

  • Consider using a .dockerignore file to exclude unnecessary files from the build context.

  • Utilize environment variables for configuration instead of hardcoding them in the Dockerfile.

  • Explore advanced techniques like multi-arch builds for supporting different architectures.

  • Environment Variables: You can use environment variables to configure your application during runtime. Define them in your Dockerfile or using the -e flag when running the container.

By following the steps and understanding the concepts outlined in this guide, you can efficiently Dockerize your TypeScript application, equipping it with the advantages of a multi-stage build for a seamless transition to production.

CIAO!!!

0
Subscribe to my newsletter

Read articles from Memek Saviour directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Memek Saviour
Memek Saviour