diff --git a/.changeset/chilly-pans-raise.md b/.changeset/chilly-pans-raise.md
new file mode 100644
index 000000000000..02a162dfb8e0
--- /dev/null
+++ b/.changeset/chilly-pans-raise.md
@@ -0,0 +1,5 @@
+---
+"svelte": patch
+---
+
+fix: allow runelike writable as prop
diff --git a/packages/svelte/src/compiler/phases/2-analyze/index.js b/packages/svelte/src/compiler/phases/2-analyze/index.js
index 798fdd065352..acd12efcc805 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/index.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/index.js
@@ -285,7 +285,9 @@ export function analyze_component(root, source, options) {
!Runes.includes(/** @type {any} */ (name)) ||
(declaration !== null &&
// const state = $state(0) is valid
- get_rune(declaration.initial, instance.scope) === null &&
+ (get_rune(declaration.initial, instance.scope) === null ||
+ // rune-line names received as props are valid too (but we have to protect against $props as store)
+ (store_name !== 'props' && get_rune(declaration.initial, instance.scope) === '$props')) &&
// allow `import { derived } from 'svelte/store'` in the same file as `const x = $derived(..)` because one is not a subscription to the other
!(
name === '$derived' &&
diff --git a/packages/svelte/tests/runtime-runes/samples/store-from-props-runelike/_config.js b/packages/svelte/tests/runtime-runes/samples/store-from-props-runelike/_config.js
new file mode 100644
index 000000000000..18880650d7c4
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/store-from-props-runelike/_config.js
@@ -0,0 +1,18 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ test({ assert, target, ok }) {
+ const button = target.querySelector('button');
+
+ flushSync(() => {
+ button?.click();
+ });
+ assert.htmlEqual(
+ target.innerHTML,
+ `
+
+ `
+ );
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/store-from-props-runelike/child.svelte b/packages/svelte/tests/runtime-runes/samples/store-from-props-runelike/child.svelte
new file mode 100644
index 000000000000..a89955d5e426
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/store-from-props-runelike/child.svelte
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/packages/svelte/tests/runtime-runes/samples/store-from-props-runelike/main.svelte b/packages/svelte/tests/runtime-runes/samples/store-from-props-runelike/main.svelte
new file mode 100644
index 000000000000..e1d19fc0c756
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/store-from-props-runelike/main.svelte
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/packages/svelte/tests/validator/samples/store-rune-conflic-from-props/input.svelte b/packages/svelte/tests/validator/samples/store-rune-conflic-from-props/input.svelte
new file mode 100644
index 000000000000..be769e18af92
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/store-rune-conflic-from-props/input.svelte
@@ -0,0 +1,6 @@
+
+
+{$state}
\ No newline at end of file
diff --git a/packages/svelte/tests/validator/samples/store-rune-conflic-from-props/warnings.json b/packages/svelte/tests/validator/samples/store-rune-conflic-from-props/warnings.json
new file mode 100644
index 000000000000..2db49bf418ad
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/store-rune-conflic-from-props/warnings.json
@@ -0,0 +1,14 @@
+[
+ {
+ "code": "store_rune_conflict",
+ "message": "It looks like you're using the `$state` rune, but there is a local binding called `state`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `state` to avoid the ambiguity",
+ "start": {
+ "line": 3,
+ "column": 9
+ },
+ "end": {
+ "line": 3,
+ "column": 15
+ }
+ }
+]