CLI tool
unjs/giget avatar
unjs/giget

giget: one command to pull a template or a repository snapshot

✨ Download templates and git repositories with pleasure!

781 stars61 forksTypeScriptNOASSERTION

At a glance

What is it?
giget downloads project templates and repository subdirectories from GitHub, GitLab, Bitbucket and Sourcehut using a compact URI, without requiring a local git or tar installation, and it caches to disk for offline use. It suits tooling authors and CI setups that need a clean copy of a template rather than a clone with history.
Who is it for?
Use giget when you ship a starter template, a CLI that needs to produce a project skeleton, or a CI job that wants a clean copy of a repository subdirectory without git history and without a local git or tar binary. Do not use it when you need history, branches or pull requests, since it copies a snapshot rather than cloning a working repository, and treat the --force-clean and --shell flags as destructive or experimental respectively.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem giget solves is copying, not cloning

giget is a tool for downloading templates and git repositories, and the name of its own tagline gives away its scope: download templates and git repositories with pleasure.

The problem it addresses is not that cloning is hard. It is that cloning is the wrong operation in a number of common situations. When you scaffold a new project from a template you usually do not want the template's commit history, its branches, its pull request refs, or its .git directory, and you may not even have git installed on the machine running your setup script. The same is true for a CI job that needs one subdirectory of a large monorepo as a starting point.

The feature list in the README is a good summary of the design decisions. Zero dependency is the first one. Support for popular git providers out of the box covers GitHub, GitLab, Bitbucket and Sourcehut. There is a native git clone provider with sparse checkout for subdirectories, and a built-in and custom template registry. Fast cloning uses tarball gzip without depending on a local git or tar. It works online and offline with disk cache support, supports custom template providers programmatically, supports extracting with a sub directory, adds authorization support so private templates can be downloaded, and can optionally install dependencies after the clone using unjs/nypm.

The audience is therefore two groups: authors who publish templates and want a single command for their users, and engineers who need reproducible, cacheable project scaffolding.

The URI grammar: provider, repository, subdir and ref

The heart of the tool is a compact source syntax. The CLI takes a template argument that is either a name or a URI describing provider, repository, sub directory and branch or ref, and the programmatic API documents the same format as provider:repo[/subpath][#ref].

The examples in the README cover the range. A bare provider prefix works for each host, so gh:unjs/template targets GitHub and gitlab:unjs/template targets GitLab. A branch is selected with a hash, as in gh:unjs/template#dev. A subdirectory is selected with a slash, as in gh:unjs/template/test, which clones the test directory from the main branch.

The interesting case is a repository path with more than two segments, which happens with GitLab subgroups. There the subdirectory separator changes to a double colon, so the example is gitlab:group/subgroup/project::src/template, where the provider and group path are separated from the subdirectory by ::. Without that distinction a path like that would be ambiguous.

Two more forms exist. The git: prefix uses the local git clone provider rather than a host API, and an https: prefix accepts a tarball URL or a JSON metadata URL directly, for example a GitHub API tarball endpoint or a raw JSON file. That last form is what makes giget usable as a generic fetcher for resources that are not templates in the registry sense.

The default provider, when you do not specify one, is github, according to the option documentation for the programmatic API.

Two clone paths: tarball gzip and a native git provider

giget can obtain the same template in two different ways, and the difference is not an implementation detail, it is a behavioural choice.

The default path is a fast clone using tarball gzip without depending on a local git or tar. The provider asks the host for a tarball, giget unpacks it in JavaScript, and nothing needs to be installed on the machine. That is what makes the tool usable inside a minimal container or on a machine where the user has no git.

The alternative is the native git clone provider, marked in the feature list as native git clone provider with sparse checkout for subdirectories. Sparse checkout is how a git clone can deliver only one directory of a repository while still using the git protocol. The README lists git:unjs/template as the way to clone using local git over HTTPS, and the section on the git clone provider is where the requirements for that path would be documented.

The practical difference: the tarball path gives you a snapshot with no history and no working repository, while the git path gives you a real clone, which is why the git provider exists for cases where you want a working checkout rather than a template. The tarball path is the default because it is faster and has no external requirements.

There is also a third route for anything that is not a git repository at all, the https: form, which takes a tarball link or a JSON document directly.

The registry: name shortcuts and a first-come-first-served rule

The template registry is how a bare word such as nuxt becomes a concrete download. giget has a built-in HTTP registry system for resolving templates, which supports template name shortcuts and meta-data. The default registry is served from the unjs/giget/templates directory in the repository itself, and the template argument in the CLI examples shows it in use with npx giget@latest nuxt.

Adding a template to the built-in registry is a pull request that drops an entry into the templates directory. The README is explicit about the governance: slugs are added on a first-come first-served basis but this might change in the future. In other words, there is no review committee described, no naming policy, and no guarantee of permanence for a slug you rely on. If your template name matters to you, treat the registry as a convenience rather than a contract.

A custom registry is the supported alternative. The contract is minimal by design: the endpoint takes the dynamic path /:template.json and returns a JSON response with the same keys as custom providers. name and tar are required, while defaultDir, url, subdir and headers are optional. defaultDir decides where the template lands when you do not pass a directory, subdir points at a directory inside the tar file, and headers lets you send custom headers when downloading.

The README notes that because of this simplicity you can even use a GitHub repository as a template registry, or bring your own API for something more capable. The CLI exposes this with --registry for a URL and --no-registry to switch the lookup off entirely, and the programmatic API accepts either a URL string or false.

Offline mode, the disk cache and how private templates authenticate

Three flags control network behaviour, and they form a sensible ladder. --prefer-offline uses the cache if it exists and otherwise tries to download. --offline does not attempt to download at all and uses the cached version. --force is unrelated to caching: it clones to an existing directory even if it exists, which is how you overwrite a previous extraction.

Two flags carry warnings in the README, and they are worth reading carefully. --force-clean removes any existing directory or file recursively before cloning. --shell opens a new shell with the current working directory in the cloned directory, and it is marked experimental. Recursive deletion of a path derived from a template argument is exactly the kind of feature that should be typed by hand rather than embedded in a script.

Authorization is handled by a single token, passed with --auth or supplied through the GIGET_AUTH environment variable, and it is used for downloading private templates. The registry URL works the same way, with GIGET_REGISTRY as the environment override for the --registry option. Environment overrides matter for CI, where you would rather not put a token in a command line that ends up in a log.

Two more options round out the CLI. --ignore takes comma separated glob patterns of files to skip when extracting, for example --ignore pnpm-lock.yaml,*.md. And --cwd sets the directory against which relative paths are resolved, which is the difference between a script that works and a script that writes into the wrong place.

Running giget from the command line

The CLI is invoked through npx, so there is no global install step. The usage line is:

bash
npx giget@latest <template> [<dir>] [...options]

The template argument is the name or URI described earlier, and dir is a relative or absolute path where the template is extracted. A first run against the built-in registry looks like this:

bash
npx giget@latest nuxt

A GitHub repository with an explicit target directory is:

bash
npx giget@latest gh:unjs/template myProject

And a GitLab project with subgroups plus a subdirectory uses the double colon separator:

bash
npx giget@latest gitlab:group/subgroup/project::src/template

To also install the template's own dependencies, add --install, which calls unjs/nypm after the extraction. To skip lock files and documentation during extraction, add --ignore with comma separated glob patterns, and to see what the tool is doing while a script runs unattended, add --verbose.

The repository itself carries a play script for exactly this kind of check, since the package manifest defines a giget script that runs the CLI from source, and a play target that clones the unjs template with --force-clean and --verbose into a .tmp/clone directory.

Programmatic use through downloadTemplate

Everything the CLI does is available to code, because the CLI is a thin wrapper over the exported function. The package is installed from npm, yarn or pnpm:

bash
npm install giget

The import differs only by module system, with the ESM form and the CommonJS form both documented:

js
import { downloadTemplate } from "giget";

A minimal call resolves a source and an output directory in one step:

js
const { source, dir } = await downloadTemplate("github:unjs/template");

The function returns a promise that resolves to the resolved template, with dir being the path to the extracted directory and source the normalized version of the input.

The options mirror the CLI flags, and the README says they are usually inferred from the input string and can be customised. They include dir, provider, force, forceClean, offline, preferOffline, providers, registry, cwd, auth and ignore. The ignore option is the most flexible of the set: it takes either an array of glob patterns matched with path.matchesGlob, or a callback that receives the relative path of each entry after subdir is applied and returns true to skip it.

That callback form is the interesting one for a library author, because it lets you strip files based on rules the glob syntax cannot express. One constraint applies, and the README states it explicitly: the glob patterns require Node.js v22.5.0 or v20.17.0 or later.

Zero dependencies, the release pipeline and a licensing wrinkle

The zero dependency claim is the feature most likely to be repeated by anyone who recommends this tool, and it holds for the published package: the package manifest lists no runtime dependencies at all, and the README says the source code has no dependencies. The tarball-based clone path is the reason, since unpacking is done in JavaScript rather than by shelling out.

The development stack is a different story and is worth reading if you plan to contribute. The manifest uses obuild for the build, vitest for the tests, tsc for type checking, oxlint and oxfmt for linting and formatting, changelogen for the release notes, and pathe for path handling. The lint and test scripts are wired into the release script, which runs the tests, builds, generates the changelog, publishes to npm and pushes tags.

The licensing situation needs a second look. The package manifest declares the licence as MIT, while the repository is classified as having a custom licence that GitHub cannot classify, with a LICENSE file in the root. The README does not reconcile the two, so for a legal review you should read the LICENSE file directly rather than relying on the manifest field.

On activity, the repository is not archived, the last push was on 2026-10-18, and the published releases are v3.3.1 on 2026-07-24, v3.3.0 on 2026-06-11 and v3.2.0 on 2026-03-26. The version line is stable, which matters for a tool that ends up in setup scripts.

Editorial conclusion

Use giget when you ship a starter template, a CLI that needs to produce a project skeleton, or a CI job that wants a clean copy of a repository subdirectory without git history and without a local git or tar binary. Do not use it when you need history, branches or pull requests, since it copies a snapshot rather than cloning a working repository, and treat the --force-clean and --shell flags as destructive or experimental respectively. Before you ship it, check the Node.js version requirement for glob based ignore patterns, decide whether the custom licence in the LICENSE file overrides the MIT field in package.json for your compliance review, and pin the version, since the last published release was v3.3.1 on 2026-07-24 and the last push was on 2026-10-18.

Frequently asked questions

What is giget and what does it do?

giget is a tool for downloading templates and git repositories, with zero dependencies and support for GitHub, GitLab, Bitbucket and Sourcehut out of the box. It can fetch a whole template, a single subdirectory or a branch, and it caches to disk so it works offline.

How do I use giget to clone a template from the command line?

Run npx giget@latest with a template name or URI and an optional target directory, for example npx giget@latest gh:unjs/template myProject. A provider prefix selects the host, a hash selects a branch, a path selects a subdirectory, and a double colon separates a subdirectory when the repository path itself has more than two segments.

Does giget need git or tar installed on my machine?

Not for the default path. The README states that fast cloning uses tarball gzip without depending on a local git or tar, and the native git clone provider with sparse checkout exists as an alternative when you want a working git checkout instead of a snapshot.

How do I add my own template to a registry?

A custom registry exposes an endpoint at /:template.json that returns name and tar, and optionally defaultDir, url, subdir and headers. The built-in registry lives in the templates directory of the repository and accepts new slugs on a first-come first-served basis.

Official sources

  1. Issues
  2. README
  3. Releases
  4. unjs/giget on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/unjs-giget.svg)](https://hysenlabs.com/projects/unjs-giget)

Was this useful?