Nix doesn't work by redirecting symlinks, much less between different versions of the same package. So there is no race condition as you describe.
Simply, if package A depends on package B then A's files will end up mentioning the absolute path to B directly (say, /nix/store/abcdef-b-1.0/bin/some-bin-file, where "abcdef" is a hash).
If package C depends on a different version of package B, then C's files will contain the path to a version of B with another hash and possibly a different version number (say, /nix/store/zywxabc-b-1.1/bin/some-bin-file).
Thanks, let me clarify my question with a proper example. Let's say I install A-1.0 and A-1.1. Both versions will depend on say a resource file they expect is at /usr/share/A.res
I was thinking that nix would symlink /bin/A -> /nix/store/abcdef-A-1.0/bin/A, and also /usr/share/A.res -> /nix/store/abcdef-A-1.0/usr/share/A.res
So when I'm upgrading to A-1.1, maybe the /bin/A symlink would update a moment before the /usr/share/A.res symlink, which means invoking A at around the same time as the upgrade could pick up the wrong resource.
Do we just try to make sure that binaries know to look for resources relative to their binary-path? Or do we use chroot/containers? Sorry if this is a dumb question :)
So, in Nix (and in NixOS) there is no /bin and there is no /usr/share.
So either A.res gets installed at /nix/store/abcdef-A-1.0/share/A.res and at /nix/store/xyw123-A-1.1/share/A.res, in case A.res is part of A, or, if it's considered a dependency, then it gets installed at /nix/store/jgh456-some-other-package-2.3/share/A.res which both A-1.0 and A-1.1 depend on.
Also, A-1.0 and A-1.1 may depend on exactly the same "some-other-package" or they may depend on different versions, which would be OK since the hash of some-other-package will be different for different versions (or different variations of the same version), so there would never be a conflict.
As other posters mentioned, there is something called a user profile (and a system profile for NixOS) which does contain symlinks to the final binaries that are supposed to be in $PATH for some user (or all users, in the case of the system profile).
But these are only symlinks to the top-level binaries. The binaries themselves (and all their dependencies, including data and other binaries) contain hardcoded paths, they don't get redirected through symlinks. So once the top-level symlink gets resolved by your shell, everything is hardcoded from then on, no package sees some half-between state of their data or their dependencies' data or binaries.
You could even have multiple versions of the same package running at the same time without any conflict, as long as their mutable data is stored in different directories. For example, you can have different versions of Firefox running at the same time, as long as they use different Firefox profiles (if you try to run the same Firefox profile with different versions of Firefox at the same time, the second Firefox will complain that it is already running, as it should -- this is not very different from trying to run the same program twice at the same time).
And also, these user profiles are themselves updated/modified atomically through a single symlink, so your effective $PATH is either the old one or the new one, but never anything in-between.
PS: to answer your question, yes, we do indeed make sure that binaries know to look for resources in the right place.
Rather than look for the files relative to their path, usually packages have a "./configure" script which allows someone to tell where to install resources such as data files, man pages, etc. Usually people install resources in /usr/share or /usr/local/share (or even $HOME/share in some cases). In Nix, we just tell the package to install their files in /nix/store/abcdef-A-1.0/share and binaries will usually know where to find these resources based on the path provided to ./configure (and if for some reason they don't, we do patch source files to make sure that they do).
Simply, if package A depends on package B then A's files will end up mentioning the absolute path to B directly (say, /nix/store/abcdef-b-1.0/bin/some-bin-file, where "abcdef" is a hash).
If package C depends on a different version of package B, then C's files will contain the path to a version of B with another hash and possibly a different version number (say, /nix/store/zywxabc-b-1.1/bin/some-bin-file).