Skip to content
touchcn
Esc
navigateopen⌘Jpreview
On this page

CLI

The touchcn CLI — command reference, the touchcn.json config, how updates work, using it with the shadcn CLI, and hosting your own registry.

The touchcn CLI distributes components as source: they are copied into your project instead of imported from a package. It is framework-awareangular, react, and vue are supported, and touchcn.json’s framework field selects which registry your project reads from and where files land.

Command Purpose
init Write a touchcn.json into your project.
add Copy components (and blocks) from the registry into your project.
diff Show which installed components have registry updates.
update Apply registry updates, three-way merging your local edits.
build Build a distributable registry from sources (registry authors).

Commands

init

Writes a touchcn.json into your project and installs @touchcn/cli as a devDependency, so every later command is a plain npx touchcn … (npx resolves the locally installed touchcn bin — only this first command needs the scoped package name). Idempotent — refuses to overwrite an existing config without --force. Installing the engine packages and adding the Tailwind CSS import are printed as next steps, not applied.

npx @touchcn/cli init                    # Angular (default)
npx @touchcn/cli init --framework react
npx @touchcn/cli init --framework vue
Option Alias Description
--framework Target framework, angular (default), react, or vue. Sets the framework field and the per-framework default paths.components.
--registry -r Registry URL or local directory path to use instead of the official registry.
--force -f Overwrite an existing touchcn.json.
--no-install Skip installing @touchcn/cli as a devDependency.

add

Reads touchcn.json (walking up from the current directory), fetches each item from the registry’s framework subdirectory, resolves registryDependencies recursively, and copies the files into paths.components.

npx touchcn add button              # a single component
npx touchcn add bottom-sheet dialog # several at once
npx touchcn add --all               # everything: every component and every block
npx touchcn add button --overwrite  # replace existing files
Option Alias Description
--all -a Add every component and every block in the registry.
--components Add every component in the registry.
--blocks -b Add every block in the registry.
--overwrite -o Overwrite existing files (otherwise they are skipped with a warning).
--no-install Skip the automatic dependency installation.

Each component’s npm dependencies — including its @radix-ui/* packages on React, or reka-ui on Vue — are installed automatically using your project’s package manager (detected from the lockfile: npm, pnpm, yarn, or bun). Pass --no-install to skip installation and get the install command printed instead.

add also records what it installed in touchcn.json — the provenance that powers updates.

Blocks

Blocks are pre-composed, page-level screens. add handles them exactly like components — by name — the only difference is where the files land: block files are copied to src/app/components/blocks/<name>/ (Angular) or src/components/blocks/<name>/ (React and Vue), and each block’s component dependencies are resolved and copied into paths.components just like any other registryDependencies.

Blocks import the components they compose through the @/components/ui/<name> alias, so your project must resolve @ to your source root — see the Blocks overview for the one-time alias setup.

diff

Reports which installed components have a newer version in the registry, and how your local files compare to it — see How updates work for the file statuses it prints.

npx touchcn diff                    # every installed component
npx touchcn diff button             # a single component
npx touchcn diff --verbose          # also print a unified diff per changed file
Option Alias Description
--verbose -v Append a unified diff (installed version → current version) per changed file, so you can review upstream changes before applying them.

update

Applies registry updates to your installed components, preserving your local edits through a three-way merge — see How updates work for the merge behavior and conflict resolution.

npx touchcn update                  # every component with an update
npx touchcn update button           # a single component (and its updated deps)
npx touchcn update --dry-run        # show what would change, write nothing
Option Alias Description
--dry-run Report every action without touching files or touchcn.json.

touchcn.json

The config init writes and every other command reads. add, diff, and update find it by walking up from the current directory.

{
  "$schema": "https://touchcn.dev/schema/touchcn.json",
  "registry": "https://raw.githubusercontent.com/capawesome-team/touchcn/main/registry/dist",
  "framework": "react",
  "paths": { "components": "src/components/ui" }
}
Field Description
registry Where components are fetched from — a URL or a local directory path (useful for monorepos and testing).
framework angular, react, or vue. Selects the registry’s framework subdirectory and the copy targets.
paths.components Project-relative directory that add copies components into.
installed Written by add, not by hand: per-component provenance (installed version + a content hash per file) that diff and update read.

paths.components is yours to change: set it to any project-relative directory (for example src/app/ui) and every subsequent add copies components there. Components that were added before the change stay where they are — move them manually if needed.

How updates work

Because components are copied source, upstream fixes don’t arrive through npmdiff and update are how they reach you. You own the code; these two commands are what keeps ownership from meaning “frozen at install time”.

The mechanism is the installed provenance map: for every component, add records the registry version it copied and a hash of each file as installed. That baseline is what lets the CLI tell your edits apart from upstream changes.

File statuses

Per component, diff prints one of:

  • up to date — the installed version equals the registry version.
  • update available <from> → <to> — a newer version exists; each file is then classified:
    • pristine — the local file is byte-identical to the version you installed (safe to overwrite).
    • modified — you edited the file locally (a three-way merge will run on update).
    • new file — the newer version adds a file you don’t have yet.
    • missing — a tracked file was deleted locally.
  • unknown (added before provenance tracking — re-add to enable updates) — the component isn’t in the installed map. Re-run add --overwrite for it to start tracking updates.

The three-way merge

For each file, update does one of:

  • pristine → overwrite with the current registry content.

  • modified → three-way merge: the version you installed is the common ancestor (base), your file is local, the registry’s new file is registry. Non-overlapping changes merge automatically. Overlapping changes are written into the file with standard conflict markers — there is no .new sibling file; the conflict lives where you resolve it:

    <<<<<<< local
    your local lines
    ||||||| base
    the version you installed
    =======
    the incoming registry lines
    >>>>>>> registry

    Resolve a conflict by editing the file and deleting the marker lines. update exits non-zero when any file has conflicts and lists them.

A component’s updated registryDependencies are resolved recursively and updated too, exactly like add. After updating, the recorded baseline for each file becomes the new registry content — so a file left with unresolved conflict markers shows up as modified on the next diff, and the next merge uses the version you just updated to as its base.

Use with the shadcn CLI

The touchcn registry is also a valid shadcn registry, so you can pull components with npx shadcn add instead of the touchcn CLI if you already have shadcn in your project. The touchcn CLI remains the first-class path — this is a convenience for existing shadcn setups.

Register the touchcn registry under a namespace in your project’s shadcn components.json via the registries map:

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "registries": {
    "@touchcn": "https://raw.githubusercontent.com/capawesome-team/touchcn/main/registry/dist/react/{name}.json"
  }
}

Then add components by their namespaced name:

npx shadcn add @touchcn/button
npx shadcn add @touchcn/datepicker   # pulls its picker dependency too
npx shadcn add @touchcn/login        # a block — writes every composed file

shadcn resolves each item’s registryDependencies (emitted namespaced, e.g. @touchcn/picker) through the same map, and writes every file to its explicit target.

What shadcn’s CLI does not do, and why the touchcn CLI stays first-class:

  • No framework awareness. It only reads the React registry; there is no --framework switch for the Angular or Vue sets.
  • No diff / update. shadcn copies files once; it has no three-way merge to reconcile your local edits with upstream fixes. touchcn diff and touchcn update (and the installed provenance in touchcn.json they rely on) are touchcn-CLI only.

Hosting your own registry

Everything below is for registry authors — teams distributing their own component set through the touchcn CLI. If you only consume the official registry, you’re done.

build

Builds a distributable registry from a directory of component sources — the same mechanism the touchcn repository uses to publish its own registry. Each component folder holds a registry.json manifest plus its sources; the build inlines file contents, derives npm dependencies from the actual imports (warning when a manifest disagrees), and emits one JSON item per component plus an index.json listing. A blocks/ subdirectory is scanned too: each of its subfolders becomes a registry:block item (with a blocks/ file target) and is listed separately in the index, so the bulk selectors (--components, --blocks) can tell the two apart.

touchcn build --input registry/angular --output registry/dist
touchcn build --input ./src --output dist --framework react
Option Alias Description
--input -i Source registry directory (required).
--output -o Output base directory (required); a <framework> subdirectory is appended automatically.
--framework Target framework; inferred from the input directory name when omitted.
--strict Fail on version drift (content changed without a version bump) — use in CI.

Serve the output directory over any static URL and point touchcn.json’s registry field at it — every CLI command then works against your registry.

Versioned registry history

Every source registry.json carries a version (starting at 0.1.0). Alongside the current <name>.json, build emits an immutable history copy <name>@<version>.json in the same directory, and stamps the version onto each index.json entry. Rebuilding the same version overwrites only its own history file (idempotent); bumping the version adds a new history file and never deletes older ones. This history is what makes three-way updates possible — update fetches the exact version you installed as the common ancestor for merging. Commit the generated history files together with the current items.

build guards the one discipline this scheme requires: changing an item’s sources without bumping its version. If content changed but the version did not, build prints a loud warning (consumers would see “up to date” while the served item — and their future merge base — silently mutates). Pass --strict to fail instead and leave the existing history file untouched.

Last updated on August 11, 2026

Was this page helpful?