NestJS is a powerful TypeScript framework, but its default compilation (using the TypeScript compiler, tsc) can become a bottleneck as projects grow. SWC (Speedy Web Compiler) is a Rust-based compiler that promises significantly faster build times (up to ~20× faster than tsc). In this comprehensive guide, we’ll walk through creating a standalone NestJS application using SWC instead of tsc. We’ll cover setup, configuration changes, integration with the Nest CLI or manual workflows, performance benchmarks, Dockerizing for production, and troubleshooting common issues. Experienced developers will find detailed steps, code snippets, and insights to supercharge NestJS compilation with SWC.

1. Setting Up a New NestJS Project

Before integrating SWC, let’s scaffold a new NestJS project. You can use the NestJS CLI to quickly create a boilerplate application:

  1. Install NestJS CLI: If you haven’t already, install the Nest CLI globally (requires Node.js). npm i -g @nestjs/cli
  2. Create a new project: Run the Nest generator to create a project (choose a package manager and features as prompted). For example: nest new my-swc-app This will create a new directory my-swc-app with a standard NestJS structure (including a main.ts, controllers, modules, etc.). By default, this uses TypeScript and the tsc compiler. We will next configure it to use SWC.
  3. Verify the project structure: Navigate into the project folder and review files like package.json, tsconfig.json, and nest-cli.json. The nest-cli.json should exist (created by Nest CLI) and typically contains default compiler options (using tsc). We will modify this file when enabling SWC.

2. Installing SWC and Related Tools

With a NestJS project ready, the next step is to add SWC compiler dependencies. SWC consists of a core library and a CLI tool. Install them as development dependencies:

npm install --save-dev @swc/cli @swc/core

This adds the SWC compiler and CLI to your project (the NestJS docs also recommend these packages). The @swc/core module is the engine, and @swc/cli provides a command-line interface for transpiling your code. Since these are only needed for building the app (not at runtime), we install them under devDependencies.

In addition, if you plan to run the app in watch mode or manage multiple processes, consider installing tools like Nodemon (to auto-restart the Node process on changes) and Concurrently (to run build and serve scripts in parallel). For example:

npm install --save-dev nodemon concurrently

These are optional but helpful for a smooth development workflow (as we’ll see later). Your package.json should now include @swc/core, @swc/cli, and possibly nodemon and concurrently under devDependencies.

3. Configuring SWC in the NestJS Project

Now we will configure the project to use SWC instead of tsc for compilation. This involves adjusting some configuration files and adding an SWC config file.

3.1 Nest CLI Configuration (nest-cli.json)

NestJS projects generated by the CLI include a nest-cli.json file that defines how the project is built and run. By default, it will use the TypeScript compiler. To switch to SWC, update this file’s compiler options to use the SWC builder:

// nest-cli.json
{
  "compilerOptions": {
    "builder": "swc",
    "assets": ["**/*.hbs"],       // example: include any assets if needed
    "watchAssets": true
  }
}

Here, setting "builder": "swc" tells the Nest CLI to use SWC for building the project. Now, whenever you run Nest CLI commands (like nest build or nest start), it will transpile using SWC. You can also specify this via command line (nest start -b swc) if you prefer, but persisting it in the config is convenient.

Optional – Type Checking: SWC does not perform type checking on its own. If you want to ensure TypeScript types are still validated during build, enable the Nest CLI’s type-check option. You can do this by adding "typeCheck": true in compilerOptions or by using the --type-check flag in commands. For example, in nest-cli.json:

{
  "compilerOptions": {
    "builder": "swc",
    "typeCheck": true
  }
}

With this, the Nest CLI will run tsc in the background in no-emit mode to report type errors while SWC handles the actual emit. This gives you the best of both worlds: fast builds and compile-time type safety. Keep in mind the type checking runs asynchronously, so your build might succeed and start even if there are type errors (they’ll be logged when detected). If you prefer to catch type errors before running, you can also run tsc --noEmit or nest build --type-check in CI pipelines.

3.2 TypeScript Compiler Options (tsconfig.json)

Open the tsconfig.json of your project. Since we generated the project via Nest CLI, it likely already has the necessary settings for decorators and metadata. Ensure the following options are set in compilerOptions:

  • "experimentalDecorators": true – allows use of decorators.
  • "emitDecoratorMetadata": true – emits metadata needed by NestJS for things like dependency injection.
  • "target": "ES2017" (or a higher ES version supported by your Node runtime) – this should match what you want your output JavaScript to target. Node 18+ can handle ES2017+ features.
  • "module": "commonjs" – since Nest apps typically run on Node (which uses CommonJS modules by default, unless you are specifically using ECMAScript modules). We want SWC to output the same module format.

These are usually already configured by Nest CLI. For example, a default Nest tsconfig uses ES2017 target and CommonJS module. Matching the SWC output to these ensures consistency. If you plan to use ECMAScript Modules (ESM) in Node, you could target "module": "es6" and adjust package.json "type": "module", but that’s beyond our scope – we’ll assume CommonJS here for simplicity.

One thing to add: if you decide to rely entirely on SWC for builds, you might set "noEmit": true in tsconfig to prevent tsc from outputting files (especially if you run tsc for type-checking). However, with the Nest CLI typeCheck mode, you don’t need to manually set this; the CLI will handle it.

3.3 SWC Configuration (.swcrc)

SWC can be configured via a file named .swcrc in the project root. The Nest CLI’s SWC builder comes pre-configured with sensible defaults for NestJS, so technically this file is optional. However, creating one allows you to tweak or ensure certain settings, especially around TypeScript features like decorators.

Create a file .swcrc in the root of your project with the following content:

{
  "$schema": "https://json.schemastore.org/swcrc",
  "sourceMaps": true,
  "module": {
    "type": "commonjs"
  },
  "jsc": {
    "target": "es2017",
    "parser": {
      "syntax": "typescript",
      "decorators": true,
      "dynamicImport": true
    },
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    },
    "keepClassNames": true,
    "baseUrl": "./"
  },
  "minify": false
}

This configuration explicitly enables TypeScript syntax parsing, including experimental decorators and dynamic import(). The transform section is crucial: it sets legacyDecorator: true and decoratorMetadata: true. These ensure that SWC handles decorators in a way compatible with NestJS (emitting design-type metadata just like emitDecoratorMetadata in tsc). The above config also keeps class names (useful for debugging/logging) and includes source maps for easier debugging. We’ve set the module type and target to match our tsconfig (CommonJS and ES2017). We also disable minification for now – in a dev/build scenario, you typically don’t minify server code.

Note: The NestJS docs note that the SWC builder is already configured for decorators, etc., but explicitly adding them in .swcrc doesn’t hurt and can avoid confusion. Also, if you have Path Aliases (e.g. "@app/*" in tsconfig paths), SWC won’t automatically resolve those. You may either avoid such non-relative imports or use a tool like tsconfig-paths at runtime. For simplicity, consider using relative imports or update your imports like src/xyz to relative paths or configure an SWC plugin for path alias resolution.

After adding the .swcrc, you have essentially replaced tsc’s job with SWC for transpiling your TypeScript to JavaScript. Next, we’ll see how to actually run the build and app using this new setup.

4. Development Workflow: Using SWC with Nest CLI vs Manual Builds

With the nest-cli.json configured to use SWC, you can run the application just as you normally would:

  • Start in development mode: Run nest start --watch (or add -b swc if you didn’t set the config). For example: nest start -b swc -w This will compile the project with SWC and launch the NestJS server, watching for file changes. Thanks to SWC’s speed, the initial compile and subsequent reloads should be much faster than with tsc.
  • Build for production: Run nest build (which will output compiled files to the dist/ folder). This uses SWC to transpile all files. If you set typeCheck: true, it will also perform a type check during this process. After building, you can start the app with node dist/main.js (or nest start without rebuild, since it can detect the dist).
  • Running with type check: If you want to ensure type errors are caught, use nest start --type-check (or set in config as discussed). This way, you get a background type-check thread while using SWC. Any type errors will appear in the console, but the app will still run if the transpilation succeeded.

One thing to note: Nest CLI plugins. These are build-time plugins (for example, the Swagger plugin that generates OpenAPI specs, or GraphQL plugin that generates schema). When using SWC, these plugins don’t run automatically unless you have typeCheck enabled (which runs the TypeScript compiler plugins). If you use such plugins and don’t want to enable full type checking, you may need to run a manual plugin metadata generation step (as described in Nest docs). For most cases, simply enabling compilerOptions.typeCheck will ensure compatibility with things like OpenAPI docs generation.

In summary, using the Nest CLI with SWC is straightforward: all your usual commands (start, start:dev, build, test etc.) continue to work, just faster. Jest testing can also be integrated with SWC, but that’s beyond our scope – see Nest documentation for using @swc/jest if needed.

5. Deployment Considerations and Dockerizing with SWC

After switching to SWC for compilation, deploying your NestJS application is not significantly different from a normal Nest app – you still ultimately deploy the compiled JavaScript. However, there are a few considerations to keep in mind:

  • Ensure SWC is installed in CI/Build environment: If your deployment involves a CI pipeline or Docker build, make sure @swc/core and @swc/cli are available in that environment (as dev dependencies). For example, if building a Docker image, you will need to install devDependencies to compile the app, then you can prune them for the final image.
  • Generating type definitions (optional): SWC does not generate .d.ts files. For applications, this is usually not needed in production. If you have a library or you need type definitions for some reason, you might run tsc separately to emit declarations. The Nest CLI has ongoing improvements to allow generating type declarations alongside SWC builds for libraries, but for an application, you can skip this.
  • Source maps: If you want to debug the deployed app, include source maps (we set "sourceMaps": true in .swcrc). Just ensure you either don’t ship the map files (to keep them private) or handle them securely. For Node apps, you can also use tools like source-map-support to enable stack traces to map to TypeScript lines.

5.1 Example Dockerfile (Multi-Stage)

Below is an example of a multi-stage Dockerfile for a NestJS app using SWC. This will build the app using SWC and produce a lean production image:

# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app

# Install dependencies (including devDependencies for build)
COPY package*.json ./
RUN npm install

# Copy source code and compile with SWC
COPY . .
# Use Nest CLI to build or directly use SWC:
RUN npm run build  # assuming "build" script uses nest build (with SWC configured)

# Stage 2: Run
FROM node:20-alpine AS runner
WORKDIR /app

# Only copy production files (compiled dist and necessary files)
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
# Install only production dependencies (if any)
RUN npm install --omit=dev && npm cache clean --force

# Inform Docker the app will listen on port 3000 (Nest default)
EXPOSE 3000

CMD ["node", "dist/main.js"]

Let’s break down a few points:

  • We use an alpine Node image for slim size. Note that SWC’s npm package includes platform-specific binaries. On Alpine (which uses musl libc), the @swc/core package will attempt to use a musl binary. Ensure the version of @swc/core you installed supports Alpine. If you encounter an error like “Failed to load SWC binary for linux/x64”, you may need to install the @swc/core-linux-musl variant or use a non-Alpine base image. An easy workaround is to use a Node image based on Debian/Ubuntu (e.g., node:20-bullseye or node:20-slim) for the build stage, since SWC provides a binary for glibc out of the box.
  • The build stage installs all dependencies (including dev). We then run the build (here using npm run build which in our case triggers nest build with SWC). This produces the dist folder with compiled JavaScript.
  • The final stage copies only the dist output and package files, then installs only production deps (--omit=dev for npm). Since NestJS apps typically don’t have runtime deps aside from Nest itself (which is already installed), this step is often quick. We don’t need @swc/core or TypeScript in the runtime image – those were only for build.
  • The result is a lightweight container containing just Node and the compiled app. Start-up is as simple as running the Node process on the main file.

This strategy ensures that your deployment artifact is as small as possible and doesn’t include source TypeScript or unnecessary packages. It’s the same approach as with tsc, except our build step is faster 😄. You can adjust the Node version as needed (just ensure compatibility with the JS output of SWC’s target).

Cloud Platforms: If you’re deploying to a serverless environment (AWS Lambda, etc.) or using a platform like Heroku, you can also compile the app ahead of time using SWC. For example, in your CI/CD, run npm run build (with SWC) to produce dist, then zip that for Lambda or push it to the platform. The important part is to run the build in an environment where the SWC binary can execute (so, on Linux if your deployment is Linux-based). If using something like AWS CodeBuild or GitHub Actions, make sure to include the npm install of dev dependencies and the nest build step in your pipeline.

Conclusion

By following this guide, you’ve transformed your NestJS build process to use SWC, unlocking significantly faster compile times. We started with a standard NestJS app, installed SWC, and configured the Nest CLI and project settings to use it. We demonstrated how to run the app with SWC in development, both via Nest CLI and manually, and we saw how SWC drastically reduces build times. We also covered how to containerize a NestJS app built with SWC for production deployment, and went through common issues and how to address them.

SWC integration in NestJS (especially with Nest v10+ and the latest CLI) is fairly mature and can provide a huge boost to development speed. Many teams have adopted it to shave minutes off build/test cycles and improve CI times. That said, keep an eye on the few corner cases (like circular imports and CLI plugins). With proper configuration and the tips above, you should be able to enjoy a much snappier NestJS workflow.

Sign up to receive updates on new content & exclusive offers

We don’t spam! Cancel anytime.