diff --git a/docs/guide/troubleshooting.md b/docs/guide/troubleshooting.md
index 7ea325d61c..464c600b00 100644
--- a/docs/guide/troubleshooting.md
+++ b/docs/guide/troubleshooting.md
@@ -69,7 +69,7 @@ export default defineConfig({
When `vite.config.ts` imports plugins at the top level, they are evaluated for every command, including `vp lint`, `vp fmt`, editor integrations, and long-lived background processes. This can make config loading slow and may trigger plugin setup side effects, such as reading files, starting watchers, or connecting to services.
-Use `lazyPlugins` to load plugins only when the Vite pipeline actually runs (`dev`, `build`, `test`, `preview`):
+Use `lazyPlugins` to skip the plugin factory when vite-plus loads your config only to read a metadata block (`lint`, `fmt`, `check`, `staged`, `pack`, `create`, the `run`/`cache` task lookup, and editor tooling). The plugins still load whenever Vite actually runs, `dev`, `build`, `test`, `preview`, and any build your own scripts spawn (a `vp run` task, `vp exec`):
```ts [vite.config.ts]
import { defineConfig, lazyPlugins } from 'vite-plus';
diff --git a/packages/cli/bin/oxfmt b/packages/cli/bin/oxfmt
index 142b0989ff..db9da6b699 100755
--- a/packages/cli/bin/oxfmt
+++ b/packages/cli/bin/oxfmt
@@ -23,8 +23,11 @@ const oxfmtBin = join(dirname(dirname(oxfmtMainPath)), 'bin', 'oxfmt');
// This allows oxfmt to load vite.config.ts.
// For `vp check` and `vp fmt`, VP_VERSION is injected by
-// `merge_resolved_envs_with_version()` in `cli.rs`, and VP_COMMAND is injected
-// by `SubcommandResolver::resolve()`.
+// `merge_resolved_envs_with_version()` in `cli.rs`.
process.env.VP_VERSION = pkg.version;
-process.env.VP_COMMAND ??= 'fmt';
+// oxfmt reads vite.config.ts only for the `fmt` block, so skip the user's
+// Vite plugin factory (lazyPlugins) while the config evaluates.
+// Literal kept in sync with CONFIG_METADATA_ENV in src/utils/constants.ts
+// (this plain-JS bin can't import the bundled constant).
+process.env.VP_RESOLVING_CONFIG_METADATA ??= '1';
await import(pathToFileURL(oxfmtBin).href);
diff --git a/packages/cli/bin/oxlint b/packages/cli/bin/oxlint
index e135a09cac..6b08f5afef 100755
--- a/packages/cli/bin/oxlint
+++ b/packages/cli/bin/oxlint
@@ -27,9 +27,12 @@ const tsgolintBin = resolveTsgolintExecutable(
// This allows oxlint to load vite.config.ts.
// For `vp check` and `vp lint`, VP_VERSION is injected by
-// `merge_resolved_envs_with_version()` in `cli.rs`, and VP_COMMAND is injected
-// by `SubcommandResolver::resolve()`.
+// `merge_resolved_envs_with_version()` in `cli.rs`.
process.env.VP_VERSION = pkg.version;
-process.env.VP_COMMAND ??= 'lint';
+// oxlint reads vite.config.ts only for the `lint` block, so skip the user's
+// Vite plugin factory (lazyPlugins) while the config evaluates.
+// Literal kept in sync with CONFIG_METADATA_ENV in src/utils/constants.ts
+// (this plain-JS bin can't import the bundled constant).
+process.env.VP_RESOLVING_CONFIG_METADATA ??= '1';
process.env.OXLINT_TSGOLINT_PATH ??= tsgolintBin;
await import(pathToFileURL(oxlintBin).href);
diff --git a/packages/cli/binding/src/cli/resolver.rs b/packages/cli/binding/src/cli/resolver.rs
index c050801113..578d525834 100644
--- a/packages/cli/binding/src/cli/resolver.rs
+++ b/packages/cli/binding/src/cli/resolver.rs
@@ -68,13 +68,7 @@ impl SubcommandResolver {
resolved_vite_config: Option<&ResolvedUniversalViteConfig>,
envs: &Arc