package.json Imports

Purpose and Scope

Package imports are the shadcn/ui path-alias option for teams that want private import specifiers declared in the project package manifest instead of TypeScript path mappings. The documented workflow applies to app workspaces such as Next.js, Vite, and TanStack Start, and it also covers monorepos where some files live in an app while shared components, hooks, styles, and utilities live in a workspace package. The practical reader problem is consistency: the CLI needs to know where to write generated files, TypeScript needs to resolve the same specifiers, and application code needs stable imports after components are installed or registry items are applied.

Sources: apps/v4/content/docs/(root)/package-imports.mdx, apps/v4/content/docs/(root)/monorepo.mdx

The important distinction is that package imports are private specifiers beginning with a hash character. They are configured under the imports field of a package manifest and are meant for files inside that same package. In a single app, this can replace compiler path aliases for shadcn/ui install targets. In a monorepo, the pattern is more deliberate: use package imports for files that belong to the current workspace, and use package exports from a shared package when another workspace consumes shared user interface code. That split keeps local generated files local while letting app code import reusable components from the workspace package.

Sources: apps/v4/content/docs/(root)/package-imports.mdx

Relevant Source Files

  • apps/v4/content/docs/(root)/package-imports.mdx — Primary user-facing guide for configuring package imports in app workspaces and monorepos, including package manifest, TypeScript, and components configuration examples.
  • apps/v4/content/docs/(root)/monorepo.mdx — Companion guide that explains how the CLI installs components across app and shared UI workspaces and why each workspace needs its own components configuration.
  • packages/shadcn/src/utils/alias.ts — CLI utility code that derives shadcn/ui alias defaults for user interface components, libraries, hooks, and utilities from a chosen components alias.

Core Primitives

A package import mapping is the first primitive. It declares private roots such as component, library, and hook locations in the package manifest. A TypeScript resolver setting is the second primitive. The docs call for modern TypeScript with bundler-style module resolution and package import resolution enabled so the compiler understands those private roots. The third primitive is the shadcn/ui components configuration, whose aliases must use the same roots. The fourth primitive appears in monorepos: package exports from the shared user interface workspace, which make shared files addressable from app workspaces through the workspace package name.

Sources: apps/v4/content/docs/(root)/package-imports.mdx, apps/v4/content/docs/(root)/monorepo.mdx

The components configuration is not just documentation for humans. It tells the CLI how and where to install components, hooks, utilities, and related registry files. The monorepo guide makes this requirement explicit for every workspace: a package manifest tells the package manager how to install dependencies, while the components configuration tells the shadcn CLI how to place files and rewrite imports. That means the package import roots and component aliases must describe the same project layout. If they drift apart, generated code may compile in one workspace but point at the wrong component family or utility location in another.

Sources: apps/v4/content/docs/(root)/monorepo.mdx

App Workspace Configuration

For a normal app workspace, begin with the package manifest. The documented shape maps component files, library files, and hook files to source-directory targets. If the app does not use a source directory, the guide says to remove that path segment from the targets rather than inventing a different alias model. After the manifest is updated, enable package import resolution in TypeScript. With that setup, the docs state that compiler path mappings are not needed for these aliases. The final step is to mirror the same roots in the shadcn/ui components configuration so generated files and rewritten imports use the package-import names.

Sources: apps/v4/content/docs/(root)/package-imports.mdx

package.json
{
  "imports": {
    "#components/*": "./src/components/*.tsx",
    "#lib/*": "./src/lib/*.ts",
    "#hooks/*": "./src/hooks/*.ts"
  }
}
tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "bundler",
    "resolvePackageJsonImports": true
  }
}
components.json
{
  "aliases": {
    "components": "#components",
    "ui": "#components/ui",
    "lib": "#lib",
    "hooks": "#hooks",
    "utils": "#lib/utils"
  }
}

Two alias details are worth preserving when you adapt the example. The user interface alias points at the component root plus the user interface subfolder, and it is still covered by the broader component import pattern in the manifest. The utilities alias points at the library root plus the utility module name, and it is covered by the broader library import pattern. In other words, the package manifest usually needs wildcard roots, while the components configuration may name more specific destinations that the CLI uses when installing files or rewriting imports.

Sources: apps/v4/content/docs/(root)/package-imports.mdx

Monorepo Flow

In a monorepo, run the add command from the app path, but expect the CLI to understand both the app workspace and the shared user interface workspace. The monorepo guide describes a generated project with web and user interface workspaces, backed by Turborepo. When a shared component such as a button is added, it is installed under the shared user interface package and app imports are updated to use that package. When a larger block includes app-specific files, the shared primitives can land in the shared package while the app-specific component stays under the app workspace.

Sources: apps/v4/content/docs/(root)/monorepo.mdx

The package imports guide refines that monorepo behavior. The app workspace can keep private imports for its local components, libraries, and hooks, while depending on the shared user interface package for shared files. Its components configuration can therefore combine local hash-based aliases with workspace-package aliases. The shared package also has its own private imports for files inside that package, but it additionally declares exports so other workspaces can import its global styles, components, libraries, and hooks. This is the critical boundary: imports are for inside a package, exports are for consumers outside that package.

Sources: apps/v4/content/docs/(root)/package-imports.mdx, apps/v4/content/docs/(root)/monorepo.mdx

apps/web/components.json
{
  "aliases": {
    "components": "#components",
    "ui": "@workspace/ui/components",
    "lib": "#lib",
    "hooks": "#hooks",
    "utils": "@workspace/ui/lib/utils"
  }
}
packages/ui/package.json
{
  "name": "@workspace/ui",
  "private": true,
  "imports": {
    "#components/*": "./src/components/*.tsx",
    "#lib/*": "./src/lib/*.ts",
    "#hooks/*": "./src/hooks/*.ts"
  },
  "exports": {
    "./globals.css": "./src/styles/globals.css",
    "./components/*": "./src/components/*.tsx",
    "./lib/*": "./src/lib/*.ts",
    "./hooks/*": "./src/hooks/*.ts"
  }
}

System-to-Code Mapping

The alias utility in the CLI shows how default aliases are derived during initialization. The exported initializer receives a components alias and optional existing aliases. It preserves existing values when present, derives the library alias first, and then derives user interface, hook, and utility aliases from the component root. The utility alias deliberately follows the library alias rather than the component alias, which matches the documentation examples where utilities are reached through the library root. This implementation detail explains why choosing a clear component root during setup affects multiple generated aliases.

Sources: packages/shadcn/src/utils/alias.ts

The derivation rules also expose important edge cases. If the components alias ends with a components segment, the CLI can swap that tail for library or hooks siblings. This handles common forms such as aliases rooted at a project shortcut or a hash-based package import root. If the alias is exactly the word components, the sibling names become simple library and hooks aliases. If the input does not match a supported components-tail shape, the helper returns an empty derived alias for those siblings, while utilities can fall back through the default utility path. These rules favor predictable sibling folders over guessing arbitrary layouts.

Sources: packages/shadcn/src/utils/alias.ts

Compact Reference

AreaConcrete setting or functionWhat it controls
App manifestimports with component, library, and hook wildcard rootsPrivate package-local specifiers for generated files
TypeScriptmoduleResolution set to bundlerResolver mode expected by the docs for package imports
TypeScriptresolvePackageJsonImports set to trueEnables resolution of package manifest imports
components configurationaliases for components, ui, lib, hooks, and utilsCLI install targets and rewritten import names
Monorepo packageexports for styles, components, libraries, and hooksPublic entry points consumed by other workspaces
CLI utilitygetInitAliasDefaultsBuilds initial alias defaults while preserving existing aliases
CLI utilityderiveAliasFromComponentsProduces sibling aliases for user interface, library, hooks, and utilities

Use this page when deciding whether a project should rely on package imports instead of TypeScript path mappings. For a single app, configure the manifest, TypeScript, and components configuration together before adding components. For a monorepo, decide which files are app-local and which belong in the shared user interface package, then make the app aliases and shared package exports reflect that boundary. Next, read the Monorepos page for the install workflow, the components.json page for every configuration field, and the CLI page for the commands that consume these settings.

Sources: apps/v4/content/docs/(root)/package-imports.mdx, apps/v4/content/docs/(root)/monorepo.mdx, packages/shadcn/src/utils/alias.ts