diff --git a/compiler/GHC/Driver/Main.hs b/compiler/GHC/Driver/Main.hs
index a514b76198d021c79085e1a4e68014bcddf4edd2..d1609e0913db87d48e831d77326cf6b1db0e4d92 100644
--- a/compiler/GHC/Driver/Main.hs
+++ b/compiler/GHC/Driver/Main.hs
@@ -261,6 +261,8 @@ import GHC.Utils.Misc
 import GHC.Utils.Logger
 import GHC.Utils.TmpFs
 
+import qualified GHC.LanguageExtensions as LangExt
+
 import GHC.Data.FastString
 import GHC.Data.Bag
 import GHC.Data.StringBuffer
@@ -871,6 +873,15 @@ hscRecompStatus
            , IsBoot <- isBootSummary mod_summary -> do
                msg UpToDate
                return $ HscUpToDate checked_iface emptyHomeModInfoLinkable
+
+           -- Always recompile with the JS backend when TH is enabled until
+           -- #23013 is fixed.
+           | ArchJavaScript <- platformArch (targetPlatform lcl_dflags)
+           , xopt LangExt.TemplateHaskell lcl_dflags
+           -> do
+              msg $ needsRecompileBecause THWithJS
+              return $ HscRecompNeeded $ Just $ mi_iface_hash $ mi_final_exts $ checked_iface
+
            | otherwise -> do
                -- Do need linkable
                -- 1. Just check whether we have bytecode/object linkables and then
diff --git a/compiler/GHC/Iface/Recomp.hs b/compiler/GHC/Iface/Recomp.hs
index b4ad91267a7d332d9e5c74b2831482232c141a3f..48b24b903b785a5a2a8fa6bab0e0ab05bafce31b 100644
--- a/compiler/GHC/Iface/Recomp.hs
+++ b/compiler/GHC/Iface/Recomp.hs
@@ -197,6 +197,7 @@ data RecompReason
   | MismatchedDynHiFile
   | ObjectsChanged
   | LibraryChanged
+  | THWithJS
   deriving (Eq)
 
 instance Outputable RecompReason where
@@ -229,6 +230,7 @@ instance Outputable RecompReason where
     MismatchedDynHiFile     -> text "Mismatched dynamic interface file"
     ObjectsChanged          -> text "Objects changed"
     LibraryChanged          -> text "Library changed"
+    THWithJS                -> text "JS backend always recompiles modules using Template Haskell for now (#23013)"
 
 recompileRequired :: RecompileRequired -> Bool
 recompileRequired UpToDate = False
diff --git a/testsuite/tests/annotations/should_run/all.T b/testsuite/tests/annotations/should_run/all.T
index a0d19cacaea606a56e158076433a4e7ad425557f..bea2a3f3327e8b7886507386b3283999adce5643 100644
--- a/testsuite/tests/annotations/should_run/all.T
+++ b/testsuite/tests/annotations/should_run/all.T
@@ -9,6 +9,9 @@ setTestOpts(when(fast(), skip))
 test('annrun01',
      [extra_files(['Annrun01_Help.hs']),
       req_th,
+      js_broken(23013), # strangely, the workaround for #23013 triggers
+                        # a call to an undefined FFI function in bytestring.
+                        # Before, it was slow but not failing.
       when(js_arch(), compile_timeout_multiplier(5)),
       pre_cmd('$MAKE -s --no-print-directory config'),
       omit_ways(['dyn'] + prof_ways)],
diff --git a/testsuite/tests/driver/OneShotTH.stdout-javascript-unknown-ghcjs b/testsuite/tests/driver/OneShotTH.stdout-javascript-unknown-ghcjs
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/testsuite/tests/driver/fat-iface/fat010.stdout-javascript-unknown-ghcjs b/testsuite/tests/driver/fat-iface/fat010.stdout-javascript-unknown-ghcjs
new file mode 100644
index 0000000000000000000000000000000000000000..b82a13ab215f8c25ecadfed26c1c75a0805b8f81
--- /dev/null
+++ b/testsuite/tests/driver/fat-iface/fat010.stdout-javascript-unknown-ghcjs
@@ -0,0 +1,5 @@
+[1 of 3] Compiling THA
+[2 of 3] Compiling THB
+[3 of 3] Compiling THC
+[1 of 3] Compiling THA [JS backend always recompiles modules using Template Haskell for now (#23013)]
+[2 of 3] Compiling THB [Source file changed]
diff --git a/testsuite/tests/driver/recompHash/recompHash.stdout-javascript-unknown-ghcjs b/testsuite/tests/driver/recompHash/recompHash.stdout-javascript-unknown-ghcjs
new file mode 100644
index 0000000000000000000000000000000000000000..4411099410cbb72327905e1b865574ff8195bffc
--- /dev/null
+++ b/testsuite/tests/driver/recompHash/recompHash.stdout-javascript-unknown-ghcjs
@@ -0,0 +1,3 @@
+[1 of 2] Compiling B
+[2 of 2] Compiling A
+[2 of 2] Compiling A [JS backend always recompiles modules using Template Haskell for now (#23013)]
diff --git a/testsuite/tests/driver/recompNoTH/recompNoTH.stdout-javascript-unknown-ghcjs b/testsuite/tests/driver/recompNoTH/recompNoTH.stdout-javascript-unknown-ghcjs
new file mode 100644
index 0000000000000000000000000000000000000000..2238b3d677ee9d744f987581a8d96d126d0f1365
--- /dev/null
+++ b/testsuite/tests/driver/recompNoTH/recompNoTH.stdout-javascript-unknown-ghcjs
@@ -0,0 +1,4 @@
+[1 of 2] Compiling B
+[2 of 2] Compiling A
+[1 of 2] Compiling B [Source file changed]
+[2 of 2] Compiling A [JS backend always recompiles modules using Template Haskell for now (#23013)]
diff --git a/testsuite/tests/driver/th-new-test/th-new-test.stdout-javascript-unknown-ghcjs b/testsuite/tests/driver/th-new-test/th-new-test.stdout-javascript-unknown-ghcjs
new file mode 100644
index 0000000000000000000000000000000000000000..06382d8af7b82a9b8844071ddd5833007c8874a0
--- /dev/null
+++ b/testsuite/tests/driver/th-new-test/th-new-test.stdout-javascript-unknown-ghcjs
@@ -0,0 +1,26 @@
+[1 of 6] Compiling B
+[2 of 6] Compiling A
+[3 of 6] Compiling D
+[4 of 6] Compiling C
+[5 of 6] Compiling Main
+[6 of 6] Linking Main
+[1 of 6] Compiling B [JS backend always recompiles modules using Template Haskell for now (#23013)]
+[2 of 6] Compiling A [JS backend always recompiles modules using Template Haskell for now (#23013)]
+[3 of 6] Compiling D [JS backend always recompiles modules using Template Haskell for now (#23013)]
+[4 of 6] Compiling C [JS backend always recompiles modules using Template Haskell for now (#23013)]
+[6 of 6] Linking Main [Objects changed]
+[1 of 6] Compiling B [Source file changed]
+[2 of 6] Compiling A [B[TH] changed]
+[3 of 6] Compiling D [JS backend always recompiles modules using Template Haskell for now (#23013)]
+[4 of 6] Compiling C [D[TH] changed]
+[6 of 6] Linking Main [Objects changed]
+[1 of 6] Compiling B [JS backend always recompiles modules using Template Haskell for now (#23013)]
+[2 of 6] Compiling A [JS backend always recompiles modules using Template Haskell for now (#23013)]
+[3 of 6] Compiling D [Source file changed]
+[4 of 6] Compiling C [D[TH] changed]
+[6 of 6] Linking Main [Objects changed]
+[1 of 6] Compiling B [Source file changed]
+[2 of 6] Compiling A [B[TH] changed]
+[3 of 6] Compiling D [Source file changed]
+[4 of 6] Compiling C [D[TH] changed]
+[6 of 6] Linking Main [Objects changed]