Usage
August 16, 2026 · View on GitHub
This guide covers the degit CLI and ESM API.
Quick start
Download the default branch of a GitHub repo to the current directory:
degit user/repo
Download to a new folder:
degit user/repo my-new-project
Download only specific files:
degit user/repo my-project --files README.md,src/index.ts
Use a specific ref:
degit user/repo#v1.0.0
Installation
npm install -g degit
degit requires Node.js 20 or later.
CLI reference
Basic syntax
degit <src>[#ref] [<dest>] [options]
src is the repository to copy. dest is the directory to extract into; if omitted, degit uses the current directory.
Supported sources
degit supports GitHub, GitLab, Bitbucket, and Sourcehut.
GitHub
degit user/repo
degit github:user/repo
degit https://github.com/user/repo
degit git@github.com:user/repo
GitLab
degit gitlab:user/repo
degit https://gitlab.com/user/repo
degit git@gitlab.com:user/repo
For a self-hosted GitLab instance, use the gitlab:// protocol:
degit gitlab://git.example.com/user/repo
Bitbucket
degit bitbucket:user/repo
degit https://bitbucket.org/user/repo
degit git@bitbucket.org:user/repo
Sourcehut
degit git.sr.ht/user/repo
degit https://git.sr.ht/user/repo
degit git@git.sr.ht:user/repo
Specify a tag, branch, or commit
Append #ref to any source:
degit user/repo#dev # branch
degit user/repo#v1.2.3 # release tag
degit user/repo#1234abcd # commit hash
If you omit the ref, degit resolves the repository's default branch.
Create a new folder
If dest is omitted, degit extracts into the current directory. The directory must be empty unless you use --force. Use --repo-name or -r to extract into a directory named after the repository instead:
degit user/repo my-new-project
degit -r user/repo
Clone a subdirectory
Add the subdirectory to the source:
degit user/repo/subdirectory
You can also paste a full GitHub URL:
degit https://github.com/user/repo/tree/main/subdirectory
For GitLab nested groups, degit first tries the two-segment user/repo interpretation, then falls back to treating the path as a nested group.
Clone specific files
To keep only specific files or directories, use --files or -F. Separate paths with commas or repeat the flag:
degit user/repo my-project --files README.md,src/index.ts
degit user/repo my-project -F README.md -F src/index.ts
Missing or out-of-bounds paths are skipped with a warning; if no requested paths resolve, the whole destination is kept.
Options
| Option | Short | Description |
|---|---|---|
--help | -h | Show help text. |
--version | -V | Show the version. |
--cache | -c | Only use the local cache; do not hit the network. |
--force | -f | Allow cloning into a non-empty destination directory. |
--files <paths> | -F <paths> | Keep only the listed files or directories. |
--repo-name | -r | Clone into a directory named after the repository. |
--verbose | -v | Print extra progress information. |
--mode <mode> | -m | tar (default) or git. --mode=git is accepted for compatibility but prints a deprecation notice. |
Run degit --help to see the published help text.
Caching
degit caches downloaded tar snapshots in a platform-appropriate directory:
- Linux/BSD:
$XDG_CACHE_HOME/degitor~/.cache/degit - macOS:
~/Library/Caches/degit - Windows:
%LOCALAPPDATA%\degitor~/AppData/Local/degit
By default, degit resolves the latest ref from the network and falls back to the cached version if the network is unreachable. Use --cache to skip the network request and only use a local cached copy.
Private repositories
Private repositories are handled automatically. degit tries the HTTPS tarball path by default and falls back to SSH cloning when it cannot fetch or extract a snapshot. SSH/private repositories still require git on your PATH.
HTTPS proxying
If you set the https_proxy environment variable, degit uses it when fetching tar archives.
Aliases
Save an alias:
degit alias github:user/repo myRepo
Use it:
degit myRepo
Manage aliases:
degit unalias myRepo
degit ls # list saved aliases
Aliases are stored in aliases.json inside the degit cache directory.
Interactive mode
Running degit with no arguments starts an interactive picker. It prompts for a source, destination, and whether to use the cache. If the destination is not empty, it asks whether to overwrite.
ESM API
degit can also be used inside a Node script.
Basic example
import degit from 'degit';
const emitter = degit('user/repo', {
cache: true,
force: true,
verbose: true,
});
emitter.on('info', (info) => {
console.log(info.message);
});
emitter.on('warn', (info) => {
console.warn(info.message);
});
await emitter.clone('path/to/dest');
console.log('done');
Constructor options
| Option | Type | Description |
|---|---|---|
aliases | Record<string, string> | Alias map used when resolving src. |
cache | boolean | Only use local cache; do not hit the network. |
fetch | FetchFn | Custom (url, dest, proxy?) => Promise<void> download function. |
files | string[] | Keep only the listed files or directories. |
force | boolean | Allow cloning into a non-empty destination. |
git | GitClient | Custom git client for ref resolution and fallback cloning. |
mode | 'tar' | 'git' | Clone mode. tar is the default. |
verbose | boolean | Print extra progress information. |
Events
The returned emitter exposes two event channels:
info— progress and success messages.warn— non-fatal issues, such as skipped paths or fallback notices.
Event objects include at least message. They may also include code, dest, repo, url, ref, and subdir.
degit.json actions
After the initial clone, degit looks for a degit.json file at the top level of the destination and runs the actions it defines. A JSON Schema is available at schemas/degit.schema.json for editor autocompletion and validation.
clone
Clone another repository into the destination, preserving existing files:
[
{
"action": "clone",
"src": "user/another-repo"
},
{
"action": "clone",
"src": "user/another-repo",
"files": ["README.md", "src/index.ts"]
}
]
The cloned repo can define its own degit.json actions.
search_replace
Replace every match of a regular expression in the listed files. The replacement field is the name of an environment variable; its value is used as the replacement string.
[
{
"action": "search_replace",
"files": ["package.json", "README.md"],
"pattern": "\\{\\{project_name\\}\\}",
"replacement": "PROJECT_NAME"
}
]
files can be a single path or an array of paths. Paths are resolved relative to the destination; paths outside the destination are skipped.
remove
Remove one or more files:
[
{
"action": "remove",
"files": ["LICENSE"]
}
]
files entries support glob patterns, so you can remove a whole class of files without listing each one. Because glob patterns can match more files than intended, they are only processed when allowGlobs is set to true. Matches outside the destination are skipped.
[
{
"action": "remove",
"files": [".github/**/*.md"],
"allowGlobs": true
}
]
Why not just git clone --depth 1?
A few salient differences:
git cloneleaves a.gitfolder that belongs to the template, not your new project. You can easily forget to re-init the repository.degitcaches archives and can work offline after the first download.- Less to type (
degit user/repoversusgit clone --depth 1 ssh://git@github.com/user/repo). - Composable post-clone actions through
degit.json. - Built-in support for subdirectories, file filtering, and aliases.
See also
- README.md — project overview and quick start
- docs/ARCHITECTURE.md — repository architecture
- docs/CONTRIBUTING.md — contributing and development workflow
- assets/help.md — published CLI help text