Short answer
Yes — > matching is case-sensitive, and it is case-sensitive uniformly: across server versions, across gateway/leaf/bridge hops, and inside JetStream. There is no server-level option to normalize subject case. But the premise in your question contains a more important correction: NATS subjects are dot-delimited, not slash-delimited. If your deployment is routing on /-separated subjects, the surprising behavior you are seeing almost certainly comes from that mismatch, not from case handling.
Confirmed facts
- Subjects are split into tokens on
. only. a/b is a single token containing a literal slash, not two hierarchy levels. - Token comparison is exact and case-sensitive.
orders.US and orders.us are distinct subjects; a subscription on one never receives messages published to the other. > matches one or more trailing tokens and must be the final token of the subscription. orders.> matches orders.us and orders.us.ny, but not orders alone, and not orders.US.* matches exactly one token at its position, with the same exact, case-sensitive comparison.- Wildcards match whole tokens only — there is no partial-token or prefix matching.
Likely explanation for the reported case-variant deliveries
When operators observe a > subscription receiving subjects that "differ in case," the usual causes are:
- Slash-delimited subjects. A publisher sending
Orders/US/East and a subscriber on Orders.> — the subscriber receives nothing, because Orders/US/East is one token and the subscription expects a dot after Orders. Conversely, a subscription on the literal subject Orders/US/East matches only that exact string. Teams migrating from MQTT or path-based systems hit this constantly and misread it as a wildcard or case bug. - Bridge or mapping rewriting. Subject mappings, gateway configs, or a custom bridge process can rewrite subjects between hops. If a mapping normalizes or rewrites case, the subscriber sees a different subject than the publisher sent — but that is the mapping doing it, not wildcard evaluation. The server's matcher itself never folds case.
- Multiple overlapping subscriptions. A subscriber holding both
foo.> and a literal case-variant subscription can make it look like one wildcard matched both cases.
JetStream and version behavior
JetStream streams capture messages whose subjects match the stream's configured subjects using the same token rules — case-sensitive, dot-delimited. A stream configured with orders.> will not store messages published to Orders.us. There is no JetStream setting that changes this, and no nats-server configuration flag for case-insensitive subject matching in any released version. This behavior has been stable across the 2.x line; if you are on an unusual fork or a very old 1.x server, verify directly rather than assuming.
Verify it yourself in two minutes
# Terminal 1: case-variant wildcard subscriber
nats sub 'foo.>'
# Terminal 2: publish with different case — expect NO delivery
nats pub Foo.Bar "should not arrive"
nats pub foo.bar "should arrive"
# Slash test: this is one token, not a hierarchy
nats sub 'a.>' # receives nothing from the publish below
nats pub 'a/b' "literal slash token"
nats sub 'a/b' # this one DOES receive it
If your bridged deployment shows deliveries that contradict this, capture the subject as seen on each hop (nats sub with headers, or trace via monitoring endpoints) to find where a mapping is rewriting it.
Design guidance
Pick one casing convention (lowercase is the common choice), enforce it at publisher boundaries, and convert any slash-delimited subjects to dots before they enter NATS. Case-sensitivity is a feature for access control here: permissions on tenant-a.> cannot be bypassed by publishing to Tenant-A.x, because that is simply a different subject tree.