I wouldn't say separating the GC at the type level is a major innovation, but as you say it's useful. I don't think Nim really sells itself on a groundbreaking GC implementation either. However it does give you a fast GC with enough flexibility should you need it. For example, the Boehm GC is not thread-local.
GC types are copied over channels with threads, or you can use the usual synchronisation primitives and pass pointers.
As you say, thread-locality avoids the hard problems and this is a good default - I would argue that most of the time you want your data being processed within a thread and the communication between them to be a special case.
Certainly, there's a lot of talk of adding some sugar to threading, and Nim does offer some interesting tastes, such as the parallel statement: https://nim-lang.org/docs/manual_experimental.html#parallel-...
The performance of the default GC is good to very good, the JVM is almost certainly better in most cases, however this is comparing apples to oranges; it's a different language.
Nim's GC pressure is much lower in most cases, not least because everything defaults to stack types which not only don't use GC but tend to be much better for cache coherence due to locality. Using ref types is not required unless you use inheritance, however the language does encourage composition over inheritance, despite providing full OO capabilities, so you find inheritance isn't as needed as in other languages.
Plus it's not really much different to using refs to drop down to pointer level and avoid the GC without disabling it:
type
DataObj = object
foo: int
Data = ptr DataObj
proc newData: Data = cast[Data](alloc0(DataObj.sizeOf))
proc free(data: Data) = data.deAlloc
var someData = newData()
someData.foo = 17
echo someData.repr
# the echo outputs eg: ptr 000000000018F048 --> [foo = 17]
someData.free
All this means that you can 'not use the GC' whilst not disabling it. I am a performance tuning freak and I still use GC seqs all the time because the performance hit is actually using the heap instead of the stack, and worse, the actual allocation of heap memory - regardless of the language. The GC overhead is miniscule even with millions of seqs and would only even come into play when allocating memory inside loops. At that point, it's not the GC that's an issue, but the allocation pattern.
Again though, it's nice to be able to drop down to pointers easily when you do need every clock cycle.