The effect of SetOutPath on the location of the file in the installer archive directory tree should IMO be noted in the User Manual.
Standard case:
SetOutPath "$INSTDIR/bin" ; Program installed and archived in 'bin'.
File "path\to\program.exe"
Special case:
SetOutPath "$INSTDIR/bin" ; Program installed in 'bin' ...
Goto +2
SetOutPath "$INSTDIR/bin64" ; ... but archived in 'bin64'.
File "path\to\program.exe"
This (hidden) feature makes sense, see:
https://nsis.sourceforge.io/Installing_mutual_exclusive_Versions_of_Programs
AFAICS, there is no extra statement to control the archive directory, so the above hack is useful in special cases. Therefore it would make sense to document this and keep the behavior stable in future releases.
Interestingly SetOutPath affects also (and only) the archive subdirectory of the uninstaller:
SetOutPath "$INSTDIR\doc" ; Uninstaller archived in 'doc' ...
File "path\to\README.txt"
WriteUninstaller "uninstall.exe" ; ... but installed in '$INSTDIR' root.
All tested with NSIS 3.11
Are you talking about the directory structure that appears when you open the installer in 7-zip? That is not a real directory structure. Our installers don't have an actual archive embedded in them. At least not one in any commonly used format that supports directory structures. That structure seems to be deduced from script ops based on your findings. This would be an issue with the heuristics used by 7-zip. I have noticed some other oddities with, for example, the plugins folder over the years. You will notice similar issues with files that get extracted with multiple different names as NSIS will only save them once in its internal structure. 7-zip is doing the best it can.
Yes, I mean the view provided by 7-Zip, and yes, 7-Zip does a good job (but see PS:). It does not matter to the end user whether the actual format is considered to contain a real directory structure (whatever this exactly means). There is at least some directory information which allows to distinguish files with same same.
In the smartmontools project, we provide 32-bit and 64-bit executables in a single NSIS installer by using this hidden
SetOutPathbehavior since 2012 (see r3544 aka cc751080949d).Feel free to call this a hack :-)
See for example recent CI builds at https://github.com/smartmontools/smartmontools-builds/releases
and the recently added fully signed (all .exe and .ps1, including uninstaller, excluding plugin) installers:
https://github.com/smartmontools/smartmontools/actions/workflows/signpath.yml
PS: For some reason, 7zip does not always list the uninstaller since we moved our docker-build image to Debian 13 which updated NSIS to 3.11.
Last edit: Christian Franke 2026-01-11
There is no directory structure at all. 7-zip reverse engineers the script to try and deduce a directory structure. That can never be totally accurate as the script has runtime dependencies.
Sorry but this is not going to be documented or supported. NSIS installers are not archives.
7-zip might be interested in enhancing their reverse engineering to support such use cases.
Thanks for clarification and sorry for the noise.
PS: Updated this page accordingly:
https://nsis.sourceforge.io/Installing_mutual_exclusive_Versions_of_Programs