diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index 9da8b27a91778..93900a9043e7e 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -9,7 +9,7 @@ use std::sync::mpsc::SyncSender;
 use build_helper::git::get_git_modified_files;
 use ignore::WalkBuilder;
 
-use crate::core::builder::Builder;
+use crate::core::builder::{Builder, Kind};
 use crate::utils::build_stamp::BuildStamp;
 use crate::utils::exec::command;
 use crate::utils::helpers::{self, t};
@@ -122,6 +122,12 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) {
 }
 
 pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
+    if build.kind == Kind::Format && build.top_stage != 0 {
+        eprintln!("ERROR: `x fmt` only supports stage 0.");
+        eprintln!("HELP: Use `x run rustfmt` to run in-tree rustfmt.");
+        crate::exit!(1);
+    }
+
     if !paths.is_empty() {
         eprintln!(
             "fmt error: path arguments are no longer accepted; use `--all` to format everything"
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 7ff385052940e..0bba441c3fa26 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -420,3 +420,56 @@ impl Step for CoverageDump {
         cmd.run(builder);
     }
 }
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct Rustfmt;
+
+impl Step for Rustfmt {
+    type Output = ();
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/rustfmt")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(Rustfmt);
+    }
+
+    fn run(self, builder: &Builder<'_>) {
+        let host = builder.build.build;
+
+        // `x run` uses stage 0 by default but rustfmt does not work well with stage 0.
+        // Change the stage to 1 if it's not set explicitly.
+        let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 {
+            builder.top_stage
+        } else {
+            1
+        };
+
+        if stage == 0 {
+            eprintln!("rustfmt cannot be run at stage 0");
+            eprintln!("HELP: Use `x fmt` to use stage 0 rustfmt.");
+            std::process::exit(1);
+        }
+
+        let compiler = builder.compiler(stage, host);
+        let rustfmt_build = builder.ensure(tool::Rustfmt { compiler, target: host });
+
+        let mut rustfmt = tool::prepare_tool_cargo(
+            builder,
+            rustfmt_build.build_compiler,
+            Mode::ToolRustc,
+            host,
+            Kind::Run,
+            "src/tools/rustfmt",
+            SourceType::InTree,
+            &[],
+        );
+
+        rustfmt.args(["--bin", "rustfmt", "--"]);
+        rustfmt.args(builder.config.args());
+
+        rustfmt.into_cmd().run(builder);
+    }
+}
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 15dc3380a39a3..75cc5d3986b88 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -1116,6 +1116,7 @@ impl<'a> Builder<'a> {
                 run::FeaturesStatusDump,
                 run::CyclicStep,
                 run::CoverageDump,
+                run::Rustfmt,
             ),
             Kind::Setup => {
                 describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor)
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index d926185ffaf1c..1d0ea3ebf6105 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -406,4 +406,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "Added a new option `rust.debug-assertions-tools` to control debug asssertions for tools.",
     },
+    ChangeInfo {
+        change_id: 140732,
+        severity: ChangeSeverity::Info,
+        summary: "`./x run` now supports running in-tree `rustfmt`, e.g., `./x run rustfmt -- --check /path/to/file.rs`.",
+    },
 ];