diff --git a/gnu/system.scm b/gnu/system.scm
index 0d98e5a036..e05f5938bc 100644
--- a/gnu/system.scm
+++ b/gnu/system.scm
@@ -1060,71 +1060,124 @@ (define* (operating-system-etc-service os)
         ;; Startup file for POSIX-compliant login shells, which set system-wide
         ;; environment variables.
         (profile    (mixed-text-file "profile"  "\
-# Crucial variables that could be missing in the profiles' 'etc/profile'
-# because they would require combining both profiles.
-# FIXME: See <http://bugs.gnu.org/20255>.
-export MANPATH=$HOME/.guix-profile/share/man:/run/current-system/profile/share/man
-export INFOPATH=$HOME/.guix-profile/share/info:/run/current-system/profile/share/info
-export XDG_DATA_DIRS=$HOME/.guix-profile/share:/run/current-system/profile/share
-export XDG_CONFIG_DIRS=$HOME/.guix-profile/etc/xdg:/run/current-system/profile/etc/xdg
-
-# Make sure libXcursor finds cursors installed into user or system profiles.  See <http://bugs.gnu.org/24445>
-export XCURSOR_PATH=$HOME/.icons:$HOME/.guix-profile/share/icons:/run/current-system/profile/share/icons
+# Set the umask, notably for users logging in via 'lsh'.
+# See <http://bugs.gnu.org/22650>.
+umask 022
 
 # Ignore the default value of 'PATH'.
 unset PATH
 
-# Load the system profile's settings.
-GUIX_PROFILE=/run/current-system/profile ; \\
-. /run/current-system/profile/etc/profile
-
 # Since 'lshd' does not use pam_env, /etc/environment must be explicitly
 # loaded when someone logs in via SSH.  See <http://bugs.gnu.org/22175>.
-# We need 'PATH' to be defined here, for 'cat' and 'cut'.  Do this before
-# reading the user's 'etc/profile' to allow variables to be overridden.
-if [ -f /etc/environment -a -n \"$SSH_CLIENT\" \\
-     -a -z \"$LINUX_MODULE_DIRECTORY\" ]
+# Do this before reading the user's 'etc/profile' to allow variables to be
+# overridden.
+if [ -f /etc/environment ] && [ -n \"$SSH_CLIENT\" ] &&
+     [ -z \"$LINUX_MODULE_DIRECTORY\" ]
 then
   . /etc/environment
-  export `cat /etc/environment | cut -d= -f1`
+  export \"$(/run/current-system/profile/bin/cut -d= -f1 < /etc/environment)\"
 fi
 
-# Arrange so that ~/.config/guix/current comes first,
-# and guix-home comes before guix-profile.
-for profile in \"$HOME/.guix-profile\"        \\
-               \"$HOME/.guix-home/profile\"   \\
-               \"$HOME/.config/guix/current\"
-do
-  if [ -f \"$profile/etc/profile\" ]
-  then
-    # Load the user profile's settings.
-    GUIX_PROFILE=\"$profile\" ; \\
-    . \"$profile/etc/profile\"
-  else
-    # At least define this one so that basic things just work
-    # when the user installs their first package.
-    export PATH=\"$profile/bin:$PATH\"
-  fi
-done
+# Merge search paths and set up environment for all default profiles.
+eval \"$(/run/current-system/profile/bin/guix package \\
+  --search-paths=prefix \\
+  --profile=\"$HOME/.config/guix/current\" \\
+  --profile=\"$HOME/.guix-profile\" \\
+  --profile=\"$HOME/.guix-home/profile\" \\
+  --profile=/run/current-system/profile)\"
+
+# Make ‘guix pull’ profile work out of the box.
+GUIX_PROFILE=\"$HOME/.config/guix/current\"
+case $PATH in
+  *$GUIX_PROFILE/bin*) ;;
+  *) export PATH=\"$GUIX_PROFILE/bin${PATH:+:}$PATH\" ;;
+esac
+# Expose the latest Guix modules to Guile so guix shell and repls spawned by
+# e.g. Geiser work out of the box.
+case $GUILE_LOAD_PATH in
+  *$GUIX_PROFILE/share/guile/site/3.0*) ;;
+  *) export GUILE_LOAD_PATH=\"$GUIX_PROFILE/share/guile/site/3.0${GUILE_LOAD_PATH:+:}$GUILE_LOAD_PATH\" ;;
+esac
+case $GUILE_LOAD_COMPILED_PATH in
+  *$GUIX_PROFILE/lib/guile/3.0/site-ccache*) ;;
+  *) export GUILE_LOAD_COMPILED_PATH=\"$GUIX_PROFILE/lib/guile/3.0/site-ccache${GUILE_LOAD_COMPILED_PATH:+:}$GUILE_LOAD_COMPILED_PATH\" ;;
+esac
+unset GUIX_PROFILE
 
 # Prepend privileged programs.
-export PATH=/run/privileged/bin:$PATH
-
-# Arrange so that ~/.config/guix/current/share/info comes first.
-export INFOPATH=\"$HOME/.config/guix/current/share/info:$INFOPATH\"
-
-# Set the umask, notably for users logging in via 'lsh'.
-# See <http://bugs.gnu.org/22650>.
-umask 022
-
-# Allow Hunspell-based applications (IceCat, LibreOffice, etc.) to
-# find dictionaries.
-export DICPATH=\"$HOME/.guix-profile/share/hunspell:/run/current-system/profile/share/hunspell\"
-
+export PATH=\"/run/privileged/bin:$PATH\"
+
+# Crucial variables that could be missing in the profiles' 'etc/profile'.
+if [ -z \"$XDG_DATA_DIRS\" ]; then
+  export XDG_DATA_DIRS=\"`
+         `$HOME/.guix-profile/share:`
+         `$HOME/.guix-home/profile/share:`
+         `/run/current-system/profile/share\"
+fi
+if [ -z \"$XDG_CONFIG_DIRS\" ]; then
+  export XDG_CONFIG_DIRS=\"`
+         `$HOME/.guix-profile/etc/xdg:`
+         `$HOME/.guix-home/profile/etc/xdg:`
+         `/run/current-system/profile/etc/xdg\"
+fi
+# When MANPATH is unset, add a trailing colon so the system default search path
+# is used.
+if [ -z \"$MANPATH\" ]; then
+  export MANPATH=\"`
+         `$HOME/.guix-profile/share/man:`
+         `$HOME/.guix-home/profile/share/man:`
+         `/run/current-system/profile/share/man:\"
+fi
+# When INFOPATH is unset, add a trailing colon so Emacs searches
+# 'Info-default-directory-list'.
+if [ -z \"$INFOPATH\" ]; then
+  export INFOPATH=\"`
+         `$HOME/.config/guix/current/share/info:`
+         `$HOME/.guix-profile/share/info:`
+         `$HOME/.guix-home/profile/share/info:`
+         `/run/current-system/profile/share/info:\"
+else
+  case $INFOPATH in
+    *$HOME/.config/guix/current/share/info*) ;;
+    *) export INFOPATH=\"$HOME/.config/guix/current/share/info:$INFOPATH\" ;;
+  esac
+fi
+# Make sure libXcursor finds cursors installed into user or system profiles.
+# See <http://bugs.gnu.org/24445>
+if [ -z \"$XCURSOR_PATH\" ]; then
+  export XCURSOR_PATH=\"`
+         `$HOME/.icons:`
+         `$HOME/.guix-profile/share/icons:`
+         `$HOME/.guix-home/profile/share/icons:`
+         `/run/current-system/profile/share/icons\"
+else
+  case $XCURSOR_PATH in
+    *$HOME/.icons*) ;;
+    *) export XCURSOR_PATH=\"$HOME/.icons:$XCURSOR_PATH\" ;;
+  esac
+fi
+# Allow Hunspell-based applications (IceCat, LibreOffice, etc.) to find
+# dictionaries.
+if [ -z \"$DICPATH\" ]; then
+  export DICPATH=\"`
+         `$HOME/.guix-profile/share/hunspell:`
+         `$HOME/.guix-home/profile/share/hunspell:`
+         `/run/current-system/profile/share/hunspell\"
+fi
 # Allow GStreamer-based applications to find plugins.
-export GST_PLUGIN_PATH=\"$HOME/.guix-profile/lib/gstreamer-1.0\"
+if [ -z \"$GST_PLUGIN_PATH\" ]; then
+  export GST_PLUGIN_PATH=\"`
+         `$HOME/.guix-profile/lib/gstreamer-1.0:`
+         `$HOME/.guix-home/profile/lib/gstreamer-1.0:`
+         `/run/current-system/profile/lib/gstreamer-1.0\"
+fi
+
+# Set up extra environment variables for Guix Home.
+HOME_ENVIRONMENT=\"$HOME/.guix-home\"
+[ -L \"$HOME_ENVIRONMENT\" ] && . \"$HOME_ENVIRONMENT/setup-environment\"
+unset HOME_ENVIRONMENT
 
-if [ -n \"$BASH_VERSION\" -a -f /etc/bashrc ]
+if [ -n \"$BASH_VERSION\" ] && [ -f /etc/bashrc ]
 then
   # Load Bash-specific initialization code.
   . /etc/bashrc
diff --git a/gnu/system/shadow.scm b/gnu/system/shadow.scm
index b68a818871..cdb804da18 100644
--- a/gnu/system/shadow.scm
+++ b/gnu/system/shadow.scm
@@ -179,16 +179,6 @@ (define %default-bash-profile
 
 # Honor per-interactive-shell startup file
 if [ -f ~/.bashrc ]; then . ~/.bashrc; fi
-
-# Merge search-paths from multiple profiles, the order matters.
-eval \"$(guix package --search-paths \\
--p $HOME/.config/guix/current \\
--p $HOME/.guix-home/profile \\
--p $HOME/.guix-profile \\
--p /run/current-system/profile)\"
-
-# Prepend setuid programs.
-export PATH=/run/setuid-programs:$PATH
 "))
 
 (define %default-zprofile
