diff --git a/Makefile.am b/Makefile.am
index 310a231259..9fd77c6f43 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@
 # Copyright © 2018 Julien Lepiller <julien@lepiller.eu>
 # Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
 # Copyright © 2018 Alex Vong <alexvong1995@gmail.com>
-# Copyright © 2019 Efraim Flashner <efraim@flashner.co.il>
+# Copyright © 2019, 2023 Efraim Flashner <efraim@flashner.co.il>
 # Copyright © 2020, 2021, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com>
 # Copyright © 2021 Chris Marusich <cmmarusich@gmail.com>
 # Copyright © 2021 Andrew Tropin <andrew@trop.in>
@@ -184,6 +184,7 @@ MODULES =					\
   guix/build-system/texlive.scm			\
   guix/build-system/tree-sitter.scm		\
   guix/build-system/trivial.scm			\
+  guix/build-system/vim.scm			\
   guix/ftp-client.scm				\
   guix/http-client.scm				\
   guix/gnupg.scm				\
@@ -241,6 +242,7 @@ MODULES =					\
   guix/build/scons-build-system.scm		\
   guix/build/texlive-build-system.scm		\
   guix/build/tree-sitter-build-system.scm	\
+  guix/build/vim-build-system.scm		\
   guix/build/waf-build-system.scm		\
   guix/build/haskell-build-system.scm		\
   guix/build/julia-build-system.scm		\
diff --git a/doc/guix.texi b/doc/guix.texi
index 3517c95251..89db688132 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -9482,6 +9482,39 @@ Build Systems
 @end itemize
 @end defvar
 
+@defvar vim-build-system
+This variable is exported by @code{(guix build-system vim)}.  It is an
+extension of the @pref{Copy Build System, @code{copy-build-system}}, installing
+vim and neovim plugins into locations where these two text editors know to find
+their plugins, using their packpaths.
+
+Packages which are prefixed with @code{vim-} will be installed in vim's
+packpath, while those prefixed with @code{neovim-} will be installed in
+neovim's packpath.  If there is a @code{doc} directory with the plugin then
+helptags will be generated automatically.
+
+There are a couple of keywords added with the @code{vim-build-system}:
+@itemize
+@item With @code{plugin-name} it is possible to set the name of the plugin.  By
+default this is set to the name and version of the package, it is often more
+helpful to set this to name which the upstream author calls their plugin.
+@item With @code{install-plan} it is possible to augment the built-in
+install-plan of the @code{vim-build-system}.  This is particularly helpful if
+you have files which should be installed in other locations.  For more
+information about using the @code{install-plan}, take a look at the @pref{Copy
+Build System, @code{copy-build-system}}.
+@item With @code{#:vim} it is possible to add this package to vim's packpath,
+in addition to if it is added automatically because of the @code{vim-} prefix.
+@item With @code{#:neovim} it is possible to add this package to neovim's
+packpath, in addition to if it is added automatically because of the
+@code{neovim-} prefix.
+@item With @code{#:mode} it is possible to adjust the path which the plugin is
+installed into.  By default the plugin is installed into @code{start} and other
+options are available, including @code{opt}.  Adding a plugin into @code{opt}
+will mean you will need to run, for example, @command{:packadd foo} to load the
+@code{foo} plugin from inside of vim.
+@end itemize
+@end defvar
 
 @cindex Clojure (programming language)
 @cindex simple Clojure build system
diff --git a/guix/build-system/vim.scm b/guix/build-system/vim.scm
new file mode 100644
index 0000000000..81f08ff436
--- /dev/null
+++ b/guix/build-system/vim.scm
@@ -0,0 +1,157 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 Jonathan Scoresby <me@jonscoresby.com>
+;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build-system vim)
+  #:use-module (guix store)
+  #:use-module (guix utils)
+  #:use-module (guix gexp)
+  #:use-module (guix monads)
+  #:use-module (guix packages)
+  #:use-module (guix search-paths)
+  #:use-module (guix build-system)
+  #:use-module (guix build-system copy)
+  #:use-module (guix build-system gnu)
+  #:export (%vim-build-system-modules vim-build vim-build-system))
+
+;; Commentary:
+;;
+;; Standard package installer for vim and neovim plugins.
+;; This is implemented as an extension of `copy-build-system'
+;; and takes advantage of vim and neovim's built-in package manager.
+;; It extends the installation procedure from the copy-build-system
+;; to put files in the correct place and then generates help tags.
+;;
+;; Code:
+
+(define %vim-build-system-modules
+  ;; Build-side modules imported by default.
+  `((guix build vim-build-system)
+    ,@%copy-build-system-modules))
+
+(define (default-vim)
+  "Return the default Vim package."
+  ;; Lazily resolve the binding to avoid a circular dependency.
+  (let ((vim (resolve-interface '(gnu packages vim))))
+    (module-ref vim 'vim)))
+
+(define (default-neovim)
+  "Return the default Neovim package."
+  (let ((vim (resolve-interface '(gnu packages vim))))
+    (module-ref vim 'neovim)))
+
+(define* (lower name
+                #:key source
+                inputs
+                native-inputs
+                outputs
+                system
+                target
+                (vim? #f)
+                (neovim? #f)
+                (plugin-name name)
+                (vim (default-vim))
+                (neovim (default-neovim))
+                #:allow-other-keys #:rest arguments)
+  "Return a bag for NAME."
+  (let* ((private-keywords '(#:target #:vim #:neovim #:inputs #:native-inputs))
+         (vim? (or (string-prefix? "vim" name)
+                   vim?))
+         (neovim? (or (string-prefix? "neovim" name)
+                      neovim?))
+         (vim-inputs (append (if vim?
+                                 `(("vim" ,vim))
+                                 '())
+                             (if neovim?
+                                 `(("neovim" ,neovim))
+                                 '())))
+         (vim-arguments (append arguments
+                                `(#:vim? ,vim?
+                                  #:neovim? ,neovim?))))
+    (bag (name name)
+         (system system)
+         (host-inputs `(,@(if source
+                              `(("source" ,source))
+                              '()) ,@inputs
+
+                        ;; Keep the standard inputs of 'gnu-build-system'.
+                        ,@(standard-packages)))
+         (build-inputs `(,@vim-inputs ,@native-inputs))
+         (outputs outputs)
+         (build vim-build)
+         (arguments (strip-keyword-arguments private-keywords vim-arguments)))))
+
+(define* (vim-build name inputs
+                    #:key guile
+                    source
+                    (vim? #f)
+                    (neovim? #f)
+                    (mode "start")
+                    (plugin-name name)
+                    (install-plan ''())
+                    (phases '(@ (guix build vim-build-system) %standard-phases))
+                    (outputs '("out"))
+                    (search-paths '())
+                    (system (%current-system))
+                    (substitutable? #t)
+                    (imported-modules %vim-build-system-modules)
+                    (modules '((guix build vim-build-system)
+                               (guix build utils))))
+
+  (define build
+    (with-imported-modules imported-modules
+      #~(begin
+          (use-modules #$@modules)
+          #$(with-build-variables inputs outputs
+              #~(vim-build #:name #$name
+                           #:vim? #$vim?
+                           #:neovim? #$neovim?
+                           #:mode #$mode
+                           #:plugin-name #$plugin-name
+                           #:install-plan #$(if (pair? install-plan)
+                                                (sexp->gexp install-plan)
+                                                install-plan)
+                           #:source #+source
+                           #:system #$system
+                           #:phases #$(if (pair? phases)
+                                          (sexp->gexp phases)
+                                          phases)
+                           #:outputs %outputs
+                           #:search-paths '#$(sexp->gexp
+                                               (map search-path-specification->sexp
+                                                    search-paths))
+                           #:inputs
+                           %build-inputs)))))
+
+  (mlet %store-monad
+        ((guile (package->derivation (or guile (default-guile))
+                                     system #:graft? #f)))
+        (gexp->derivation name
+                          build
+                          #:system system
+                          #:target #f
+                          #:graft? #f
+                          #:substitutable? substitutable?
+                          #:guile-for-build guile)))
+
+(define vim-build-system
+  (build-system (name 'vim)
+                (description "The standard Vim build system")
+                (lower lower)))
+
+;;; vim.scm ends here
diff --git a/guix/build/vim-build-system.scm b/guix/build/vim-build-system.scm
new file mode 100644
index 0000000000..28c0f8f83f
--- /dev/null
+++ b/guix/build/vim-build-system.scm
@@ -0,0 +1,117 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2022 Jonathan Scoresby <me@jonscoresby.com>
+;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il>
+;;;
+;;; This file is part of GNU Guix.
+;;;
+;;; GNU Guix is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; GNU Guix is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
+
+(define-module (guix build vim-build-system)
+  #:use-module ((guix build copy-build-system)
+                #:prefix copy:)
+  #:use-module (guix build utils)
+  #:use-module (ice-9 match)
+  #:use-module (ice-9 ftw)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:export (%standard-phases vim-build))
+
+;; Commentary:
+;;
+;; System for installing vim and neovim plugins. It downloads
+;; the source and copies the appropriate files to vim and nvim
+;; packpaths. It then generates helptags.
+;;
+;; Code:
+
+(define copy:install
+  (assoc-ref copy:%standard-phases 'install))
+
+(define vim-path
+  "/share/vim/vimfiles/pack/guix/")
+(define nvim-path
+  "/share/nvim/site/pack/guix/")
+
+(define* (install #:key plugin-name
+                  install-plan
+                  neovim?
+                  vim?
+                  mode
+                  outputs
+                  #:allow-other-keys)
+
+  (let* ((include-regexp '(".*\\/.*\\/.*"))
+         (exclude-regexp '("^scripts/.*"
+                           "tests?/.*" "^t/.*"
+                           "assets/.*"
+                           ".*\\/\\..*"))
+         (vim-install (if vim?
+                          `(("." ,(string-append vim-path mode "/" plugin-name "/")
+                             #:include-regexp ,include-regexp
+                             #:exclude-regexp ,exclude-regexp))
+                          '()))
+         (neovim-install (if neovim?
+                             `(("." ,(string-append nvim-path mode "/" plugin-name "/")
+                                #:include-regexp ,include-regexp
+                                #:exclude-regexp ,exclude-regexp))
+                             '())))
+    (copy:install #:outputs outputs
+                  #:install-plan (append vim-install
+                                         neovim-install
+                                         install-plan))))
+
+(define* (generate-helptags #:key plugin-name
+                            neovim?
+                            vim?
+                            mode
+                            outputs
+                            #:allow-other-keys)
+
+  (define (vim-generate output)
+    (invoke "vim" "--clean" "-en" "--cmd"
+            (string-append "helptags "
+                           output vim-path mode "/" plugin-name "/doc")
+            "--cmd" "q"))
+
+  (define (neovim-generate output)
+    (invoke "nvim" "--clean" "--headless" "-en" "--cmd"
+            (string-append "helptags "
+                           output nvim-path mode "/" plugin-name "/doc")
+            "--cmd" "q"))
+
+  (when (scandir "./doc")
+    (let ((out (assoc-ref outputs "out")))
+      (when vim?
+            (vim-generate out))
+      (when neovim?
+            (neovim-generate out)))))
+
+(define %standard-phases
+  ;; Everything is as with the Copy Build System except for
+  ;; the addition of the generate-helptags phase and a few
+  ;; custom actions are added to the install phase
+  (modify-phases copy:%standard-phases
+    (replace 'install install)
+    (add-after 'install 'generate-helptags generate-helptags)))
+
+(define* (vim-build #:key inputs
+                    (phases %standard-phases)
+                    #:allow-other-keys #:rest args)
+  "Build the given package, applying all of PHASES in order."
+  (apply copy:copy-build
+         #:inputs inputs
+         #:phases phases
+         args))
+
+;;; vim-build-system.scm ends here
