You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This may seem an odd one, but for users, it makes updating far quicker and easier. Especially for portable packages, where setups like this can become stale and potentially cause issues down the line.
Perhaps theres a reason you dont wish to do this?
Proposed solution
A good reason for this, is that updating portable packages, means copying new files over existing installs. That means unpacking nearly twenty thousand files, copying them to temp, then copying them to the installed location, small files take a lot of time to enumerate and slow the process down considerably in my experience.
I completely understand if this is something you do NOT want to do, whatever your reasons, but I feel it keeps the install location clean without leaving redundant files in the process, which over time, could be numerous and possibly problematic.
Thanks for raising this, and sorry it took a bit to come back with something concrete. I wanted real numbers rather than a guess.
You were right about the cause. I measured the published 0.13.0 Windows package: 18,143 files, 883 MB unpacked. Copying that over an existing install is exactly as slow as you describe, and most of it is the bundled Python runtime, which barely changes between releases.
I went a different route than a single EXE though, and I want to be honest about why.
Why not embed Python into the EXE
The onefile modes (PyInstaller, Nuitka) do not really remove the files, they extract the whole payload to a temp folder on every launch. With torch, demucs and onnxruntime in there, that is well over a gigabyte unpacked each time you start the app. It trades a slow update for a slow startup, every single time. On top of that, torch's CUDA loading and onnxruntime's dynamic imports fight the frozen-import hooks, which is a lot of fragility for the machines that need GPU most.
So I attacked the actual cost instead: stop shipping the runtime on every update at all.
What is coming
1. The package itself got leaner (measured, not estimated):
0.13.0
now
files
18,143
16,056
size
883 MB
850 MB
That is 2,087 fewer files, mostly the Python standard library's own test suite and per-package test folders that are never imported at runtime.
2. The real fix: in-app updates. StemDeck now updates itself. When a new release is available you get an Update now button next to Download, and it fetches only the app layer:
5 MB and 123 files, instead of 284 MB and 16,056.
It swaps the app and restarts itself. Your data/ folder, settings, jobs and stems are untouched, and the Python runtime is never replaced at all, which is what keeps it small.
One caveat
Updating to the first release that includes this is still a manual download, since your current build has no updater in it. From the release after that, it is one click.
Also, when a release genuinely does change StemDeck's Python dependencies, the updater deliberately steps aside and sends you to the normal full download, because swapping the app without the matching runtime would break the install. Looking at the history that is roughly 1 release in 10.
This is in #423 and I have tested it end to end on Windows, including that your data survives the update. Manual copying stays available either way, so nothing is taken away.
Tbh, I literally only found out this morning that Python does that! I mean, about unpacking from the exe if embedded. I saw you were working on it and wasn't sure if to say anything, you probably wouldnt have seen my message. Sorry about that! I should've looked into it a bit more. But your solution is a great idea, and at least makes it for the most part much easier. This is one of the reasons I was trying to find a way around using python all morning! I'm looking at using Lazarus where possible for future projects. Though, I understand the likely ease and necessity in the use of certain apps, python makes sense. I just dislike how it functions this way personally.
Anyway, thanks for putting so much effort into this, you coulda just said no like most devs do, so thank you! Really appreciate what you've done. :D
@sl2365 Why I would say no to something that I'm building for everybody to have fun with? You have no idea how cool it is to see that something that I built for fun is being used for a lot of people :)
Anytime that you have a proposal and sugestion or anything feel free to reach :D
on another note, stay tunned for 0.15.0, I will be dropping in search for youtube and soundcloud today :)
Activity
fix(updater): make the in-app update actually work, verified end to e…
fix: address code-quality review on the version-source change (#421)
thcp commentedon Aug 23, 2026
Thanks for raising this, and sorry it took a bit to come back with something concrete. I wanted real numbers rather than a guess.
You were right about the cause. I measured the published 0.13.0 Windows package: 18,143 files, 883 MB unpacked. Copying that over an existing install is exactly as slow as you describe, and most of it is the bundled Python runtime, which barely changes between releases.
I went a different route than a single EXE though, and I want to be honest about why.
Why not embed Python into the EXE
The onefile modes (PyInstaller, Nuitka) do not really remove the files, they extract the whole payload to a temp folder on every launch. With torch, demucs and onnxruntime in there, that is well over a gigabyte unpacked each time you start the app. It trades a slow update for a slow startup, every single time. On top of that, torch's CUDA loading and onnxruntime's dynamic imports fight the frozen-import hooks, which is a lot of fragility for the machines that need GPU most.
So I attacked the actual cost instead: stop shipping the runtime on every update at all.
What is coming
1. The package itself got leaner (measured, not estimated):
That is 2,087 fewer files, mostly the Python standard library's own test suite and per-package test folders that are never imported at runtime.
2. The real fix: in-app updates. StemDeck now updates itself. When a new release is available you get an Update now button next to Download, and it fetches only the app layer:
5 MB and 123 files, instead of 284 MB and 16,056.
It swaps the app and restarts itself. Your
data/folder, settings, jobs and stems are untouched, and the Python runtime is never replaced at all, which is what keeps it small.One caveat
Updating to the first release that includes this is still a manual download, since your current build has no updater in it. From the release after that, it is one click.
Also, when a release genuinely does change StemDeck's Python dependencies, the updater deliberately steps aside and sends you to the normal full download, because swapping the app without the matching runtime would break the install. Looking at the history that is roughly 1 release in 10.
This is in #423 and I have tested it end to end on Windows, including that your data survives the update. Manual copying stays available either way, so nothing is taken away.
sl2365 commentedon Aug 23, 2026
Tbh, I literally only found out this morning that Python does that! I mean, about unpacking from the exe if embedded. I saw you were working on it and wasn't sure if to say anything, you probably wouldnt have seen my message. Sorry about that! I should've looked into it a bit more. But your solution is a great idea, and at least makes it for the most part much easier. This is one of the reasons I was trying to find a way around using python all morning! I'm looking at using Lazarus where possible for future projects. Though, I understand the likely ease and necessity in the use of certain apps, python makes sense. I just dislike how it functions this way personally.
Anyway, thanks for putting so much effort into this, you coulda just said no like most devs do, so thank you! Really appreciate what you've done. :D
feat(updater): extend the in-app update to Linux (#421)
fix(updater): see pre-releases, and compile the Rust in CI (#421)
test(e2e): match the releases-list shape the app now polls (#421)
Windows: leaner portable package and opt-in in-app updater (#421) (#423)
thcp commentedon Aug 25, 2026
@sl2365 Why I would say no to something that I'm building for everybody to have fun with? You have no idea how cool it is to see that something that I built for fun is being used for a lot of people :)
Anytime that you have a proposal and sugestion or anything feel free to reach :D
on another note, stay tunned for 0.15.0, I will be dropping in search for youtube and soundcloud today :)
sl2365 commentedon Aug 26, 2026
Yeah I understand that. Thanks, it's a really great app! You're doing a fantastic job!
ci: stop fork pull requests running on the self-hosted runners (#522)
fix(linux): verify the FFmpeg download against a pinned checksum (#530)
ci: stop fork pull requests running on the self-hosted runners