diff --git a/.changeset/eighty-hairs-remain.md b/.changeset/eighty-hairs-remain.md
new file mode 100644
index 000000000000..55cd8e1fcd74
--- /dev/null
+++ b/.changeset/eighty-hairs-remain.md
@@ -0,0 +1,5 @@
+---
+'svelte': minor
+---
+
+feat: add $effect.active rune
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js
index 6a301726b106..b4a69e5a24c9 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js
@@ -109,6 +109,7 @@ export function CallExpression(node, context) {
 
 			break;
 
+		case '$effect.active':
 		case '$effect.tracking':
 			if (node.arguments.length !== 0) {
 				e.rune_invalid_arguments(node, rune);
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js
index 79dccd5a7cf5..4de72a4217c1 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/Identifier.js
@@ -53,10 +53,6 @@ export function Identifier(node, context) {
 				parent = /** @type {Expression} */ (context.path[--i]);
 
 				if (!is_rune(name)) {
-					if (name === '$effect.active') {
-						e.rune_renamed(parent, '$effect.active', '$effect.tracking');
-					}
-
 					if (name === '$state.frozen') {
 						e.rune_renamed(parent, '$state.frozen', '$state.raw');
 					}
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/CallExpression.js
index 7a3057451aa1..9f1e355703cb 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/CallExpression.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/CallExpression.js
@@ -17,6 +17,9 @@ export function CallExpression(node, context) {
 		case '$effect.tracking':
 			return b.call('$.effect_tracking');
 
+		case '$effect.active':
+			return b.call('$.effect_active');
+
 		case '$state.snapshot':
 			return b.call(
 				'$.snapshot',
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js
index afb90bbec7f9..dea8924e4730 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js
@@ -25,6 +25,7 @@ export function VariableDeclaration(node, context) {
 			if (
 				!rune ||
 				rune === '$effect.tracking' ||
+				rune === '$effect.active' ||
 				rune === '$effect.root' ||
 				rune === '$inspect' ||
 				rune === '$inspect.trace' ||
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/CallExpression.js
index 386c6b6ff393..ee2b18c889c3 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/CallExpression.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/CallExpression.js
@@ -16,7 +16,7 @@ export function CallExpression(node, context) {
 		return b.id('undefined');
 	}
 
-	if (rune === '$effect.tracking') {
+	if (rune === '$effect.tracking' || rune === '$effect.active') {
 		return b.literal(false);
 	}
 
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js
index 31de811ac76f..b3e875b7d084 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js
@@ -19,7 +19,13 @@ export function VariableDeclaration(node, context) {
 		for (const declarator of node.declarations) {
 			const init = declarator.init;
 			const rune = get_rune(init, context.state.scope);
-			if (!rune || rune === '$effect.tracking' || rune === '$inspect' || rune === '$effect.root') {
+			if (
+				!rune ||
+				rune === '$effect.tracking' ||
+				rune === '$effect.active' ||
+				rune === '$inspect' ||
+				rune === '$effect.root'
+			) {
 				declarations.push(/** @type {VariableDeclarator} */ (context.visit(declarator)));
 				continue;
 			}
diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js
index f22c33babc52..8113bfd0dd18 100644
--- a/packages/svelte/src/internal/client/index.js
+++ b/packages/svelte/src/internal/client/index.js
@@ -100,6 +100,7 @@ export {
 export { derived, derived_safe_equal } from './reactivity/deriveds.js';
 export {
 	effect_tracking,
+	effect_active,
 	effect_root,
 	legacy_pre_effect,
 	legacy_pre_effect_reset,
diff --git a/packages/svelte/src/internal/client/reactivity/effects.js b/packages/svelte/src/internal/client/reactivity/effects.js
index bf890627f7e0..7d393ae1b587 100644
--- a/packages/svelte/src/internal/client/reactivity/effects.js
+++ b/packages/svelte/src/internal/client/reactivity/effects.js
@@ -173,6 +173,19 @@ export function effect_tracking() {
 	return !skip_reaction;
 }
 
+/**
+ * Internal representation of `$effect.active()`
+ * @returns {boolean}
+ */
+export function effect_active() {
+	if (is_destroying_effect) {
+		return false;
+	}
+	return (
+		active_effect !== null || (active_reaction !== null && (active_reaction.f & UNOWNED) === 0)
+	);
+}
+
 /**
  * @param {() => void} fn
  */
diff --git a/packages/svelte/src/utils.js b/packages/svelte/src/utils.js
index e42721b4f4b4..b5e0c0496e24 100644
--- a/packages/svelte/src/utils.js
+++ b/packages/svelte/src/utils.js
@@ -428,6 +428,7 @@ const RUNES = /** @type {const} */ ([
 	'$effect',
 	'$effect.pre',
 	'$effect.tracking',
+	'$effect.active',
 	'$effect.root',
 	'$inspect',
 	'$inspect().with',
diff --git a/packages/svelte/tests/compiler-errors/samples/effect-active-rune/_config.js b/packages/svelte/tests/compiler-errors/samples/effect-active-rune/_config.js
deleted file mode 100644
index e12e4046f36d..000000000000
--- a/packages/svelte/tests/compiler-errors/samples/effect-active-rune/_config.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { test } from '../../test';
-
-export default test({
-	error: {
-		code: 'rune_renamed',
-		message: '`$effect.active` is now `$effect.tracking`'
-	}
-});
diff --git a/packages/svelte/tests/compiler-errors/samples/effect-active-rune/main.svelte.js b/packages/svelte/tests/compiler-errors/samples/effect-active-rune/main.svelte.js
deleted file mode 100644
index c33c104aac31..000000000000
--- a/packages/svelte/tests/compiler-errors/samples/effect-active-rune/main.svelte.js
+++ /dev/null
@@ -1 +0,0 @@
-$effect.active();
diff --git a/packages/svelte/tests/runtime-runes/samples/effect-active/_config.js b/packages/svelte/tests/runtime-runes/samples/effect-active/_config.js
new file mode 100644
index 000000000000..8629829c6451
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/effect-active/_config.js
@@ -0,0 +1,19 @@
+import { test } from '../../test';
+
+export default test({
+	ssrHtml: `
+		<p>false</p>
+		<p>false</p>
+		<p>false</p>
+		<p>false</p>
+		<p>false</p>
+	`,
+
+	html: `
+		<p>false</p>
+		<p>true</p>
+		<p>true</p>
+		<p>true</p>
+		<p>true</p>
+	`
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/effect-active/main.svelte b/packages/svelte/tests/runtime-runes/samples/effect-active/main.svelte
new file mode 100644
index 000000000000..bf488752db67
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/effect-active/main.svelte
@@ -0,0 +1,19 @@
+<script module>
+	const mod = $effect.active()
+</script>
+
+<script>
+	import { untrack } from 'svelte';
+
+	const foo = $effect.active();
+	let bar = $state(false);
+	$effect.pre(() => {
+		bar = $effect.active();
+	});
+</script>
+
+<p>{mod}</p>
+<p>{foo}</p>
+<p>{bar}</p>
+<p>{(bar, $effect.active())}</p>
+<p>{untrack(() => (bar, $effect.active()))}</p>