Skip to content

How to Install and Set Up shadcn/ui with npm, pnpm, Yarn, and Bun

Written By Ajay Patel Categories: tutorials
Published: Updated:
8 min read

How to Install and Set Up shadcn/ui with npm, pnpm, Yarn, and Bun

Installing shadcn/ui is not like installing a component library. You do not add a package and import from it - the CLI writes component source directly into your project.

The command for a new setup is:

npx shadcn@latest init

That partz is easy. The part that goes wrong is everything init checks before it does anything: your framework, your Tailwind setup, and your import aliases. Miss one and the command stops with an error instead of a config file.

This guide covers the correct command for each package manager, the Yarn version trap, what init actually verifies, and how to fix each failure.

Once your setup works, shadcnstudio.com is a useful place to see how installed components come together in real interfaces.

Version note: Verified against shadcn@4.18.0 in August 2026. CLI prompts and flags change between releases, so check your version with npx shadcn@latest --version if something here doesn’t match.

Package Manager Commands

The CLI runs through whichever package manager your project already uses. There is no shadcn-specific reason to prefer one. Choose npm, pnpm, Yarn, or Bun below; your selection is remembered across every command on this page.

npx shadcn@latest init
npx shadcn@latest add button

Two notes on that table.

Yarn Classic has no dlx. If yarn --version reports 1.x, yarn dlx fails outright. See the fix below.

Bun works either way. The official docs use bunx --bun, which forces the Bun runtime. Plain bunx shadcn@latest init also works, though it will quietly write a lockfile entry.

Match the CLI to your lockfile - package-lock.json means npm, pnpm-lock.yaml means pnpm, yarn.lock means Yarn, bun.lock means Bun. Initializing with one manager and adding components with another is a good way to end up with two lockfiles.

If you want a complete starting layout after initialization, a Shadcn template gives you a larger foundation than installing individual components one by one.

What init Checks Before It Runs

This is the part worth understanding, because almost every failed install fails here rather than during the install itself.

init runs four preflight checks in order, and stops at the first one that fails:

  1. An existing components.json - if one is already there, it asks before overwriting.
  2. A supported framework - detected from your project, not assumed.
  3. Tailwind CSS - must already be installed and configured.
  4. Import aliases - must already exist in tsconfig.json.

Two of those deserve emphasis because they are prerequisites, not things the CLI sets up for you:

Tailwind must be installed first. shadcn does not install or configure it. Both Tailwind v3 and v4 are supported - v3 needs a config file and a CSS file, v4 needs the CSS file.

Path aliases must already exist. init reads them; it never writes them. If @/* isn’t in your tsconfig.json, the command refuses to proceed.

When the checks pass, init creates components.json, adds the cn utility, installs dependencies, and writes your theme tokens into your global CSS. A typical result:

project/
├── components.json
├── components/ui/
├── lib/utils.ts
└── app/globals.css

The Init Prompts

In an existing project, init asks less than most tutorials suggest. The first prompt is your component base:

? Select a component library › - Use arrow-keys. Return to submit.
❯   Base UI (Recommended)
    React Aria
    Radix UI

Base UI is the default for new projects. Radix is still fully supported, and React Aria is a first-class option - this is a real choice, not a legacy one.

The second prompt is your starting style:

? Which preset would you like to use?
❯   Nova - Lucide / Geist
    Vega
    Maia
    Lyra
    Mira
    Luma
    Sera
    Rhea
    Custom

Both answers are recorded in components.json. The base is stored as a prefix on the style, so choosing Base UI with Nova gives you "style": "base-nova".

One answer is hard to reverse. The docs state that style, baseColor, and cssVariables cannot be changed after initialization. Switching base later prompts a warning that components outside your ui directory may need manual updates. If you want a different neutral palette afterwards, that is a separate job - see changing the shadcn base color in an existing project.

After init has written your theme tokens, the Shadcn Theme Generator can help you preview a coordinated palette before applying visual changes across the project.

You can skip the prompts entirely:

npx shadcn@latest init -b base -p nova -y

init takes a few other flags worth knowing about at setup time, including --rtl, which turns on right-to-left support so components are generated direction-aware from the start. If you are building for Arabic, Hebrew, Persian or Urdu, it is much less work to set that here than to retrofit it - see RTL support for shadcn/ui in Next.js for what it changes.

Installing in an Existing Project

The flow is the same, but the prerequisites are on you rather than on a scaffold. Before running init, confirm Tailwind is installed and @/* is mapped in tsconfig.json.

cd my-project
npx shadcn@latest init

If preflight fails, nothing is written - you can fix the problem and run it again safely. For a fuller walkthrough of retrofitting an established codebase, see adding shadcn/ui to an existing project.

Verify the Setup Worked

Three checks, in order.

1. components.json exists in your project root.

2. A component installs.

npx shadcn@latest add button

That should create components/ui/button.tsx. For anything about which components to install, or installing many at once, see adding all shadcn components in one command.

3. It renders.

import { Button } from "@/components/ui/button"

export default function Page() {
  return <Button>Test Button</Button>
}

If the button renders with styling, the setup is done.

From there, Shadcn blocks are a practical next step when you need composed sections such as a hero, form, or dashboard panel rather than another standalone component.

Common Setup Errors and Fixes

ErrorCauseFix
error Command "dlx" not found.Yarn Classic 1.x has no dlxUse npx shadcn@latest init, or move the project to Yarn Berry
We could not detect a supported framework at <path>Not a recognised framework, or dependencies aren’t installedInstall dependencies first, or follow the manual setup guide. Nothing was written, so retrying is safe
No Tailwind CSS configuration foundTailwind missing or misconfiguredInstall and configure Tailwind, then re-run init
Could not find valid path aliases or package imports for init.No @/* mapping in tsconfig.jsonAdd the alias yourself - init won’t create it
A components.json file already exists. Would you like to overwrite it?A prompt rather than an error - the project is already initializedDefault is No, so nothing is lost by accident. Answer y to overwrite, or pass --force to skip the question
You need to create a components.json file to add components. Proceed?You ran add before initAccept the prompt, or run init first
It looks like you are using React 19. then How would you like to proceed?npm only. The CLI flags a possible peer-dependency conflict when it detects React 19 with npmChoose --force or --legacy-peer-deps. Non-interactive and --silent runs pick --force automatically. pnpm, Yarn and Bun never show this
CLI behaves oddly or can’t be foundYou installed shadcn-uiThat package is deprecated. Use shadcn

Yarn Classic

The most common one, because the official docs publish a single yarn dlx command that doesn’t work on Yarn 1.x:

yarn --version        # 1.x means Classic
npx shadcn@latest init

Upstream is aware of this - there are open issues and an unmerged documentation fix - so expect the docs to keep showing yarn dlx for now.

Signs you’re following an outdated guide

Two instructions date a tutorial immediately:

  • npm install shadcn-ui or yarn add shadcn-ui. shadcn is not a dependency you import from, and that package was renamed to shadcn in 2024 and is now deprecated - though it still records hundreds of thousands of installs a month, because older guides keep pointing at it.
  • create-react-app. It isn’t one of the supported templates. The current CLI targets next, vite, start, react-router, laravel, and astro.

If a guide opens with either one, assume the rest of its instructions are stale too.

Import path doesn’t resolve

If @/components/ui/button won’t resolve after a successful install, your alias and your project layout disagree. A project using src/ needs:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

The aliases in components.json must match the same structure.

Re-running init

You can. On a project that already has components.json, init asks first:

? A components.json file already exists. Would you like to overwrite it? › (y/N)

The default is No, so an accidental re-run won’t wipe your config. Passing --force skips that question and instead asks whether to re-install your existing UI components.

Which Frameworks Are Supported?

init can scaffold or detect these templates:

next · vite · start · react-router · laravel · astro

The install command is identical for all of them; only the generated project layout differs.

For a complete screen within an existing app, Shadcn pages show how multiple sections fit together after the basic component setup is in place.

FAQ

  • Do I need Tailwind CSS before installing shadcn/ui?

Yes, and it is a hard requirement rather than a recommendation. init checks for it and stops with No Tailwind CSS configuration found if it isn’t there. Both v3 and v4 are supported.

  • Does init set up my import aliases?

No. It reads them and refuses to continue without them. Add @/* to your tsconfig.json before running it.

  • Should I use npm, pnpm, Yarn, or Bun?

Whichever your project already uses. The only real difference is invocation - and that Yarn Classic can’t run yarn dlx at all.

Conclusion

Most shadcn/ui setup problems are not shadcn problems. The CLI checks your framework, your Tailwind install, and your import aliases before it writes anything, and it stops at the first thing that isn’t ready.

So the fastest path to a working install is to get those three right first, run init with the command that matches your package manager, and verify with a single component before building anything on top of it. If the command fails, the error text tells you exactly which check didn’t pass.