diff --git a/.helmignore b/.helmignore
index 941be0f9c3828f7c637bb4e48d46af847069810d..bb24c23d0366a66cd8707457a9886f98f1622677 100644
--- a/.helmignore
+++ b/.helmignore
@@ -25,3 +25,4 @@ Screenshot*
 CHANGELOG.md
 LICENSE
 renovate.json
+node_modules
diff --git a/templates/nextcloud-onlyoffice-config.yaml b/templates/nextcloud-onlyoffice-config.yaml
index 90037544dcc1318bb0a5315c920c6c1838b2fba3..e1b7666df3023b5d58114c3ad2ed6f9205e1561a 100644
--- a/templates/nextcloud-onlyoffice-config.yaml
+++ b/templates/nextcloud-onlyoffice-config.yaml
@@ -31,11 +31,14 @@ data:
     #
     # This script gets executed by a post-install,post-upgrade helm hook, which
     #
-    #   * Persists and loads the onlyoffice-config.json config file
-    #   * Runs upgrade routines after installation of a new release.
-    #   * Updates all applications
     #   * Installs all apps declared in the `apps` helm values array
+    #     * Installs all apps
+    #     * Updates pinned apps if their pinned version has changed
+    #     * Always updates unpinned apps to their newest version
+    #   * Runs upgrade routines after installation of a new release or new
+    #     pinned apps.
     #   * Configures single-sign-on
+    #   * Persists and loads the onlyoffice-config.json config file
     #   * Updates database indices, columns, keys, etc needed after NC upgrade
 
     set -ev
@@ -49,6 +52,7 @@ data:
     # Enable app store so we can run `install` and `enable` commands
     php $occ config:system:set appstoreenabled --type boolean --value true
 
+    app_versions=$(php occ app:list --output json)
 
     # Install all apps declared in the `apps` helm values array
     {{- range .Values.apps }}
@@ -56,35 +60,27 @@ data:
     # Apps with a pinned version number are downloaded from GitHub so we can
     # update the pin with Renovatebot
 
-    # Get currently installed app version without using jq. Empty string if
-    # nothing is installed
-    # This counts on pipefail being off!
-    current_version=$(php occ app:list --output json | grep -o '"{{ .name }}":"[0-9]\+.[0-9]\+.[0-9]\+"' | grep -o '[0-9]\+.[0-9]\+.[0-9]\+' | cat)
-
-    if [ "$current_version" != "{{ .version }}" ]
+    if [[ $app_versions =~ '"{{ .name }}":"{{ .version }}"' ]]
     then
-      echo "Upgrading app {{ .github_repository }} from '$current_version' to '{{ .version }}'"
+      echo "App {{ .name }} is up-to-date at version {{ .version }}"
+    else
+      echo "No match in ${app_versions} for \"{{ .name }}\":\"{{ .version }}\","
+      echo "Installing app {{ .github_repository }} version '{{ .version }}'"
       # Where to install the app
-      target_directory="/var/www/html/custom_apps/{{ .name }}"
-      tmpdir=$(mktemp --directory)
-      cd $tmpdir
+      target_directory="/var/www/html/custom_apps"
       # We need to edit $ to be able to use `tpl` inside a `range`,
       # see https://github.com/helm/helm/issues/5979#issuecomment-518231758
       # allows us to use version variable in the release_filename
       {{- $_ := set $ "version" .version}}
-      curl "https://github.com/{{ .github_repository }}/releases/download/v{{ .version }}/{{ tpl .release_filename $ }}" -Lo {{ .name }}.tar.gz
-      tar -xf {{ .name }}.tar.gz
+      curl "https://github.com/{{ .github_repository }}/releases/download/v{{ .version }}/{{ tpl .release_filename $ }}" -Lo "{{ .name }}.tar.gz"
       # Remove old version of the app
-      if [[ -d $target_directory ]] 
+      if [[ -d "$target_directory/{{ .name }}" ]]
       then
-        rm -r $target_directory
+        rm -r "$target_directory/{{ .name }}"
       fi
-      # Move app directory into target directory
-      mv {{ .name }} $target_directory
-      cd -
-      rm -r $tmpdir
-    else
-      echo "App {{ .name }} is up-to-date"
+      # Extract app into target directory. The app tars usually contain a folder
+      # named after the app name
+      tar -xf "{{ .name }}.tar.gz" -C "$target_directory"
     fi
     {{- else }}
     # Unpinned app
@@ -92,14 +88,14 @@ data:
         php $occ app:install {{ .name }} --keep-disabled --no-interaction
     else
         # Update the app to its latest version
-        php $occ app:update --all --no-interaction
+        php $occ app:update {{ .name }} --no-interaction
     fi
-    {{ end }}
+    {{ end }} # end if and .github_repository .version
     {{- if .enabled }}
     # Enable {{ .name }} app
     php $occ app:enable {{ .name }}
-    {{ end }} # -- end {{ .name }}
-    {{ end }} # end range {{ .Values.apps }}
+    {{ end }} # end if .enabled
+    {{ end }} # end range .Values.apps
 
     # Some of the manually installed apps might need to run upgrade scripts, run
     # them now
diff --git a/values-local.yaml.example b/values-local.yaml.example
index 7b02ddb2e2653cc268e14a8d856d52782f8f1b93..8777439089d7eb4f20235f7f52666e8c99c42ca0 100644
--- a/values-local.yaml.example
+++ b/values-local.yaml.example
@@ -69,10 +69,12 @@ rabbitmq:
 #   - name: polls
 #     # Install an app from a github repository. This has the advantage that you
 #     # can pin the version number, so it does not get auto-updated to breaking
-#     # versions
+#     # versions.
+#     # Note: you can use the version number in the release_filename variable if
+#     # needed, as written here:
 #     github_repository: nextcloud/polls
 #     version: 3.8.1
-#     release_filename: polls-.8.1.tar.gz
+#     release_filename: polls-{{ .version }}.tar.gz
 #     enabled: true
 
 # sociallogin enables login via oAuth/Open-ID Connect