components.json
The components.json file is an optional configuration file for the Untitled UI CLI. Use it to customize import aliases and paths for your project structure.
Overview
The components.json file allows you to configure how the CLI handles import paths and file locations when adding components to your project. This is particularly useful for:
- Monorepos with custom workspace aliases
- Projects with non-standard directory structures
- Teams that want consistent component installation paths
Note: The components.json file is optional. If you don't have one, the CLI will auto-detect your project structure from tsconfig.json and prompt you for paths as needed.
Creating components.json
Create a components.json file in the root of your project (or the folder where you run the CLI):
{ "aliases": { "components": "@/components/", "utils": "@/utils/", "hooks": "@/hooks/", "styles": "@/styles/" }, "examples": "app" }
Configuration options
aliases
The aliases object defines the import path prefixes used in your component files. These must match your tsconfig.json path mappings.
{ "aliases": { "components": "@/components/", "utils": "@/utils/", "hooks": "@/hooks/", "styles": "@/styles/" } }
| Property | Description |
|---|---|
components | Import alias for component files (e.g., @/components/, @workspace/ui/components/) |
utils | Import alias for utility functions (e.g., @/utils/, ~/lib/utils/) |
hooks | Import alias for React hooks (e.g., @/hooks/) |
styles | Import alias for style files (e.g., @/styles/) |
app | Import alias for @/app/ imports (e.g., @workspace/web/app/) |
src | Fallback alias for any other @/ import that none of the keys above cover (e.g., ~/) |
Important: Aliases must be valid tsconfig path aliases, not relative paths. The CLI uses your tsconfig.json to resolve these aliases to actual filesystem locations.
examples
The examples property specifies where example page files should be installed. This is useful when working in a monorepo where your web app is in a different directory.
{ "examples": "../../apps/web" }
version
The version property pins the component library version the CLI pulls ("7" or "8"). It is optional and defaults to "8". The upgrade command sets it to "8" when a migration completes. See Version support.
{ "version": "7" }
The CLI reads only aliases, examples and version; any other keys are ignored.
How aliases work
When you add a component, the CLI performs two key operations using your aliases:
1. Import statement transformation
The CLI rewrites import statements in component code to match your aliases:
// Original component code import { Button } from "@/components/base/buttons/button"; import { cx } from "@/utils/cx"; // After transformation (if your alias is @workspace/ui/) import { Button } from "@workspace/ui/components/base/buttons/button"; import { cx } from "@workspace/ui/utils/cx";
2. File path resolution
The CLI uses your tsconfig.json paths to determine where to place files on disk:
// tsconfig.json { "compilerOptions": { "paths": { "@workspace/ui/*": ["./packages/ui/src/*"] } } }
With the above config, a component with path components/base/button.tsx would be installed to ./packages/ui/src/components/base/button.tsx.
Alias requirements
Critical: Aliases in components.json must be valid tsconfig path aliases. Relative paths like ../../components will not work correctly.
Why relative paths don't work
The CLI uses the tsconfig-paths library to resolve aliases to filesystem locations. This library only understands aliases defined in your tsconfig.json paths configuration.
| Alias Format | Works? | Reason |
|---|---|---|
@/components/ | Yes | Resolved via tsconfig paths |
@workspace/ui/ | Yes | Resolved via tsconfig paths |
~/components/ | Yes | Resolved via tsconfig paths |
../../components/ | No | Cannot be resolved by tsconfig-paths |
/absolute/path/ | No | Cannot be resolved by tsconfig-paths |
Correct setup
To use custom aliases, you must configure both your tsconfig.json and components.json:
Configure tsconfig.json
Add your path mappings to tsconfig.json:
{ "compilerOptions": { "baseUrl": ".", "paths": { "@workspace/ui/*": ["./packages/ui/src/*"] } } }
Configure components.json
Reference the same aliases in components.json:
{ "aliases": { "components": "@workspace/ui/components/", "utils": "@workspace/ui/utils/", "hooks": "@workspace/ui/hooks/", "styles": "@workspace/ui/styles/" } }
Add components
Now the CLI will correctly resolve paths and transform imports:
npx untitledui@latest add button
Example configurations
Standard Next.js project
{ "aliases": { "components": "@/components/", "utils": "@/utils/", "hooks": "@/hooks/", "styles": "@/styles/" } }
With corresponding tsconfig.json:
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] } } }
Monorepo with shared UI package
{ "aliases": { "components": "@workspace/ui/components/", "utils": "@workspace/ui/utils/", "hooks": "@workspace/ui/hooks/", "styles": "@workspace/ui/styles/" }, "examples": "../../apps/web" }
With corresponding tsconfig.json:
{ "compilerOptions": { "baseUrl": ".", "paths": { "@workspace/ui/*": ["./packages/ui/src/*"] } } }
Vite project with custom alias
{ "aliases": { "components": "~/components/", "utils": "~/lib/", "hooks": "~/hooks/", "styles": "~/styles/" } }
With corresponding tsconfig.json:
{ "compilerOptions": { "baseUrl": ".", "paths": { "~/*": ["./src/*"] } } }
FAQs
Please refer to our frequently asked questions page for more.
No, it's optional. Without it, the CLI detects your project structure from tsconfig.json and prompts you for any missing information, such as where to add components.
Each alias must match a path mapping in your tsconfig.json. The CLI resolves aliases with tsconfig-paths, so it needs tsconfig path aliases like @/components/; relative paths like ../../components/ and absolute paths can't be resolved.
In the directory where you run the CLI, usually your project root. If you run add with --dir, the CLI looks for it in that directory instead. For monorepos, place it in the package directory where you want to install components.
Only the upgrade command does: after a run without --dry-run, it sets version to "8" in your existing components.json. It never creates the file, and no other command modifies it.
Put the Untitled UI settings (aliases, examples, version) in an untitledui.json file instead. The CLI recognizes a shadcn/ui components.json and doesn't take its aliases from it, and an untitledui.json always takes priority when present.
Set up path mappings in your tsconfig.json (e.g., "@workspace/ui/*": ["./packages/ui/src/*"]), then reference those same aliases in your components.json. See the monorepo guide for detailed instructions.
Yes. Set components, utils, hooks and styles separately, plus app for @/app/ imports and src as a fallback for any other @/ import. Each one is resolved independently through your tsconfig.json paths.