A channel is a named lane inside a project. It carries its own lifecycle, so a release created in the Beta channel can promote through a different set of environments than one created in Stable - same project, same deployment process, different route to production.
Channel version rules decide what is allowed into the lane. A channel can filter on the release version itself, and on the package versions pinned into that release - so 3.0.0-beta7 never lands in Stable, and a nightly build of a package never reaches a release destined for production.
What a channel can gate
The release version rule
Each channel has one release version rule, made of two independent parts, plus a helper for auto-suggested versions. Everything is optional.
- Version range - bounds the version number, written in interval notation. A square bracket includes the endpoint, a round bracket excludes it, and a missing endpoint means unbounded.
- Prerelease versions - a dropdown deciding whether prereleases are allowed at all, and which ones.
- Tag to add to auto-suggested versions - the tag Jaws appends to the version it proposes for you, e.g.
beta.
The one piece of range notation worth committing to memory is the first line below: a bare version is a minimum, not an exact match. Writing 1.0.0 when you meant "only 1.0.0" opens the channel to every version above it instead.
How to write the range you mean
The same notation applies to the release version rule and to package rules.
1.0.0 1.0.0 and anything above it - a bare version is a MINIMUM,
not an exact match. This is the one that surprises people.
[1.0.0] exactly 1.0.0, and nothing else
[2.0,3.0) 2.0 or above, but below 3.0 - the usual way to say "2.x only"
(2.0,3.0) above 2.0 and below 3.0 - both endpoints excluded
[2.0,) 2.0 or above, with no upper bound
(,3.0] 3.0 or below, with no lower bound
Choosing whether prereleases are allowed
The range says nothing about prereleases - that is the Prerelease versions dropdown's job. It offers four choices:
- Any version - no constraint. Stable and prerelease versions are equally welcome.
- Stable only - no prereleases - the channel accepts
2.4.0and rejects2.4.0-beta1. This is what a production channel usually wants. - Prereleases only - the mirror image:
2.4.0-beta1is accepted and2.4.0is rejected. Useful for a channel that must never be handed a final build. - Matching a pattern... - your own regular expression over the tag, for when the presets are too blunt.
^beta.$acceptsbeta,beta1andbeta.3but notrc1;^(beta|rc).$opens the lane to both.
A custom pattern is matched against the prerelease label without the leading -, and against an empty string for a stable version - which is why the stable-only preset is simply ^$.
The dropdown is not a stored field of its own: it is derived from the pattern. A channel created over the REST API with versionTagRegex set to ^$ shows up in the editor as Stable only, and anything the presets do not recognise shows as Matching a pattern... with your expression intact. There is one rule, and two ways to write it.
If you have met NuGet version ranges elsewhere, note that this is deliberately not how a raw NuGet range behaves. NuGet sorts a prerelease below its own release, so a raw [2.0,4.0) would reject 2.0.0-beta while happily accepting 4.0.0-beta. For a dependency resolver that is defensible; for a channel gate it is not. A channel configured as "2.0 to 4.0, betas only" has to accept 2.0.0-beta, so Jaws compares the bounds on the number and leaves the prerelease question entirely to the dropdown.
Why a tag for auto-suggested versions exists
When you open the release form, Jaws suggests the next version for you. With a channel selected the suggestion is seeded from the releases already in that channel, which is what lets a stable and a prerelease stream keep independent numbering, and is then nudged to satisfy the channel's rule: it snaps up to the minimum of the version range, and appends the tag you configured.
That last part needs its own field because a suggested version has no prerelease tag on its own - so a channel that requires one would reject its own suggestion. Set the tag to beta and the form suggests 1.4.0-beta instead of 1.4.0. Leave it blank to suggest plain version numbers. The field is hidden for a stable-only channel, where a prerelease tag would be a contradiction, and the editor rejects a tag that the channel's own pattern would not match.
Package version rules
A channel also carries an ordered list of package rules. Each rule has:
- a package filter - a glob over the package ID, e.g.
orMyApp.. Case insensitive;*and?are the wildcards and every other character is literal, so a.in a filter is a dot, not a wildcard. - a version range and a prerelease versions setting, with exactly the same meaning - and the same dropdown - as on the release version rule.
Rules are evaluated in order, and the first rule whose filter matches a package wins. A package matched by no rule is unconstrained. That ordering is the whole design: put the specific filters at the top and the catch-all at the bottom.
So a Stable channel that wants stable packages everywhere except for one component that is allowed to ship release candidates reads:
Specific first, catch-all last
The first matching filter wins, so MyApp.Frontend never reaches the second rule.
1. MyApp.Frontend range: (blank) prereleases: matching ^(rc|$)
2. * range: (blank) prereleases: stable only
Each filter may only be used once per channel - two rules with the same filter would mean the second could never match, so the editor rejects it rather than letting you save a rule that does nothing.
A rule that constrains a package which has no compliant version available is not silently ignored either. See below.
What you see when creating a release
The rules are applied while you fill the form in, not only when you submit:
- The version box is pre-filled with a suggestion that already satisfies the channel's rule.
- Package dropdowns are filtered. For each package you only see the versions the selected channel allows, newest first.
- Switching channel re-pins packages. If a version you had selected is not allowed in the channel you just picked, Jaws moves it to the newest allowed version and tells you which packages it changed.
- A package with nothing to pin blocks the release. If no available version of a package satisfies the rule, you get an explicit error naming the package, and the create button is disabled until you push a compliant version or choose a different channel.
- Anything the server rejects appears in a summary at the bottom of the form - for example "Release version 2.4.0 is not allowed in channel 'Beta': prerelease tag '(none)' does not match ^beta.$"*.
Behaviour worth knowing about
- A channel with no rules is unrestricted. Every rule field is optional and starts blank, so a channel constrains only what you explicitly tell it to. The channels page lists such a channel as No restrictions.
- The server is the authority. The release API loads the channel and its rules from the database rather than trusting anything on the request, so an API caller cannot pick which rules apply to it.
- Rules gate creation, not deployment. A release that already exists keeps working if you later tighten the channel's rules. The rule is a gate on the way in.
- CI gets the same errors. Create a release over the REST API with a non-compliant version or package and the response tells you which channel rejected it and why - the same sentence the UI shows.
- Patterns are bounded. Tag patterns are compiled non-backtracking with a timeout, so a pathological expression cannot hang anything. Backreferences and lookarounds are rejected at save time as a consequence.
Setting the rules up
Open a project, go to Channels, and add or edit a channel. The release version rule sits directly under the lifecycle picker, with a try a version against this rule box next to it - type a version and it tells you Allowed or Rejected, with the reason, before you save anything. Package rules are the table below it; Add package rule appends a row, and rows are matched top to bottom.
Over the REST API the same rule fields hang off the channel endpoints. On update an omitted field leaves the stored value alone while an empty one clears it, and that applies to the package rules as a whole: omit packageRules to leave them untouched, or send an empty list to remove all of them.
Create a beta channel with package rules
Rules are matched in the order they appear in packageRules.
POST /api/project/channel
Authorization: Basic <base64(serviceAccountId:apiKey)>
Content-Type: application/json
{
"projectId": "prj_abc123",
"name": "Beta",
"lifecycleId": "lc_preview",
"versionTagRegex": "^beta.*$",
"versionDefaultTag": "beta",
"packageRules": [
{
"packageFilter": "MyApp.Frontend",
"versionRange": "[2.0,3.0)"
},
{
"packageFilter": "*",
"versionTagRegex": "^$"
}
]
}