lpm add
Copy source files from a package into your project (shadcn-style).
lpm add <package>lpm add extracts a package's source files into your project rather than installing it as a runtime dependency. Think shadcn-ui style: the code lands in your repo, you own it, you edit it.
lpm install is the runtime-dependency command. lpm add is the source-delivery command. The two are not aliases.
Works with any registry the resolver can reach — lpm.dev, npmjs.org, or a .npmrc-declared private registry. Anything that ships a tarball is fair game.
Examples
lpm add @lpm.dev/owner.ui-kit # add an lpm.dev package
lpm add @lpm.dev/owner.ui-kit@1.2.0 # add a specific version
lpm add @lpm.dev/owner.ui-kit?component=dialog # add only one component
lpm add lodash.merge # add an npm package's source
lpm add @my-co/internal --path ./src/vendor # custom destination
lpm add my-pkg --dry-run # preview without writingHow it works
- Resolves the spec against the appropriate registry.
- Downloads the tarball into a temporary file and extracts it to a tempdir. Unlike
lpm install, the tarball is not persisted to~/.lpm/store/—lpm addis a copy-and-discard flow. Re-runninglpm addre-downloads. - Picks where to put the files. With
--path, honors it. Without--pathin a TTY (and not--yes/--json), prompts for an install directory. Non-interactive (--yes,--json, or non-TTY) requires--pathfor simple-path packages (nolpm.config.json); config-aware packages auto-detect from their declared ecosystem. - Copies the source into the destination, prompting on conflicts.
- If the package declares an
lpm.config.json, runs the package's configured install steps (component selection, alias rewrites, dep installation). If not, it's a plain source copy and you handle dependencies yourself.
lpm add does not auto-install bare imports it discovers in the copied source. It will surface them at the end of the run so you can add them yourself.
Human output is structured around the source-copy flow:
› Downloading source package source-pkg@1.0.0
› Detecting project structure
Framework: Vite
Install path: src/components
Import alias: @/src/components/
✓ Files copied
+ Foo.tsx
› Installing declared dependencies
+ lucide-react@^0.400.0
✓ Done · added 1 file and 1 dependency in 486msFile conflicts use a slim warning line (! File exists: ...) before the interactive choice.
Config-aware vs simple copy
A package becomes "config-aware" by shipping an lpm.config.json at the tarball root. That file declares components, dependencies to auto-install, import aliases, and editor integration hints. Without it, lpm add is a plain source copy — useful for any tarball, not just lpm.dev packages.
Swift packages
For Swift packages, prefer lpm install — it's the right command for SPM dependencies (resolves through the SE-0292 registry and edits Package.swift). lpm add still works for Swift sources today and respects --target for Xcode-target wiring, but consider it the legacy path for that ecosystem.
Authoring config-aware packages: lpm.config.json
Ship lpm.config.json at the root of your tarball to control how lpm add extracts your package. With the file present, lpm add becomes a configurable installer — interactive prompts, conditional file copying, conditional dependency injection, import-path rewriting.
{
"$schema": "https://lpm.dev/schemas/lpm.config.json",
"ecosystem": "js",
"importAlias": "@/",
"configSchema": {
"component": {
"type": "select",
"label": "Which component?",
"options": ["dialog", "popover"],
"default": "dialog",
"required": true
},
"withTests": { "type": "boolean", "label": "Include tests?", "default": false }
},
"files": [
{ "src": "src/dialog/**", "dest": "dialog", "include": "when",
"condition": { "component": "dialog" } },
{ "src": "tests/**", "dest": "__tests__", "include": "when",
"condition": { "withTests": true } }
],
"dependencies": {
"withTests": { "true": ["vitest"] }
}
}The full schema reference — every field, every value type, every default — lives at lpm.config.json. The published JSON Schema at https://lpm.dev/schemas/lpm.config.json drives editor autocomplete (add $schema as shown above).
Pre-answering prompts
Prompts can be pre-answered from the CLI by appending ?key=value&key=value to the package spec:
lpm add @lpm.dev/owner.ui-kit?component=dialog&styling=pandaInline values bypass the prompt entirely. With --yes, prompts are skipped and defaultConfig / configSchema.<field>.default fill in any required fields the user didn't supply.
Behavior matrix
| State | What lpm add does |
|---|---|
No lpm.config.json | Plain copy of the package's source. No prompts. No auto-install. Surfaces bare imports for you to install yourself. |
lpm.config.json present, TTY | Prompts for every configSchema key not already inlined; copies per files[] rules; installs dependencies matching the chosen values. |
lpm.config.json present, --yes / --json / non-TTY | Skips prompts; uses defaults for required fields; copies per matching rules; installs deps. |
Prerequisites
If the source package declares dependencies (config-driven or via its own package.json), your project must already have a package.json. lpm add runs a preflight check before copying any files and exits early with a remediation hint if the manifest is missing — there's nowhere for the dep entries to land otherwise, and we'd rather fail loudly than copy source files you can't import from.
$ lpm add @author/ui-kit
error: this source package declares dependencies, but the project has no
`package.json` to record them in.
Run `lpm init` (or `npm init -y`) first to create a manifest, then
re-run `lpm add`.
To copy the source files without installing the declared dependencies,
pass `--no-install-deps` and resolve the imports yourself.If you only want the source files (and you'll handle the imports yourself), pass --no-install-deps to skip the preflight and let the copy proceed without touching package.json.
Flags
| Flag | Effect |
|---|---|
--path <DIR> | Target directory (overrides interactive prompt and auto-detection) |
-y, --yes | Skip interactive prompts, use defaults |
--force | Overwrite existing files without prompting |
--dry-run | Show what would be done without writing anything |
--no-install-deps | Skip dependency installation after copy (for config-aware packages) |
--no-skills | Skip skills auto-install |
--no-editor-setup | Skip editor auto-integration |
--pm <NAME> | Package manager for dep installation (lpm, npm, pnpm, yarn, bun, auto; default lpm) |
--alias <ALIAS> | Import alias prefix (e.g., @/components) — overrides auto-detection |
--target <NAME> | Swift SPM target name (Swift packages only) |
--no-engine-strict | Skip the engines.lpm / engines.node preflight (see lpm install). The check runs before any manifest mutation, so a constraint violation can't leave the project half-modified. |
Plus the global flags.
See also
lpm remove— undo anlpm addlpm install— install runtime dependencies- Registries — how packages route
- Swift Package Registry — SE-0292 design and the
lpm install-preferred path for Swift