Installing from a URL is the same command as installing from the official registry, with one argument changed. Most of what goes wrong is not conceptual: it is a shell, a quote, an expired key or a file that already exists. This is that list.
The command
Any registry that serves item JSON works the same way. The URL points at one item; the CLI reads its files, its npm dependencies and its registry dependencies, and writes everything into the paths your components.json aliases define. The CLI guide covers that resolution in full.
Quote the URL
The first thing to check, and the cause of most reports. An unquoted URL containing & is two shell commands, and the error you get talks about a missing file rather than about the ampersand. Quote it, every time, in every shell.
The related one: $API_KEY_21ST only expands inside double quotes. In single quotes it is sent literally, and the registry answers with an authentication error that looks like a bad key.
The failures, in the order they happen
401 or 403. The key is missing, expired, or scoped to something else. Print the variable before blaming the registry: echo $API_KEY_21ST. In CI, check that the secret is exposed to the job rather than only to the environment.
404 on the item. The item was renamed or removed. Because add copies rather than links, a registry can rename an item without breaking anyone who already installed it, which means stale install commands in blog posts and READMEs are common.
Nothing happens. The file already exists, so the CLI left it alone. That is the correct behaviour and it is why re-adding an edited component appears to do nothing. --overwrite replaces it, and your edits with it, so commit first.
A missing import after install. The item declared a file it did not declare a dependency for. Nothing on your side fixes it; install the missing package by hand and tell the registry's author.
The wrong folder. The item's type decides which alias it lands in, so a hook typed as registry:ui ends up in your components directory. --path overrides it for one install.
In CI and in scripts
Three flags turn an interactive command into a scriptable one: --yes to accept prompts, --silent to quiet the output, and --cwd to target a package in a monorepo, which the monorepo guide covers.
Worth saying plainly: installing components during a build is usually the wrong shape. The whole point of the copied-source model is that the files are committed, reviewed and diffable. A CI job that fetches them at build time gives up the review and adds a network dependency to your deploy.
Reading what arrived
The install is not the end of the task. Before committing, look at three things: the diff, so you know exactly which files were written; the imports, since the component may have brought primitives you already had under different names; and the tokens, because someone else's radius and spacing are easier to normalise now than after three more components copy the pattern.
Where else to look
The honest list, because the answer is not always us:
| Source | Best for | Trade-off |
|---|---|---|
| shadcn CLI docs | The canonical flags and error behaviour | Official registry examples only |
| 21st MCP | Installing from the editor, with the preview before the file | Installs require a membership |
| Copying the file by hand | One component, no CLI, total control | You resolve every dependency yourself |
| The registry directory | Finding the URL in the first place | Only registries that publish an index |
Taking one
That key comes from your 21st account, and installs require a membership. Set API_KEY_21ST once in your shell and the command works for anything in the catalogue.
Browse the registry directory →
Frequently asked
- Why do I get a 401 installing from a registry?
- The key is missing, expired or scoped elsewhere. Print the variable to check it is set, and remember that a single-quoted URL sends the variable name literally rather than its value. In CI, confirm the secret is exposed to that specific job rather than only to the environment.
- Should CI install components from a registry?
- Usually not. The point of the copied-source model is that the files are committed, reviewed and diffable. Fetching them at build time gives up the review and adds a network dependency to your deploy. Commit the component and let CI build what is in the repository.
- Why did the component land in the wrong folder?
- Because the item's type decides which alias it uses: registry:ui goes to the UI alias, registry:hook to hooks, and so on. If a registry typed a hook as a UI item, it lands in your components directory. Use --path to override it for that install.
- What should I check before committing an installed component?
- The diff, so you know which files were written; the imports, since the component may have brought primitives you already have under different names; and the tokens, because adapting someone else's radius and spacing is cheap now and expensive after other components copy the pattern.



