shadcn-ui/ui codebase analysis: How does shadcn-ui CLI work? — Part 2.14
Tags: javascript, shadcnui, nextjs, opensource
Published: 2024-07-16 21:07:29

I wanted to find out how shadcn-ui CLI works. In this article, I discuss the code used to build the shadcn-ui/ui CLI.

In part 2.11, we looked at runInit function and how shadcn-ui/ui ensures directories provided in resolvedPaths in config exist.

The following operations are performed in runInit function:

![](https://media.licdn.com/dms/image/D4E12AQHEmOyCs-cx4Q/article-inline_image-shrink_1000_1488/0/1721163275555?e=1726704000&v=beta&t=6j10fRzVcFjODfc_inb84FvvhMQFq_TDSF1gYGiUcks)

1.  Ensure all resolved paths directories exist.
2.  Write tailwind config.
3.  Write css file.
4.  Write cn file.
5.  Install dependencies.

1, 2, 3 from the above are covered in part 2.12 and 2.13, let’s find out how “Write cn file” operation is done.

> _Want to learn how to build shadcn-ui/ui from scratch? Check out_ [_build-from-scratch_](https://tthroo.com/)

Write cn file
-------------

The below code snippet is picked from [cli/src/commands/init.ts](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/init.ts#L373)

```js
// Write cn file.
  await fs.writeFile(
    \`${config.resolvedPaths.utils}.${extension}\`,
    extension === "ts" ? templates.UTILS : templates.UTILS\_JS,
    "utf8"
  )
```

[templates.UTILS](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/templates.ts#L1) contains the below code

```js
export const UTILS = \`import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue\[\]) {
  return twMerge(clsx(inputs))
}
\`

export const UTILS\_JS = \`import { clsx } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs) {
  return twMerge(clsx(inputs))
}
\`
```

cn utility is literally code returned as a string and written to lib/utils when you run shadcn init.

Conclusion:
-----------

templates.UTILS variable in [packages/cli/src/commands/init.ts](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/init.ts#L331C3-L356C4) contains the cn utility function related code.

```js
export const UTILS = \`import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue\[\]) {
  return twMerge(clsx(inputs))
}
\`


export const UTILS\_JS = \`import { clsx } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs) {
  return twMerge(clsx(inputs))
}
\`
```

Catch here is, this code is presented as a string into fs.writeFile that writes to a provided path as shown below

```js
await fs.writeFile(
    \`${config.resolvedPaths.utils}.${extension}\`,
    extension === "ts" ? templates.UTILS : templates.UTILS\_JS,
    "utf8"
  )
```

> _Want to learn how to build shadcn-ui/ui from scratch? Check out_ [_build-from-scratch_](https://tthroo.com/)

About me:
---------

Website: [https://ramunarasinga.com/](https://ramunarasinga.com/)

Linkedin: [https://www.linkedin.com/in/ramu-narasinga-189361128/](https://www.linkedin.com/in/ramu-narasinga-189361128/)

Github: [https://github.com/Ramu-Narasinga](https://github.com/Ramu-Narasinga)

Email: [ramu.narasinga@gmail.com](mailto:ramu.narasinga@gmail.com)

[Build shadcn-ui/ui from scratch](https://tthroo.com/)

References:
-----------

1.  [https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/init.ts#L331C3-L356C4](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/commands/init.ts#L331C3-L356C4)
2.  [https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/templates.ts#L1](https://github.com/shadcn-ui/ui/blob/main/packages/cli/src/utils/templates.ts#L1)