Migrate flatpaks from system to user - Problem solved - Script included

Description

So far there is no good tooling to move the flatpaks installed with the defaults from system to user. I did not want to go through them manually, so wrote a bash script flatpak_system_to_user.sh ( code below )

Example KDEnlive

Before:

knurpht@Lenovo-P16:~> flatpak --system list
Naam                                Toepassings-ID                                    Versie            Branch
TAP-plugins                         org.freedesktop.LinuxAudio.Plugins.TAP            1.0.1             24.08
SWH                                 org.freedesktop.LinuxAudio.Plugins.swh            0.4.17            24.08
Mesa                                org.freedesktop.Platform.GL.default               25.3.5            24.08
Mesa (Extra)                        org.freedesktop.Platform.GL.default               25.3.5            24.08extra
openh264                            org.freedesktop.Platform.openh264                 2.5.1             2.5.1
Adwaita theme                       org.kde.KStyle.Adwaita                                              6.9
KDE Application Platform            org.kde.Platform                                                    6.9
Kdenlive                            org.kde.kdenlive                                  25.12.2           stable
knurpht@Lenovo-P16:~> flatpak --system list | grep -i kdenlive
Kdenlive        org.kde.kdenlive        25.12.2 stable
knurpht@Lenovo-P16:~> flatpak --user list | grep -i kdenlive
knurpht@Lenovo-P16:~> 

This from my real system where I aleady ran the script, so the rest of the flatpaks are already there, just not KDEnlive and its deps.

The script

#!/usr/bin/env bash

# Name      : flatpak_system_to_user.sh
# Purpose   : Migrating system flatpaks from system to user
# 
# Usage: 
# - create the file in some folder, do `chmod +x flatpak_system_to_user.sh
# - run ./flatpak_system_to_user.sh as your user from that folder. 

set -euo pipefail

# Set some vars 
USER_NAME=$(whoami)
FLATPAK_REMOTE_NAME="flathub"
FLATPAK_REMOTE_URL="https://flathub.org/repo/flathub.flatpakrepo"
FLATPAK_REMOTE_USER=$(flatpak remote-list --user | awk '{print $1}' | grep -qx "$FLATPAK_REMOTE_NAME")


# Install flathub to the user if needed
echo "Checking for user remote"
if [[ "$(id -un)" != "$USER_NAME" ]]; then
  echo "Run this as $USER_NAME" >&2
  exit 1
fi

if [[ $FLATPAK_REMOTE_USER ]]; then
  echo "Adding flathub remote for user" >&2
  flatpak --user remote-add --if-not-exists "$FLATPAK_REMOTE_NAME" "$FLATPAK_REMOTE_URL"
else echo "User remote already setup"
fi


# Create lists from both system and user installed flatpaks
echo "Create lists from both system and user installed flatpaks" >&2
mapfile -t system_fp < <(flatpak --system list --columns=ref | awk 'NF {print $1}')
mapfile -t user_fp < <(flatpak --user list --columns=ref | awk 'NF {print $1}')

# Build a set of user‑installed flatpak refs
declare -A user_set
for ref in "${user_fp[@]}"; do
  user_set["$ref"]=1
done

# For each system flatpak, install in user if missing, then remove from system

for ref in "${system_fp[@]}"; do
echo "Migrating flatpaks to user install: $ref" >&2
  if [[ -n "${user_set[$ref]+x}" ]]; then
    echo "Already in user install: $ref" >&2
    echo "Uninstall flatpak from system: $ref" >&2
    sudo flatpak uninstall -y --system  --force-remove --noninteractive "$ref"
  else 
    echo "- Installing flatpak to user: $ref" >&2
    flatpak install -y --user --noninteractive flathub "$ref"    
    echo "Uninstall flatpak from system: $ref" >&2
    sudo flatpak uninstall -y --system --force-remove --noninteractive "$ref"
  continue
  fi

done
echo "Migration finished"

The script spits out some output on the way.

The result

Migration finished?
Let’s check

knurpht@Lenovo-P16:~/bin> flatpak --system list
knurpht@Lenovo-P16:~/bin> flatpak --system list
knurpht@Lenovo-P16:~/bin> flatpak --user list | grep -i kdenlive
Kdenlive        org.kde.kdenlive        25.12.2 stable
knurpht@Lenovo-P16:~/bin> 

On github

github repo: https://github.com/knurpht/flatpak_system_to_user.sh

7 Likes

DISCLAIMER: This script was created without the help of an AI agent.

5 Likes

And, here’s how to go about in Discover. If your user had only the default system entry, you will now see the user’s one. Enable it, disable or remove the stock one, and you will never need the script again.

THE END


And with this setting it will install as system again.
Mind, if you decide to do both system and user flatpaks for whatever reason, do not use the script gain.

knurpht@Lenovo-P16:/etc/sysconfig> flatpak --system list 
Naam                                              Toepassings-ID                                  Versie            Branch
Blanket                                           com.rafaelmardojai.Blanket                      0.8.0             stable
Mesa                                              org.freedesktop.Platform.GL.default             25.3.5            24.08
Mesa (Extra)                                      org.freedesktop.Platform.GL.default             25.3.5            24.08extra
openh264                                          org.freedesktop.Platform.openh264               2.5.1             2.5.1
GNOME Application Platform version 48             org.gnome.Platform                                                48
knurpht@Lenovo-P16:/etc/sysconfig> 
1 Like

Latesst version of the script
Code:

  #!/usr/bin/env bash

# Name      : flatpak_system_to_user.sh
# Purpose   : Migrating system flatpaks from system to user
# 
# Usage: 
# - create the file in some folder, do `chmod +x flatpak_system_to_user.sh
# - run ./flatpak_system_to_user.sh as your user from that folder. 


# Set some vars 
FLATPAK_REMOTE_NAME="flathub"
FLATPAK_REMOTE_URL="https://flathub.org/repo/flathub.flatpakrepo"
FLATPAK_REMOTE_DISABLED="disabled"
FLATPAK_REMOTE_USER=$(flatpak --user remote-list --show-disabled| awk '{print $1}')
FLATPAK_REMOTE_USER_DISABLED=$(flatpak --user remote-list --show-disabled | awk '{print $2}')
FLATPAK_SYSTEM_COUNT=0
FLATPAK_USER_COUNT=0

# Check whether user is not "root"
echo "Checking for permissions" >&2
if [[ ! $EUID > 0 ]]; then
  echo "Run this as your user, exiting" >&2
  exit 1
fi

# Install flathub remote to the user if needed
if [[ ! $FLATPAK_REMOTE_USER ]]; then
  echo "User flathub remote not installed" >&2
  echo "Adding flathub remote for user" >&2
  flatpak --user remote-add --if-not-exists "$FLATPAK_REMOTE_NAME" "$FLATPAK_REMOTE_URL"
  sleep 5
  flatpak --user remote-modify --enable "$FLATPAK_REMOTE_NAME" >/dev/null 2>&1
  echo "User flathub remote now enabled" >&2  
else 
  echo "User flathub remote already installed" >&2
  echo "Checking user flathub remote status" >&2 
  if [[ $FLATPAK_REMOTE_USER_DISABLED ]]; then
    echo "User flathub remote disabled" >&2
    flatpak --user remote-modify --enable "$FLATPAK_REMOTE_NAME" >/dev/null 2>&1
    echo "User flathub remote now enabled" >&2
  fi
  echo "User flatpak remote setup complete !" >&2
fi


# Create lists from both system and huser installed flatpaks
echo "Create lists from system and user installed flatpaks" >&2
mapfile -t system_fp < <(flatpak --system list --columns=ref | awk 'NF {print $1}')
mapfile -t user_fp < <(flatpak --user list --columns=ref | awk 'NF {print $1}')

# Build a set of user‑installed flatpak refs
declare -A user_set
for ref in "${user_fp[@]}"; do
  user_set["$ref"]=1
  ((FLATPAK_USER_COUNT++))
done
declare -A system_set
for ref in "${system_fp[@]}"; do
  system_set["$ref"]=1
  ((FLATPAK_SYSTEM_COUNT++))
done

OLD=$FLATPAK_SYSTEM_COUNT
FP=""
if [[ $OLD == 1 ]]; then
  FP="flatpak"
else
  FP="flatpaks"
fi

# For each system flatpak, install in user if missing, then remove from system
echo "Totals: To do: $OLD >> User: $FLATPAK_USER_COUNT" >&2
if [[ ! $OLD == 0 ]]; then
  for ref in "${system_fp[@]}"; do
    echo "Migrating $FLATPAK_SYSTEM_COUNT flatpaks to user install: $ref" >&2
    if [[ -n "${user_set[$ref]+x}" ]]; then 
      echo "- Already in user install: $ref" >&2
      echo "- Uninstalling flatpak from system: $ref" >&2
      sudo flatpak uninstall -y --system  --force-remove --noninteractive "$ref" >/dev/null 2>&1
      echo "- Uninstalled from system: $ref" >&2
      ((FLATPAK_SYSTEM_COUNT--))
      echo "Totals: To do: $FLATPAK_SYSTEM_COUNT | User: $FLATPAK_USER_COUNT" >&2
    else 
      echo "- Installing flatpak to user: $ref" >&2
      flatpak install -y --user --noninteractive flathub "$ref" >/dev/null 2>&1    
      echo "- Installed to user: $ref" >&2
      ((FLATPAK_USER_COUNT++))
      echo "- Totals: To do: $FLATPAK_SYSTEM_COUNT | User: $FLATPAK_USER_COUNT" >&2
      echo "- Uninstalling flatpak from system: $ref" >&2
      sudo flatpak uninstall -y --system --force-remove --noninteractive "$ref" >/dev/null 2>&1
      echo "- Uninstalled from system: $ref" >&2
      ((FLATPAK_SYSTEM_COUNT--))
      echo "- Totals: To do: $FLATPAK_SYSTEM_COUNT | User: $FLATPAK_USER_COUNT" >&2
    continue
    fi
  done
  echo "Migration of $OLD $FP to user flathub remote completed" >&2
else 
  echo "Migration of $FLATPAK_SYSTEM_COUNT $FP to user is useless, exiting" >&2
  exit 1
fi

Prove that I have a good test case:

knurpht@Lenovo-P16:~/bin> LANG=C flatpak --system list --columns=name,application
Name                                     Application ID
Mesa                                     org.freedesktop.Platform.GL.default
Mesa (Extra)                             org.freedesktop.Platform.GL.default
Codecs Extra Extension                   org.freedesktop.Platform.codecs-extra
Adwaita theme                            org.kde.KStyle.Adwaita
KDE Application Platform                 org.kde.Platform
Amarok                                   org.kde.amarok
knurpht@Lenovo-P16:~/bin> 
knurpht@Lenovo-P16:~/bin> LANG=C flatpak --user list --columns=name,application | grep amarok
knurpht@Lenovo-P16:~/bin> 

Now run the script:

knurpht@Lenovo-P16:~/bin> ./flatpak_system_to_user.sh 
Checking for permissions
User flathub remote not installed
Adding flathub remote for user
User flathub remote now enabled
Create lists from system and user installed flatpaks
Totals: To do: 6 >> User: 51
Migrating 6 flatpaks to user install: org.freedesktop.Platform.GL.default/x86_64/25.08
- Already in user install: org.freedesktop.Platform.GL.default/x86_64/25.08
- Uninstalling flatpak from system: org.freedesktop.Platform.GL.default/x86_64/25.08
- Uninstalled from system: org.freedesktop.Platform.GL.default/x86_64/25.08
Totals: To do: 5 | User: 51
Migrating 5 flatpaks to user install: org.freedesktop.Platform.GL.default/x86_64/25.08-extra
- Already in user install: org.freedesktop.Platform.GL.default/x86_64/25.08-extra
- Uninstalling flatpak from system: org.freedesktop.Platform.GL.default/x86_64/25.08-extra
- Uninstalled from system: org.freedesktop.Platform.GL.default/x86_64/25.08-extra
Totals: To do: 4 | User: 51
Migrating 4 flatpaks to user install: org.freedesktop.Platform.codecs-extra/x86_64/25.08-extra
- Already in user install: org.freedesktop.Platform.codecs-extra/x86_64/25.08-extra
- Uninstalling flatpak from system: org.freedesktop.Platform.codecs-extra/x86_64/25.08-extra
- Uninstalled from system: org.freedesktop.Platform.codecs-extra/x86_64/25.08-extra
Totals: To do: 3 | User: 51
Migrating 3 flatpaks to user install: org.kde.KStyle.Adwaita/x86_64/6.10
- Already in user install: org.kde.KStyle.Adwaita/x86_64/6.10
- Uninstalling flatpak from system: org.kde.KStyle.Adwaita/x86_64/6.10
- Uninstalled from system: org.kde.KStyle.Adwaita/x86_64/6.10
Totals: To do: 2 | User: 51
Migrating 2 flatpaks to user install: org.kde.Platform/x86_64/6.10
- Already in user install: org.kde.Platform/x86_64/6.10
- Uninstalling flatpak from system: org.kde.Platform/x86_64/6.10
- Uninstalled from system: org.kde.Platform/x86_64/6.10
Totals: To do: 1 | User: 51
Migrating 1 flatpaks to user install: org.kde.amarok/x86_64/stable
- Installing flatpak to user: org.kde.amarok/x86_64/stable
- Installed to user: org.kde.amarok/x86_64/stable
- Totals: To do: 1 | User: 52
- Uninstalling flatpak from system: org.kde.amarok/x86_64/stable
- Uninstalled from system: org.kde.amarok/x86_64/stable
- Totals: To do: 0 | User: 52
Migration of 6 flatpaks to user flathub remote completed
knurpht@Lenovo-P16:~/bin> 

Run it again:

knurpht@Lenovo-P16:~/bin> ./flatpak_system_to_user.sh 
Checking for permissions
User flathub remote already installed
Checking user flathub remote status
User flatpak remote setup complete !
Create lists from system and user installed flatpaks
Totals: To do: 0 >> User: 52
Migration of 0 flatpaks to user is useless, exiting
knurpht@Lenovo-P16:~/bin>
1 Like

Out of curiosity, why do you do so (i.e. converting from “system” to “user”)? I know that both is possible and many people use “user” and it is often told to do so. But why? When I use software by repository management (RPM) it is also “system”, isn’t it. What are actual advantages of “user” — what are actual disadvantages of “system”?

There is a big difference between running apps entirely as your user, and running system apps. Despite the sandboxing of flatpaks.

My personal reasons were basically that some people had already pointed out that moving all from system installed to user installed was possible via Discover / Gnome Software, but not a fun job when one has 80 flatpaks installed, and that there are no tools that can do that for you in one go. I have those days that I think “OK, let’s make this a little bash script” and added the challenge of not using AI agents or copy-paste-edit from elsewhere on the web, but only own bash knowledge, notes and my own script library.
The fun for me is writing something that does the job, then see how it can be expanded and more elegant codewise and verbositywise. Things I’m currently considering:

  • Adding user interaction
  • Adding selective sysem → user migration
  • Making it work both ways
  • Packaging the script
  • Ultimately make it a GUI tool for manipulating flatpak installs.

You mean security wise?

When yes, then why are they installed by the system manager on the system?

And now the system manager wants users who want to use them to copy them to their own space for security? within a given time space because after that the system manager will remove them from the system?

Sorry, but I try to understand the need for this.

When installed from a user remote, there is no system manager involved, unless you insist that flatpak itself was installed by the system manager. You can see from the script that I don’t

  • run the script as root
  • that I install the remote for the user as the user
  • that I only do need root permissions to interact with the system uninstalls

Now, we both know

  • that bad things can happen in software, backdoors, malicious instructions etc.
  • the difference between an app running with such as system app and the same app running entirely as userin such cases.

Then there is another thing: You and some of my “local customers” have their homedir on a separate partition, that they reuse on a reinstall. With their entire flatpak environment living in their homedir, there is no need to reinstall their flatpaks, A matter of conveniance.
Like said, I personally don’t care that much, it was started as and still is a fun project. If you, or anyone else, see potential improvements or issues, I would appreciate your contributions. Fork the repo, improve the script, send a merge/pull request and after reviewing with good outcome I’ll gladly merge the MR/ PR into the main branch.

What do you actually mean by “system apps”?

AFAIK, when Flatpaks installed by system context (instead of user context), I still use them as a user with user rights (not as some system or root). But they are available for all my users on my system (not only the current one — in that case each user would have to manage the Flatpaks on their own, each).

Do sandboxing really differ between managed by system context and managed by user context? I mean, the Flatpaks are managed by system context… but they are actually run (normally) by user context. At least, I do so.

1 Like

@C7NhtpnK they should all run at a user level, less chance of having system related issues, better to balk a user on the system rather than the system for multiple users…

1 Like

Thank you so much! I have been putting this off for the longest time precisely because of how long it would take me manually. Doing god’s work here, brother, cheers

1 Like