Skip to content

Tags and Defaults

Chloe41427 edited this page Sep 27, 2026 · 1 revision

Tags, latest and the Default Version

Under the old Vendor API you made a version the "default" with a dedicated PUT /default call. That mechanism is gone. In the State API, the default is derived from a tag - there's no separate "set default" operation. This page explains the model.


The mental model

A tag is a moving label that points at exactly one version within a scope. Think of latest the way you'd think of a Git branch pointer or a Docker :latest tag: it names "the current one," and it moves as you publish.

The scope of a tag is:

(candidate, distribution, platform)

Within any one scope, a tag is mutually exclusive - only one version can carry it at a time. Assigning latest to a new version automatically moves it off whichever version held it before.

Common tags:

  • latest - newest release, bleeding edge included (e.g. 26.0.0-ea.15).
  • lts - stable release, drives the default (e.g. Java 25.0.1).
  • Major pointer - newest release in a major line (e.g. 21). Major only for now, not 21.0.

Tags must match ^[a-zA-Z0-9]([a-zA-Z0-9._-]{0,48}[a-zA-Z0-9])?$ (max 50 chars): start and end alphanumeric, dots/hyphens/underscores allowed in between.


How the "default" version works now

There is no stored default. When SDKMAN! needs the default version for a candidate, it resolves it on every request as:

the version carrying the lts tag - checked on UNIVERSAL first, then LINUX_X64, considering only rows with no distribution.

Implications:

  • To set the default, assign the lts tag to the version you want as default.
  • If no version carries lts, the candidate simply has no default (the field is absent, not null).
  • Java has no single default - because Java uses per-distribution tags, the default field is always absent for it.

Assigning and moving tags

There are two ways to manage tags.

1. As part of publishing (POST /versions)

The tags field on a version publish behaves as:

tags value Effect
(absent) Preserve the version's existing tags
[] (empty) Clear all tags from the version
["latest", "lts"] Replace all tags with exactly these

So a single publish can create the version and claim all its tags at once, e.g. "tags": ["latest", "lts", "21"], each moving off its previous holder. No follow-up calls needed.

2. As a standalone operation (POST /versions/tags)

To move a single tag without republishing a version, assign it directly:

curl -sf -X POST https://state.sdkman.io/versions/tags \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "candidate": "gradle",
    "version": "8.12",
    "platform": "UNIVERSAL",
    "tag": "latest"
  }'

This appends the tag to the target version and moves it off any other version in the same scope. Re-assigning a tag a version already has is a no-op. It never creates a version - the target must already exist (else 404).

To remove a tag, DELETE /versions/tags with the same scope (candidate, tag, distribution, platform).


Deleting a tagged version

You cannot delete a version that still has active tags. The API returns 409 Conflict and lists the offending tags:

{
  "error": "Conflict",
  "message": "Cannot delete version with active tags. Remove or reassign the following tags first.",
  "tags": ["latest", "lts", "21"]
}

Remove or reassign those tags first (move latest to another version, for example), then delete.

Clone this wiki locally