Skip to main content
Version: 1.1.x

Synchronizing settings with tsconfig.json

TypeScript and SWC both need to be configured in their own files, typically tsconfig.json and .swcrc, respectively. Some settings are meant to be common between the two, such as how dependencies are resolved on the disk.

This is not a Bazel-specific problem, so we can just look for existing solutions in the ecosystem, and adapt those to be run under Bazel.

Ideally, we'd like SWC to simply read from tsconfig.json, as it is the "source-of-truth" for how editors understand .ts files. There is an issue already filed for this, but as of Jan 2023 it's not yet supported.

This document explores our options.

Maintain two files

You might just check in both files as sources.

Since both tsconfig.json and .swcrc are JSON files, we recommend adding an assert_json_matches rule to guarantee that they don't accidentally diverge.

A typical example looks like this:

load("@aspect_bazel_lib//lib:testing.bzl", "assert_json_matches")

# Verify that the "paths" entry is the same
# between swc and TS language service (in the editor)
name = "check_paths",
file1 = "tsconfig.json",
file2 = ".swcrc",
filter1 = ".compilerOptions.paths",
filter2 = ".jsc.paths",

Generate the .swcrc

Another option provided by the community is to convert the tsconfig.json file. Under Bazel we can model this as a codegen step that happens automatically.

The relevant package is tsconfig-to-swcconfig. Let's see how to wire it up.

First, add the package to your devDependencies as usual.

Then, invoke it in your BUILD file, replacing [my/pkg] with the Bazel package where the package.json appears:

load("@npm//[my/pkg]:tsconfig-to-swcconfig/package_json.bzl", tsconfig_to_swcconfig = "bin")

name = "write_swcrc",
srcs = ["tsconfig.json"],
args = ["--filename", "$(location tsconfig.json)"],
stdout = ".swcrc",
visibility = ["//:__subpackages__"],

Now you can just use the standard swc rule with the swcrc attribute. See /examples/generate_swcrc for a full example.