Set up path aliases and type checking in MDX with TypeScript

Improve DX and reliability in your MDX + TypeScript setup using two small but powerful configuration changes.

MDX is a great fit for React-based projects. It allows you to mix Markdown with JSX, making it ideal for blogs, docs, and other content-driven UIs.

However, when working with MDX and TypeScript in a Vite-powered project (in my case, using React Router 7), I ran into two issues:

  1. TypeScript path aliases don’t work inside .mdx files.
  2. Type safety is lost when authoring components in MDX.

Both of these can be resolved with minimal configuration.

#Enable TypeScript Path Aliases in .mdx Files

When using Vite with TypeScript, it's recommended to use the vite-tsconfig-paths plugin to automatically resolve path aliases defined in your tsconfig.json for .ts and .tsx files.

This allows you to use clean import paths like @/components/Button instead of long relative ones like ../../components/Button.

Here's how path aliases are set up on this website:

portfolio/tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./app/*"]
    }
  }
}
portfolio/vite.config.ts
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
...

export default defineConfig({
  plugins: [..., tsconfigPaths()],
});
portfolio/app/routes/example.tsx
import Button from "@/components/ui/Button";

export default function Example() {
  return <Button>Click me</Button>;
}

#Path Aliases Don’t Work in .mdx

The problem is, that path aliases do not apply to non-TypeScript modules — like .mdx — out of the box.

Path aliases do not work in MDX files out of the box — leading to an error when importing components

To enable this behavior, you need to opt into JavaScript file support by enabling allowJs in your tsconfig.json:

{
  "compilerOptions": {
    "allowJs": true
  }
}

With this option enabled, Vite will — in most cases — correctly resolve path aliases inside MDX content.

#Alternative: Use loose: true

According to vite-tsconfig-paths documentation, if you prefer not to enable allowJs, or it didn't help, you can pass loose: true to the plugin config instead:

vite.config.ts
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
...

export default defineConfig({
  plugins: [..., tsconfigPaths({ loose: true })],
});

This should make alias resolution work across all file types, without changing your TypeScript configuration.

#Enable Strict Type Checking in MDX Files

By default, MDX files don’t benefit from TypeScript’s type checking. That means you can pass incorrect props to components inside .mdx files and nothing will warn you.

Without type checking enabled, props can be passed incorrectly to components in MDX without any warnings or errors

The mdx-analyzer project supports strict type checking inside MDX via the checkMdx flag. This enables proper validation of component usage in .mdx files.

To turn it on, add the following to your tsconfig.json:

tsconfig.json
{
  "mdx": {
    "checkMdx": true
  }
}

With checkMdx enabled, you’ll get type errors when props don’t match expected types. This improves reliability and helps catch mistakes earlier.

With type checking enabled, invalid props in MDX trigger a clear error message