diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md
index c6e54dc1fe..a51678b621 100644
--- a/NEXT_CHANGELOG.md
+++ b/NEXT_CHANGELOG.md
@@ -13,5 +13,6 @@
 * When glob for wheels is used, like "\*.whl", it will filter out different version of the same package and will only take the most recent version. ([#2982](https://github.com/databricks/cli/pull/2982))
 * When building Python artifacts as part of "bundle deploy" we no longer delete `dist`, `build`, `*egg-info` and `__pycache__` directories. ([#2982](https://github.com/databricks/cli/pull/2982))
 * Fix variable resolution for lookup variables with other references ([#3054](https://github.com/databricks/cli/pull/3054))
+* Added preset `presets.artifacts_dynamic_version` that automatically enables `dynamic_version: true` on all "whl" artifacts.
 
 ### API Changes
diff --git a/acceptance/bundle/artifacts/artifacts_dynamic_version/databricks.yml b/acceptance/bundle/artifacts/artifacts_dynamic_version/databricks.yml
new file mode 100644
index 0000000000..c2134924c2
--- /dev/null
+++ b/acceptance/bundle/artifacts/artifacts_dynamic_version/databricks.yml
@@ -0,0 +1,10 @@
+presets:
+  artifacts_dynamic_version: true
+
+artifacts:
+  first_wheel:
+    type: whl
+    build: uv build --wheel
+  second_wheel:
+    type: jar
+    build: true
diff --git a/acceptance/bundle/artifacts/artifacts_dynamic_version/output.txt b/acceptance/bundle/artifacts/artifacts_dynamic_version/output.txt
new file mode 100644
index 0000000000..8b4936fa85
--- /dev/null
+++ b/acceptance/bundle/artifacts/artifacts_dynamic_version/output.txt
@@ -0,0 +1,18 @@
+{
+  "first_wheel": {
+    "build": "uv build --wheel",
+    "dynamic_version": true,
+    "files": [
+      {
+        "source": "[TEST_TMP_DIR]/dist/*.whl"
+      }
+    ],
+    "path": "[TEST_TMP_DIR]",
+    "type": "whl"
+  },
+  "second_wheel": {
+    "build": "true",
+    "path": "[TEST_TMP_DIR]",
+    "type": "jar"
+  }
+}
diff --git a/acceptance/bundle/artifacts/artifacts_dynamic_version/script b/acceptance/bundle/artifacts/artifacts_dynamic_version/script
new file mode 100644
index 0000000000..c3ba9bd25f
--- /dev/null
+++ b/acceptance/bundle/artifacts/artifacts_dynamic_version/script
@@ -0,0 +1 @@
+$CLI bundle validate -o json | jq .artifacts
diff --git a/acceptance/bundle/artifacts/artifacts_dynamic_version/test.toml b/acceptance/bundle/artifacts/artifacts_dynamic_version/test.toml
new file mode 100644
index 0000000000..93ee159927
--- /dev/null
+++ b/acceptance/bundle/artifacts/artifacts_dynamic_version/test.toml
@@ -0,0 +1,5 @@
+RecordRequests = false
+
+[[Repls]]
+Old = '\\\\'
+New = '/'
diff --git a/acceptance/bundle/debug/out.stderr.txt b/acceptance/bundle/debug/out.stderr.txt
index 9e72c92fe2..614238bf53 100644
--- a/acceptance/bundle/debug/out.stderr.txt
+++ b/acceptance/bundle/debug/out.stderr.txt
@@ -52,6 +52,7 @@
 10:07:59 Debug: Apply pid=12345 mutator=CheckPermissions
 10:07:59 Debug: Apply pid=12345 mutator=TranslatePaths
 10:07:59 Debug: Apply pid=12345 mutator=PythonWrapperWarning
+10:07:59 Debug: Apply pid=12345 mutator=ApplyArtifactsDynamicVersion
 10:07:59 Debug: Apply pid=12345 mutator=artifacts.Prepare
 10:07:59 Info: No local tasks in databricks.yml config, skipping auto detect pid=12345 mutator=artifacts.Prepare
 10:07:59 Debug: Apply pid=12345 mutator=apps.Validate
diff --git a/bundle/config/mutator/artifacts_dynamic_version.go b/bundle/config/mutator/artifacts_dynamic_version.go
new file mode 100644
index 0000000000..9d66a7619b
--- /dev/null
+++ b/bundle/config/mutator/artifacts_dynamic_version.go
@@ -0,0 +1,38 @@
+package mutator
+
+import (
+	"context"
+
+	"github.com/databricks/cli/bundle"
+	"github.com/databricks/cli/libs/diag"
+)
+
+type artifactsUseDynamicVersion struct{}
+
+// ApplyArtifactsDynamicVersion configures all artifacts to use dynamic_version when the preset is enabled.
+func ApplyArtifactsDynamicVersion() bundle.Mutator {
+	return &artifactsUseDynamicVersion{}
+}
+
+func (m *artifactsUseDynamicVersion) Name() string {
+	return "ApplyArtifactsDynamicVersion"
+}
+
+func (m *artifactsUseDynamicVersion) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
+	if !b.Config.Presets.ArtifactsDynamicVersion {
+		return nil
+	}
+
+	for _, a := range b.Config.Artifacts {
+		if a == nil {
+			continue
+		}
+		if a.Type != "whl" {
+			// This has no effect since we only apply DynamicVersion if type is "whl" but it makes output cleaner.
+			continue
+		}
+		a.DynamicVersion = true
+	}
+
+	return nil
+}
diff --git a/bundle/config/presets.go b/bundle/config/presets.go
index 252c5b5f74..46562067ae 100644
--- a/bundle/config/presets.go
+++ b/bundle/config/presets.go
@@ -24,6 +24,9 @@ type Presets struct {
 	// File synchronization to ${workspace.file_path} is skipped.
 	SourceLinkedDeployment *bool `json:"source_linked_deployment,omitempty"`
 
+	// ArtifactsDynamicVersion enables dynamic_version on every artifact.
+	ArtifactsDynamicVersion bool `json:"artifacts_dynamic_version,omitempty"`
+
 	// Tags to add to all resources.
 	Tags map[string]string `json:"tags,omitempty"`
 }
diff --git a/bundle/internal/schema/annotations.yml b/bundle/internal/schema/annotations.yml
index c68bca50f9..a7ab9a8ba5 100644
--- a/bundle/internal/schema/annotations.yml
+++ b/bundle/internal/schema/annotations.yml
@@ -104,6 +104,9 @@ github.com/databricks/cli/bundle/config.Lock:
     "description": |-
       Whether to force this lock if it is enabled.
 github.com/databricks/cli/bundle/config.Presets:
+  "artifacts_dynamic_version":
+    "description": |-
+      Whether to enable dynamic_version on all artifacts.
   "jobs_max_concurrent_runs":
     "description": |-
       The maximum concurrent runs for a job.
diff --git a/bundle/phases/initialize.go b/bundle/phases/initialize.go
index c3d3d27656..7af9d61329 100644
--- a/bundle/phases/initialize.go
+++ b/bundle/phases/initialize.go
@@ -151,6 +151,11 @@ func Initialize(ctx context.Context, b *bundle.Bundle) diag.Diagnostics {
 		// Provides warnings when Python wheel tasks are used with DBR < 13.3 or when wheel wrapper is incompatible with source-linked deployment
 		trampoline.WrapperWarning(),
 
+		// Reads (typed): b.Config.Presets.ArtifactsDynamicVersion (checks if artifacts preset is enabled)
+		// Updates (typed): b.Config.Artifacts[].DynamicVersion (sets to true when preset is enabled)
+		// Applies the artifacts_dynamic_version preset to enable dynamic versioning on all artifacts
+		mutator.ApplyArtifactsDynamicVersion(),
+
 		// Reads (typed): b.Config.Artifacts, b.BundleRootPath (checks artifact configurations and bundle path)
 		// Updates (typed): b.Config.Artifacts (auto-creates Python wheel artifact if none defined but setup.py exists)
 		// Updates (dynamic): artifacts.*.{path,build_command,files.*.source} (sets default paths, build commands, and makes relative paths absolute)
diff --git a/bundle/schema/jsonschema.json b/bundle/schema/jsonschema.json
index 5b220c5c0b..517766be58 100644
--- a/bundle/schema/jsonschema.json
+++ b/bundle/schema/jsonschema.json
@@ -1795,6 +1795,10 @@
                 {
                   "type": "object",
                   "properties": {
+                    "artifacts_dynamic_version": {
+                      "description": "Whether to enable dynamic_version on all artifacts.",
+                      "$ref": "#/$defs/bool"
+                    },
                     "jobs_max_concurrent_runs": {
                       "description": "The maximum concurrent runs for a job.",
                       "$ref": "#/$defs/int"
