diff --git a/ci/docker/indent/prepare.sh b/ci/docker/indent/prepare.sh
index 462e29f940..4ee196c8f3 100755
--- a/ci/docker/indent/prepare.sh
+++ b/ci/docker/indent/prepare.sh
@@ -33,7 +33,7 @@ meson install -C _build
 wget -O gstbayer2rgb.c "https://gitlab.freedesktop.org/gstreamer/gstreamer/-/raw/main/subprojects/gst-plugins-bad/gst/bayer/gstbayer2rgb.c?inline=false"
 
 for i in 1 2; do
-indent \
+gst-indent-1.0 \
   --braces-on-if-line \
   --case-brace-indentation0 \
   --case-indentation2 \
diff --git a/gst-env.py b/gst-env.py
index 594dc39728..2da1adbb05 100755
--- a/gst-env.py
+++ b/gst-env.py
@@ -283,7 +283,7 @@ def get_subprocess_env(options, gst_version):
         return get_wine_subprocess_env(options, env)
 
     prepend_env_var(env, "PATH", os.path.join(SCRIPTDIR, 'meson'),
-        options.sysroot)
+                    options.sysroot)
 
     env["GST_PLUGIN_SYSTEM_PATH"] = ""
     env["GST_PLUGIN_SCANNER"] = os.path.normpath(
@@ -304,10 +304,10 @@ def get_subprocess_env(options, gst_version):
         lib_path_envvar = 'LD_LIBRARY_PATH'
 
     prepend_env_var(env, "GST_PLUGIN_PATH", os.path.join(SCRIPTDIR, 'subprojects',
-                                                        'gst-python', 'plugin'),
+                                                         'gst-python', 'plugin'),
                     options.sysroot)
     prepend_env_var(env, "GST_PLUGIN_PATH", os.path.join(PREFIX_DIR, 'lib',
-                                                        'gstreamer-1.0'),
+                                                         'gstreamer-1.0'),
                     options.sysroot)
     prepend_env_var(env, "GST_PLUGIN_PATH", os.path.join(options.builddir, 'subprojects',
                                                          'libnice', 'gst'),
@@ -322,7 +322,11 @@ def get_subprocess_env(options, gst_version):
     prepend_env_var(env, "PKG_CONFIG_PATH", os.path.join(PREFIX_DIR, 'lib', 'pkgconfig'),
                     options.sysroot)
 
-    # gst-indent
+    # gst-indent-1.0
+    prepend_env_var(env, "PATH", os.path.join(options.builddir, 'subprojects',
+                    'gst-indent', 'src'),
+                    options.sysroot)
+    # gst-indent (FIXME: remove or move into gst-indent module)
     prepend_env_var(env, "PATH", os.path.join(SCRIPTDIR, 'scripts'),
                     options.sysroot)
 
@@ -502,7 +506,7 @@ def get_subprocess_env(options, gst_version):
 
 def get_windows_shell():
     command = ['powershell.exe', '-noprofile', '-executionpolicy', 'bypass', '-file',
-        os.path.join(SCRIPTDIR, 'data', 'misc', 'cmd_or_ps.ps1')]
+               os.path.join(SCRIPTDIR, 'data', 'misc', 'cmd_or_ps.ps1')]
     result = subprocess.check_output(command)
     return result.decode().strip()
 
@@ -588,7 +592,8 @@ if __name__ == "__main__":
                 for p in BASH_COMPLETION_PATHS:
                     if os.path.exists(p):
                         bash_completions_files += os.listdir(path=p)
-                bc_rc = BC_RC.format(bash_completions=' '.join(bash_completions_files), bash_completions_paths=' '.join(BASH_COMPLETION_PATHS))
+                bc_rc = BC_RC.format(bash_completions=' '.join(bash_completions_files),
+                                     bash_completions_paths=' '.join(BASH_COMPLETION_PATHS))
                 tmprc.write(bc_rc)
                 tmprc.flush()
             args.append("--rcfile")
diff --git a/meson.build b/meson.build
index d28f530c6d..fa57997fb9 100644
--- a/meson.build
+++ b/meson.build
@@ -677,6 +677,8 @@ if dotnet_format.found()
     )
 endif
 
+indent = find_program('gst-indent-1.0', native: true, required: get_option('gst-indent').allowed())
+
 summary({
   'gstreamer-full library': building_full,
   'gstreamer-full target type': get_option('gst-full-target-type'),
diff --git a/meson_options.txt b/meson_options.txt
index d73d9cce34..6baaed6cbe 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -45,6 +45,7 @@ option('gst-full-target-type', type : 'combo', value : 'shared_library', choices
 option('orc-source', type: 'combo', choices: ['system', 'subproject', 'auto'], value: 'subproject')
 option('build-tools-source', type: 'combo', choices: ['system', 'subproject'], value: 'subproject')
 option('virtme_kernel_image', type: 'string', value: '', description: 'Path to a Linux kernel image to be used for virtme testing')
+option('gst-indent', type: 'feature', value: 'auto', description: 'Whether to build the gst-indent tool')
 
 # License-related feature options
 option('gpl', type: 'feature', value: 'disabled',
diff --git a/scripts/gst-indent.py b/scripts/gst-indent.py
new file mode 100755
index 0000000000..4222aa44f3
--- /dev/null
+++ b/scripts/gst-indent.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+import subprocess
+from sys import argv
+import shutil
+
+if __name__ == '__main__':
+    indent = shutil.which('gst-indent-1.0')
+
+    if not indent:
+        raise RuntimeError('''Did not find gst-indent-1.0, please install it before continuing.''')
+
+    version = subprocess.run([indent, '--version'], capture_output=True, text=True)
+
+    if 'GNU' not in version.stdout:
+        raise RuntimeError(f'''Did not find gst-indent-1.0, please install it before continuing.
+      (Found {indent}, but it doesn't seem to be gst-indent-1.0)''')
+
+    # Run twice. GNU indent isn't idempotent
+    # when run once
+    for i in range(2):
+        subprocess.check_call([indent,
+            '--braces-on-if-line',
+            '--case-brace-indentation0',
+            '--case-indentation2',
+            '--braces-after-struct-decl-line',
+            '--line-length80',
+            '--no-tabs',
+            '--cuddle-else',
+            '--dont-line-up-parentheses',
+            '--continuation-indentation4',
+            '--honour-newlines',
+            '--tab-size8',
+            '--indent-level2',
+            '--leave-preprocessor-space'] + argv[1:]
+        )
diff --git a/subprojects/gst-indent.wrap b/subprojects/gst-indent.wrap
new file mode 100644
index 0000000000..ac1430fd60
--- /dev/null
+++ b/subprojects/gst-indent.wrap
@@ -0,0 +1,8 @@
+[wrap-git]
+directory=gst-indent
+url=https://gitlab.freedesktop.org/gstreamer/gst-indent.git
+push-url=git@gitlab.freedesktop.org:gstreamer/gst-indent.git
+revision=main
+
+[provide]
+program_names = gst-indent-1.0
diff --git a/subprojects/gstreamer/libs/gst/check/libcheck/README.txt b/subprojects/gstreamer/libs/gst/check/libcheck/README.txt
index cc0f2ed27c..e4414646e2 100644
--- a/subprojects/gstreamer/libs/gst/check/libcheck/README.txt
+++ b/subprojects/gstreamer/libs/gst/check/libcheck/README.txt
@@ -21,7 +21,7 @@ Steps to sync with upstream:
 
 1. Clone libcheck from the above git repository
 2. Copy files into this directory
-3. Run GNU indent on all the code
+3. Run gst-indent-1.0 on all the code
 4. Fix internal #includes
 5. Manually inspect the diff
 6. Update configure.ac, m4/check-checks.m4, meson.build files, etc