It's not that the node is non-destroyable. It just exists at a level of the SceneTree that isn't freed when scenes change. It's the same concept as a variable outside the scope of a function.
The singletons and the active scene get added to the root viewport. To see this in action, create a singleton and do the following:
func _ready():
for child in get_tree().get_root().get_children():
printt(child, child.get_name())
So if you'd like to scope things in the same fashion in code you could manage the children manually by retrieving the root viewport. Then applying the methods add_child()
, remove_child()
, move_child()
, etc.
var root = get_tree().get_root()
root.add_child(my_node)