I tested shadcn/ui during a short coding break while cleaning up the landing page for a small SaaS idea. My goal was simple: ship a decent interface without introducing a large component framework, runtime styling layer, or another monthly tool to manage.
The first impression was refreshing. shadcn/ui does not behave like a traditional dependency-heavy component library. The CLI adds component source code directly to the project, which means I can inspect, modify, and delete everything without fighting an abstraction later.
The friction appeared when I added the first button to a minimal Next.js project. The component itself was copied correctly, but the import path failed:
Cannot find module "@/lib/utils"
The issue was not the button. My starter project did not have the expected path alias, and I had assumed the CLI would silently create one. It did not fit my existing TypeScript configuration.
The fix was small. I added the alias to tsconfig.json:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"]
}
}
}
Then I initialized the project and added the component:
npx shadcn@latest init
npx shadcn@latest add button
After restarting the development server, the import worked:
import { Button } from "@/components/ui/button";
That small failure was useful because it exposed the main trade-off: shadcn/ui gives me ownership, not complete insulation from project configuration. I still need to understand my Tailwind setup, aliases, CSS variables, and component dependencies.
For a solo builder, that is a good exchange. I can ship quickly, keep the generated code inside my repository, and make visual changes without waiting for a library release. It also works well with Docker because there is no separate UI service or runtime to operate.
My takeaway: watch the CLI-generated assumptions, especially path aliases and Tailwind configuration. Once those are aligned, shadcn/ui is a minimal, practical foundation for React interfaces without much bloat.
Top comments (0)