Update (October 2026): I no longer recommend DVM. Use mise instead: it pins decK, and any other CLI, per project, with checksums, and CI reads the same file. The follow-up shows how: Stop switching tool versions: pin every CLI per project with mise. This post still explains why an upgrade needs more than one decK version.
I wrote DVM, the decK Version Manager, during a Kong Gateway 2.8 to 3.4 upgrade. The job was to take an existing 2.8 configuration, convert it to the 3.x format, and prove it still worked, which meant running the same files through more than one version of decK in a single afternoon. Downloading and swapping binaries by hand got old quickly, so I wrapped it in a small script.
This post explains why an upgrade like that needs several decK versions, how DVM works, a Linux bug in the original script, and why I now recommend mise instead.
Versions used: DVM with the Linux fix, on Ubuntu 24.04 · decK 1.38.0, 1.39.4 and 1.62.1 · mise 2026.9.9 on macOS
Why one decK version isn’t enough during an upgrade
decK is the command-line tool for managing Kong configuration as files. During a major upgrade you end up using it in two roles at once:
- Reading the old world. You export and diff configuration from the gateway you’re leaving, with a decK version you know works against it.
- Writing the new world. You convert the files to the new format and validate them with a newer decK.
The conversion is where the version matters. Kong 3.0 changed how route paths are interpreted: a regex path must now start with ~, and everything else is treated as plain text (breaking changes in 3.0). deck file convert handles that for you. Here is a 2.x-style file:
# kong-2x.yaml
_format_version: "1.1"
services:
- name: orders-api
url: http://orders.example.com
routes:
- name: order-by-id
paths: ["/orders/\\d+$"]
Converted with decK 1.62.1:
deck file convert --from 2.8 --to 3.4 --input-file kong-2x.yaml --output-file kong-3x.yaml
# kong-3x.yaml
_format_version: "3.0"
services:
- host: orders.example.com
name: orders-api
port: 80
protocol: http
routes:
- name: order-by-id
paths:
- ~/orders/\d+$
The format version moves to 3.0 and the regex path gets its ~. Which source and target formats are available depends on the decK version: 1.62.1 converts from 2.8, 3.4 or 3.10 to 3.4, 3.10, 3.14 or Konnect (deck file convert). So when you’re checking a conversion, you want to know exactly which decK produced it, and to be able to run the same file through another version to compare.
How DVM works
DVM is a single shell script (source). It does three things:
- Install a decK version by downloading the release archive from GitHub into
~/.deck_versions/<version>/. - Switch by pointing a symlink at
/usr/local/bin/deckto the chosen version. - List the installed versions and mark the one the symlink points to.
Because the symlink lives in /usr/local/bin, switching needs sudo, and the switch is global: every terminal and every project sees the same decK.
Using DVM
You need curl, tar and git. Install:
git clone https://github.com/bhatikuldeep/dvm.git
cd dvm
./install.sh
If you installed decK with Homebrew, run brew uninstall deck first so the two don’t fight over /usr/local/bin/deck.
Install two versions and switch between them:
dvm install 1.39.4
dvm install 1.38.0
dvm switch 1.39.4
dvm list
Expected output of the last command:
Installed decK versions:
1.38.0
* 1.39.4 (current)
And deck version now reports decK v1.39.4. To remove DVM, run ./uninstall.sh from the repository folder.
A Linux bug in the original script
The macOS path worked, but on Linux every install failed with:
URL does not exist or is unreachable: https://github.com/Kong/deck/releases/download/v1.39.4/deck_v1.39.4_linux_arm64.tar.gz
decK’s Linux archives are named deck_1.39.4_linux_arm64.tar.gz, without the v in the file name. I checked the release assets for 1.38.0, 1.39.4 and 1.62.1, and all of them use that pattern. The fix is one character in the download URL. After it, the full install, switch and list sequence above runs cleanly on Ubuntu 24.04.
The lesson is the usual one: a tool you wrote for yourself on one operating system isn’t tested on the others until someone runs it there.
Use mise instead
DVM solved my problem in 2024, but its design has limits I’d now avoid:
- Global switch. One symlink means one decK for every project on the machine. Working on two upgrades at once is exactly when you need two versions at the same time.
- sudo for every switch. Changing a developer tool shouldn’t need administrator rights.
- No integrity check. decK publishes a
checksums.txtwith every release, and DVM doesn’t verify downloads against it.
My recommendation now is mise, a version manager for any tool, not just decK. In each project folder:
mise use deck@1.39.4
That writes a mise.toml next to your config:
[tools]
deck = "1.39.4"
From then on, decK inside that folder is 1.39.4, and inside another project pinned to 1.38.0 it’s 1.38.0, with no symlink, no sudo and nothing global. Two folders side by side:
project-a: decK v1.39.4 (aca781a)
project-b: decK v1.38.0 (b6aba61)
Commit mise.toml and everyone on the team, and your CI, gets the same version. In GitHub Actions, the Kong/setup-deck action does the same job with its deck-version input.
The same file can pin kongctl, kubectl, Helm and the rest of your toolbox, with checksums. I wrote that up in Stop switching tool versions: pin every CLI per project with mise.
Takeaways
- A major Kong upgrade needs more than one decK version: one to read the old configuration, a newer one to convert and validate it.
- Always record which decK version produced a converted file. Conversion options change between decK releases.
- Use mise instead of DVM, for decK and every other CLI. A per-project pin lets two projects use different versions at the same time and keeps the version under review with the code.
- If you still use DVM on Linux, update to the fixed version.
References
- deck file convert, Kong docs
- Breaking changes in Kong Gateway 3.0, Kong docs
- DVM source, GitHub
- decK releases, GitHub
- mise, tool version manager
- Kong/setup-deck, GitHub Action