TL;DR
giget is the UnJS template downloader — downloads Git repos and tar archives without git history, supports GitHub, GitLab, Bitbucket, and custom registries, used by Nuxt's nuxi init. degit is Rich Harris's project scaffolding tool — downloads repos without git history, simple CLI, created by the Svelte author. tiged is the community fork of degit — fixes bugs and adds features degit hasn't merged, drop-in replacement. In 2026: giget for programmatic template downloading, degit/tiged for CLI project scaffolding.
Key Takeaways
- giget: ~3M weekly downloads — UnJS, programmatic API, registry support, powers Nuxt CLI
- degit: ~500K weekly downloads — Rich Harris, CLI-first, simple but unmaintained
- tiged: ~100K weekly downloads — community fork of degit, maintained, bug fixes
- All three download repos without
.githistory — clean project scaffolding - giget supports custom template registries (like Nuxt starters)
- degit and tiged are CLI tools; giget has both CLI and programmatic API
The Problem
# git clone downloads the ENTIRE history:
git clone https://github.com/nuxt/starter
# → Downloads all commits, branches, tags
# → .git directory is ~50MB for large repos
# → You just wanted the latest files
# What you actually want:
# → Download just the latest files
# → No .git directory
# → No commit history
# → Ready to start a new project
giget
giget — universal template downloader:
CLI usage
# Download from GitHub:
npx giget gh:nuxt/starter my-app
npx giget github:vitejs/vite/packages/create-vite/template-react-ts my-react-app
# Short syntax:
npx giget nuxt/starter my-app
# GitLab:
npx giget gitlab:user/repo my-project
# Bitbucket:
npx giget bitbucket:user/repo my-project
# Specific branch/tag:
npx giget gh:nuxt/starter#v3 my-app
npx giget gh:vuejs/create-vue#main my-vue-app
# Subdirectory:
npx giget gh:unjs/template/ts my-ts-project
Programmatic API
import { downloadTemplate } from "giget"
// Download a template:
const { source, dir } = await downloadTemplate("gh:nuxt/starter", {
dir: "./my-app",
force: true, // Overwrite existing directory
install: false, // Don't run npm install
})
console.log(`Downloaded from ${source} to ${dir}`)
// With options:
await downloadTemplate("gh:vitejs/vite", {
dir: "./my-project",
preferOffline: true, // Use cache if available
offline: false, // Allow network requests
cwd: process.cwd(),
auth: process.env.GITHUB_TOKEN, // For private repos
})
Custom registries
import { downloadTemplate } from "giget"
// Nuxt uses a custom registry for starters:
await downloadTemplate("nuxt", {
registry: "https://raw.githubusercontent.com/nuxt/starter/templates/templates",
})
// Custom registry for your organization:
await downloadTemplate("my-template", {
registry: "https://templates.mycompany.com",
})
How Nuxt uses giget
// nuxi init uses giget to scaffold projects:
// npx nuxi init my-app
// Internally:
import { downloadTemplate } from "giget"
async function initProject(name: string, template: string = "v3") {
await downloadTemplate(`nuxt/starter#${template}`, {
dir: name,
force: false,
})
console.log(`✅ Nuxt project created in ./${name}`)
console.log(` cd ${name} && npm install`)
}
degit
degit — project scaffolding:
CLI usage
# Download from GitHub:
npx degit user/repo my-project
npx degit sveltejs/template my-svelte-app
# Specific branch:
npx degit user/repo#dev my-project
# Specific tag:
npx degit user/repo#v1.0.0 my-project
# Subdirectory:
npx degit user/repo/path/to/subdir my-project
# GitLab / Bitbucket:
npx degit gitlab:user/repo my-project
npx degit bitbucket:user/repo my-project
# With verbose output:
npx degit -v user/repo my-project
Programmatic usage
import degit from "degit"
const emitter = degit("user/repo", {
cache: true,
force: true,
verbose: true,
})
emitter.on("info", (info) => {
console.log(info.message)
})
await emitter.clone("./my-project")
degit.json actions
// degit.json — post-clone actions:
[
{
"action": "clone",
"src": "user/another-repo"
},
{
"action": "remove",
"files": ["LICENSE", ".github"]
}
]
degit limitations
degit:
✅ Simple CLI — npx degit user/repo dir
✅ Caching — downloads faster on repeat
✅ Post-clone actions (degit.json)
✅ Created by Rich Harris (Svelte author)
❌ Not actively maintained (last release 2020)
❌ GitHub API issues unfixed
❌ No private repo support (without workarounds)
❌ Limited programmatic API
❌ No TypeScript types
→ Use tiged (maintained fork) or giget instead
tiged
tiged — maintained degit fork:
CLI usage (same as degit)
# Drop-in replacement for degit:
npx tiged user/repo my-project
npx tiged sveltejs/template my-svelte-app
# All degit syntax works:
npx tiged user/repo#branch my-project
npx tiged gitlab:user/repo my-project
npx tiged user/repo/subdir my-project
Fixes over degit
tiged improvements over degit:
✅ Fixed GitHub API rate limiting issues
✅ Fixed private repo downloading
✅ Fixed subdirectory extraction bugs
✅ Active maintenance (regular releases)
✅ TypeScript support
✅ Better error messages
Same API — just replace "degit" with "tiged":
npx degit user/repo dir → npx tiged user/repo dir
Programmatic usage
import tiged from "tiged"
const emitter = tiged("user/repo", {
cache: true,
force: true,
verbose: true,
})
emitter.on("info", (info) => {
console.log(info.message)
})
emitter.on("warn", (warning) => {
console.warn(warning.message)
})
await emitter.clone("./my-project")
Feature Comparison
| Feature | giget | degit | tiged |
|---|---|---|---|
| CLI | ✅ | ✅ | ✅ |
| Programmatic API | ✅ (full) | ⚠️ (basic) | ⚠️ (basic) |
| GitHub | ✅ | ✅ | ✅ |
| GitLab | ✅ | ✅ | ✅ |
| Bitbucket | ✅ | ✅ | ✅ |
| Custom registries | ✅ | ❌ | ❌ |
| Private repos | ✅ (auth token) | ❌ | ✅ |
| Subdirectories | ✅ | ✅ | ✅ |
| Branch/tag | ✅ | ✅ | ✅ |
| Caching | ✅ | ✅ | ✅ |
| Post-clone actions | ❌ | ✅ (degit.json) | ✅ (degit.json) |
| TypeScript | ✅ | ❌ | ✅ |
| Maintained | ✅ (UnJS) | ❌ (2020) | ✅ |
| Weekly downloads | ~3M | ~500K | ~100K |
When to Use Each
Use giget if:
- Need a programmatic API for template downloading
- Building a CLI tool that scaffolds projects (like nuxi, create-*)
- Want custom template registries
- In the UnJS ecosystem
Use tiged if:
- Want a CLI-first scaffolding tool (npx tiged user/repo dir)
- Currently using degit and need bug fixes
- Need post-clone actions (degit.json)
- Want a maintained drop-in degit replacement
Use degit if:
- Already using it and it works for your use case
- Note: consider switching to tiged for bug fixes
Building Your Own create-* CLI with giget
The most common production use of giget is building scaffolding CLIs — the create-myapp experience that sets up a project from a template with a single command. giget's programmatic API makes this straightforward:
// create-myapp — a minimal scaffolding CLI using giget
import { downloadTemplate } from "giget"
import { defineCommand, runMain } from "citty"
const main = defineCommand({
meta: {
name: "create-myapp",
description: "Scaffold a new MyApp project",
},
args: {
name: {
type: "positional",
description: "Project directory name",
required: true,
},
template: {
type: "string",
description: "Template to use (default, typescript, minimal)",
default: "default",
},
},
async run({ args }) {
const { name, template } = args
console.log(`Scaffolding ${name} with ${template} template...`)
const { source, dir } = await downloadTemplate(
`gh:myorg/myapp-templates/${template}`,
{
dir: `./${name}`,
force: false,
install: false,
}
)
console.log(`✅ Project created at ${dir}`)
console.log(` cd ${name} && npm install && npm run dev`)
},
})
runMain(main)
// package.json for the create-* CLI:
{
"name": "create-myapp",
"bin": {
"create-myapp": "./dist/index.mjs"
},
"dependencies": {
"citty": "^0.1.6",
"giget": "^1.2.3"
}
}
This pattern powers nuxi init, create-h3, create-nitro, and dozens of other UnJS-ecosystem scaffolding tools.
Private Repository Support
Downloading templates from private repositories requires authentication. The approaches differ by tool:
giget (recommended):
# Via environment variable (recommended for CI):
GITHUB_TOKEN=ghp_your_token npx giget gh:myorg/private-template my-project
# Via CLI flag:
npx giget gh:myorg/private-template my-project --auth=ghp_your_token
// Programmatic with token:
await downloadTemplate("gh:myorg/private-template", {
dir: "./my-project",
auth: process.env.GITHUB_TOKEN,
})
tiged:
# tiged can use GITHUB_TOKEN via environment variable
GITHUB_TOKEN=ghp_your_token npx tiged myorg/private-repo my-project
degit: Has known issues with private repositories. GitHub's API changes in 2021-2022 broke degit's private repo support in some configurations — this is one of the main reasons tiged exists.
For enterprise setups with GitHub Enterprise Server or self-hosted GitLab:
// giget — custom source providers:
import { downloadTemplate } from "giget"
// Self-hosted GitLab:
await downloadTemplate("gitlab:myorg/template", {
dir: "./my-project",
auth: process.env.GITLAB_TOKEN,
// Custom GitLab instance:
// registry: "https://gitlab.mycompany.com/api/v4"
})
giget vs git clone + rm -rf .git
The common question: why not just git clone and delete the .git directory?
# Manual approach:
git clone https://github.com/user/template my-project
rm -rf my-project/.git
cd my-project && npm install
# Problems:
# 1. Downloads entire git history (may be hundreds of MB for large repos)
# 2. Requires git to be installed (not always true in container environments)
# 3. No subdirectory support (git sparse checkout is complex)
# 4. No registry abstraction (can't use "nuxt/starter" shorthand)
# giget approach:
npx giget nuxt/starter my-project
# Advantages:
# 1. Downloads only latest commit (tarball — much faster)
# 2. Works in environments without git
# 3. Supports subdirectories: npx giget user/repo/path/to/subdir
# 4. Shorthand registry support
For most template use cases, giget is 5-10x faster than git clone because it downloads a tarball of the latest commit rather than the entire git history.
Community Adoption and Download Trends in 2026
Weekly npm downloads tell a clear adoption story (early 2026 estimates):
| Package | Weekly Downloads | GitHub Stars | Last Release |
|---|---|---|---|
| giget | ~3M | 1,200+ | Active (UnJS) |
| degit | ~500K | 5,400+ | 2020 (unmaintained) |
| tiged | ~100K | 500+ | Active |
degit's 5,400 GitHub stars versus tiged's 500 says something interesting: stars are vanity metrics. degit accumulated stars over years of being the go-to scaffolding tool, but the download numbers show the actual trajectory. giget is pulling 6x more downloads than degit — the ecosystem has moved on.
The stars-to-downloads ratio for degit is inverted compared to what you would expect from an active package. People starred it, moved on, and either switched to giget (for programmatic use) or tiged (for CLI-first use). degit's maintainer Rich Harris is focused on Svelte and SvelteKit — which now includes its own scaffolding in sv create, reducing the need for degit even in the Svelte community.
giget's download growth tracks almost exactly with Nuxt 3 adoption. The Nuxt team built nuxi init on giget, and every Nuxt project creation is a giget install. This gives giget a massive baseline of downloads that are not at all related to direct user choice — they are transitive.
Performance Comparison
All three tools solve the same speed problem relative to git clone, but their implementation details differ:
| Tool | Method | Speed (typical) | Caching |
|---|---|---|---|
| giget | GitHub tarball download | 2-5 seconds | Local cache dir |
| degit | GitHub tarball download | 3-8 seconds | ~/.degit dir |
| tiged | GitHub tarball download | 3-8 seconds | ~/.degit dir |
| git clone | Full git history | 15-60+ seconds | None |
All three download GitHub's auto-generated tarball for the target ref — the same .tar.gz that GitHub generates for "Download ZIP." The speed difference relative to git clone is dramatic: instead of fetching every commit in the history, you get only the files at the target commit.
giget tends to be slightly faster than degit/tiged in practice because its codebase was written more recently with modern async patterns and it handles the Cloudflare/GitHub CDN responses more efficiently. The difference is measured in seconds at most — not a deciding factor for most users.
Migration Guide: degit to tiged or giget
If you are currently using degit and hitting bugs (the most common being GitHub API rate limiting and private repo issues), here is the migration path:
degit to tiged (drop-in):
# Before:
npx degit user/repo my-project
npx degit user/repo#branch my-project
# After (identical syntax):
npx tiged user/repo my-project
npx tiged user/repo#branch my-project
# Programmatic — change only the import:
# Before:
import degit from "degit"
const emitter = degit("user/repo", { cache: true })
# After:
import tiged from "tiged"
const emitter = tiged("user/repo", { cache: true })
degit to giget (API change):
# CLI — syntax differs slightly:
# Before:
npx degit user/repo my-project
npx degit user/repo#branch my-project
# After:
npx giget gh:user/repo my-project
npx giget gh:user/repo#branch my-project
# Programmatic:
# Before:
import degit from "degit"
const emitter = degit("user/repo")
await emitter.clone("./my-project")
# After:
import { downloadTemplate } from "giget"
await downloadTemplate("gh:user/repo", { dir: "./my-project" })
The giget migration requires updating both the CLI syntax (adding the gh: prefix) and the programmatic API (from event-emitter pattern to promise-based downloadTemplate). For teams with simple usage, this is a 10-minute change. For teams with complex degit.json post-clone actions, note that giget does not support degit.json — you would need to replicate that logic in your scaffolding script.
Real-World Who Uses What in 2026
Understanding which tools power which projects helps clarify the intended use case for each:
giget powers the Nuxt ecosystem. nuxi init, nuxi add, and template-based project creation in Nuxt 3 all use giget. The UnJS template registry at unjs/template uses giget. create-h3, create-nitro, and other UnJS scaffolding CLIs are built on giget's programmatic API. If you are building a create-* package for your own framework or toolchain, giget is the standard choice in 2026.
tiged is the tool for developers who want npx tiged user/repo dir and nothing more. It is popular in the Svelte community (since degit is the original Svelte scaffolding tool and tiged is the maintained version), and among developers who want a simple CLI without the UnJS ecosystem dependency.
degit remains in use only in projects that haven't updated their scaffolding docs. It still works for public repositories on GitHub that haven't changed their API behavior. The Svelte official docs pointed to degit for years, and many tutorials still reference it — but the recommended path is now npx sv create for SvelteKit or tiged for custom templates.
Template Caching and Offline Workflows
All three tools support local caching of downloaded templates, which matters for developers working on planes or in environments with unreliable network access. giget caches tarballs to ~/.giget by default, and the { cache: true } option in the programmatic API tells it to use the cached version if the template has been downloaded before. degit and tiged cache similarly to ~/.degit. The cache key is the resolved ref (commit hash), not just the branch name — so gh:user/repo#main will re-download when the main branch gets new commits, but gh:user/repo#abc123 (a pinned commit) will always use the cache after the first download. For create-* CLIs that need to work offline, explicitly pinning a commit hash in the default template URL ensures the cache is always valid. Clearing the cache is manual (delete the directory), which is a minor pain point all three share. giget's { force: true } option bypasses the cache for a fresh download regardless of what is stored.
Methodology
Download data from npm registry (weekly average, February 2026). Feature comparison based on giget v1.x, degit v2.x, and tiged v3.x.
Compare project scaffolding tool health on PkgPulse. Also see cac vs meow vs arg 2026 for CLI argument parsing and cosmiconfig vs lilconfig vs c12 for config loading.
Related: archiver vs adm-zip vs JSZip (2026).