CLI tool for keeping an existing GregTech: New Horizons instance up to date with GTNH daily or experimental manifests.
It tracks installed mods, downloads changes, and applies config updates using git to merge pack changes while preserving user edits.
This is only used for updating from a daily to a daily or an experimental to an experimental
If coming from the old gtnh-nightly-updater jar, it is best to start from scratch and manually copy any user added mods and config changes (as well as the other folders on the wiki page about updating)
Always make a full instance backup before first using this program
- Initializes tracking from an existing instance (
init) - Updates mods to manifest-pinned versions (
update) - Optional
--latestmode to use newest non-pre releases when available (Only use if you know what you are doing) - Tracks config files with a local git branch; merges pack updates automatically (pack wins on conflicts)
- Supports excluded mods and user-defined extra mods
- Supports named profiles and multi-profile batch updates (
update-all) - Download caching and configurable concurrency
- Optional startup self-update check with SHA256-verified
self-updatecommand
- Go 1.25+ (for building/running from source)
- Existing GTNH instance directory
- Network access to GTNH manifests/assets and mod download sources
- Git (for config updates, skipped if missing)
- Optional
GITHUB_TOKENfor private GitHub downloads or higher API limits
Releases are available for Linux, Windows, and MacOS
No Go required
Just download the version for your OS and run it from the command line.
Note: I suggest putting it somewhere in your PATH so it can be ran from anywhere.
On Linux, I have ~/.local/bin added to my PATH
Building from source code:
go build -o gtnh-daily-updater .Or install into your Go bin:
go install .Building on Windows (to avoid UAC admin prompts):
On Windows, the build process generates a manifest file that prevents unnecessary UAC prompts. To build with the manifest:
# Install rsrc (one-time setup)
go install github.com/akavel/rsrc@v0.10.2
# Generate the Windows manifest resource
rsrc -manifest gtnh-daily-updater.manifest -arch amd64 -o rsrc_windows_amd64.syso
# Build the executable (go will automatically link the .syso file)
go build -o gtnh-daily-updater.exe .For another Windows architecture (for example, 386), keep GOARCH and rsrc -arch aligned:
$env:GOARCH = "386"
rsrc -manifest gtnh-daily-updater.manifest -arch $env:GOARCH -o "rsrc_windows_$($env:GOARCH).syso"
go build -o gtnh-daily-updater.exe .- Initialize state for an existing instance:
Note: You MUST pass the current config version your instance has. It will not work correctly otherwise.
Config versions can be found at https://github.com/GTNewHorizons/GT-New-Horizons-Modpack/releases.
For Daily and Experimental builds, the config version is found in the gtnh-XXXXXX-manifest.json build artifact and will likely be 2.X.0-nightly-<daily build date>.
For MultiMC/Prism clients, the instance-dir should be the folder that contains the .minecraft folder, not the .minecraft folder itself.
For servers, the instance-dir is the root of the server folder, the one that contains mods, config, etc.
gtnh-daily-updater init \
--instance-dir "/path/to/instance" \
--side client \
--config 2.9.0-nightly-2026-02-10Use --side server for servers.
For experimental packs:
gtnh-daily-updater init \
--instance-dir "/path/to/instance" \
--side client \
--mode experimental \
--config 2.9.0-nightly-2026-02-10- Check current status:
gtnh-daily-updater status --instance-dir "/path/to/instance"- Preview changes:
gtnh-daily-updater update --instance-dir "/path/to/instance" --dry-run- Apply update:
gtnh-daily-updater update --instance-dir "/path/to/instance"update: apply a single-instance updateupdate-all <profile> [profile...]: update multiple saved profiles sequentiallystatus: compare local state vs latest manifestconfig diff [--all] [path]: show tracked file drift, or file-level diff for one pathexclude add|remove|list: skip selected manifest modsextra add|remove|list: manage non-manifest modsprofile create|list|show|delete: manage reusable option setsself-update: download and install the latest release after SHA256 verification
Inspect all options:
gtnh-daily-updater --help
gtnh-daily-updater <command> --helpExclude manifest mods:
gtnh-daily-updater exclude add ModName AnotherMod
gtnh-daily-updater exclude listAdd extra mods from assets DB (default source):
gtnh-daily-updater extra add AngelicaAdd extra mods from GitHub releases:
gtnh-daily-updater extra add SomeMod --source github:Owner/RepoAdd extra mods from CurseForge (latest release file, requires CurseForge API key):
gtnh-daily-updater extra add SomeMod --source curseforge:12345Add extra mods from CurseForge (pinned file):
gtnh-daily-updater extra add SomeMod --source curseforge:12345/67890Add extra mods from Modrinth (latest release, no API key needed, rate limit 300/min/ip):
gtnh-daily-updater extra add SomeMod --source modrinth:slug-or-idAdd extra mods from Modrinth (pinned version):
gtnh-daily-updater extra add SomeMod --source modrinth:slug-or-id/versionIDAdd extra mods from direct URL:
gtnh-daily-updater extra add CustomMod --source https://example.com/CustomMod.jarPick a specific jar from a GitHub release that ships multiple variants. Use --match <regex> to select the asset; the pattern must uniquely match one .jar, otherwise the candidate names are listed so you can refine. Anchor patterns can be used (e.g. "unlimited\.jar$" for JourneyMap, "-\d+\.\d+\.\d+\.jar$" for GTNH-Web-Map) to avoid matching -dev, -sources, or -preshadow variants:
gtnh-daily-updater extra add journeymap \
--source github:TeamJM/journeymap-legacy \
--match "unlimited\.jar$"A same-name extra overrides the manifest entry — no need to exclude the original version first. This is the supported way to swap, for example, the manifest's journeymap-fairplay for the unlimited build from the same release.
Profiles are stored as TOML files under the OS-native user config directory:
- Linux:
${XDG_CONFIG_HOME:-~/.config}/gtnh-daily-updater/profiles - macOS:
~/Library/Application Support/gtnh-daily-updater/profiles - Windows:
%AppData%\gtnh-daily-updater\profiles
Profiles previously stored under ~/.config/gtnh-daily-updater on macOS/Windows are auto-migrated to the new location on first run.
Create and use a profile:
gtnh-daily-updater profile create main-client \
--instance-dir "/path/to/instance" \
--side client \
--concurrency 8
gtnh-daily-updater update --profile main-clientBatch update profiles:
gtnh-daily-updater update-all main-client alt-server- Local state is stored at
<instance-dir>/.gtnh-daily-updater.json - On Prism/MultiMC layouts, game files are resolved under
<instance-dir>/.minecraft/ - On server/other layouts, game files are resolved directly under
<instance-dir>/ - Config files are tracked in a git repo at
<game-dir>/.gtnh-configs/on alocalbranch; pack updates are applied viagit merge -X theirs(pack wins on conflicts) - Tracked items:
config/,journeymap/(preservingdata/),resourcepacks/(client only),serverutilities/,servers.json(client only) config diffshows your changes relative to the pack version (git diff <configVersion>..local)config diff "GregTech/Pollution.cfg"shows diff for a specific file (also acceptsconfig/GregTech/Pollution.cfg)- Config tracking requires git; config updates are skipped gracefully if git is unavailable or the repo hasn't been initialized yet
- Default mod cache and log directory lives under the OS-native user cache directory:
- Linux:
${XDG_CACHE_HOME:-~/.cache}/gtnh-daily-updater/{mods,logs} - macOS:
~/Library/Caches/gtnh-daily-updater/{mods,logs} - Windows:
%LocalAppData%\gtnh-daily-updater\{mods,logs}
- Linux:
- Caches/logs previously stored under
~/.cache/gtnh-daily-updateron macOS/Windows are auto-migrated to the new location on first run. - Disable cache with
--no-cache - Override cache location with
--cache-dir - Control parallel downloads with
--concurrency(default:6) - Logs are written to
<cache-dir>/logs/<timestamp>.log; debug output is always written to the log file regardless of the-vflag
Provide token via env var:
export GITHUB_TOKEN=your_token_hereOr pass per command:
gtnh-daily-updater update --github-token your_token_hereRequired to use curseforge: extra mod sources. Get a key at https://console.curseforge.com/.
Provide via env var:
export CURSEFORGE_API_KEY=your_key_hereOr pass per command:
gtnh-daily-updater update --curseforge-key your_key_hereThe tool can check GitHub for newer releases at startup and install them on demand. Both behaviors are off by default.
A global config file is created on first run at:
- Linux:
${XDG_CONFIG_HOME:-~/.config}/gtnh-daily-updater/config.toml - macOS:
~/Library/Application Support/gtnh-daily-updater/config.toml - Windows:
%AppData%\gtnh-daily-updater\config.toml
auto_update_check = false
include_prereleases = falseWhen auto_update_check = false (default), the tool prints a one-line hint pointing to the config file. When true, each invocation queries GitHub (3s timeout, silent on failure) and prints a notice if a newer release is available.
Install the latest release:
gtnh-daily-updater self-update # prompts for confirmation
gtnh-daily-updater self-update --yes # skip prompt (non-interactive)
gtnh-daily-updater self-update --prereleaseThe downloaded zip's SHA256 is verified against the digest published by the GitHub release API before the running binary is replaced. On Windows, the previous binary is left as <exe>.old and removed on next startup.
Run tests:
go test ./...