diff --git a/.changeset/famous-parents-turn.md b/.changeset/famous-parents-turn.md
new file mode 100644
index 0000000000..b41b14bc20
--- /dev/null
+++ b/.changeset/famous-parents-turn.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+feat: allow snippets to be exported from module scripts
diff --git a/packages/svelte/src/compiler/phases/1-parse/acorn.js b/packages/svelte/src/compiler/phases/1-parse/acorn.js
index 52c4b69895..090686f155 100644
--- a/packages/svelte/src/compiler/phases/1-parse/acorn.js
+++ b/packages/svelte/src/compiler/phases/1-parse/acorn.js
@@ -10,17 +10,43 @@ const ParserWithTS = acorn.Parser.extend(tsPlugin({ allowSatisfies: true }));
/**
* @param {string} source
* @param {boolean} typescript
+ * @param {boolean} is_script
*/
-export function parse(source, typescript) {
+export function parse(source, typescript, is_script) {
const parser = typescript ? ParserWithTS : acorn.Parser;
const { onComment, add_comments } = get_comment_handlers(source);
-
- const ast = parser.parse(source, {
- onComment,
- sourceType: 'module',
- ecmaVersion: 13,
- locations: true
- });
+ // @ts-ignore
+ const parse_statement = parser.prototype.parseStatement;
+
+ // If we're dealing with a
+
+{#snippet foo(a, b)}
+ Hello world {a + b}
+{/snippet}
diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-hoisted-module/_config.js b/packages/svelte/tests/runtime-runes/samples/snippet-hoisted-module/_config.js
new file mode 100644
index 0000000000..be8d22b4e8
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/snippet-hoisted-module/_config.js
@@ -0,0 +1,8 @@
+import { test } from '../../test';
+
+export default test({
+ compileOptions: {
+ dev: true // Render in dev mode to check that the validation error is not thrown
+ },
+ html: `Hello world 3`
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/snippet-hoisted-module/main.svelte b/packages/svelte/tests/runtime-runes/samples/snippet-hoisted-module/main.svelte
new file mode 100644
index 0000000000..80e9df514b
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/snippet-hoisted-module/main.svelte
@@ -0,0 +1,5 @@
+
+
+{@render foo(1, 2)}
diff --git a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js
index 58ccf7ed7f..bcddb6f658 100644
--- a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js
+++ b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js
@@ -2,17 +2,17 @@ import "svelte/internal/disclose-version";
import * as $ from "svelte/internal/client";
import TextInput from './Child.svelte';
-var root = $.template(` `, 1);
+const snippet = ($$anchor) => {
+ $.next();
-export default function Bind_component_snippet($$anchor) {
- const snippet = ($$anchor) => {
- $.next();
+ var text = $.text("Something");
- var text = $.text("Something");
+ $.append($$anchor, text);
+};
- $.append($$anchor, text);
- };
+var root = $.template(` `, 1);
+export default function Bind_component_snippet($$anchor) {
let value = $.state('');
const _snippet = snippet;
var fragment = root();
diff --git a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js
index b645d05570..d223a31502 100644
--- a/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js
+++ b/packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/server/index.svelte.js
@@ -1,14 +1,13 @@
import * as $ from "svelte/internal/server";
import TextInput from './Child.svelte';
+function snippet($$payload) {
+ $$payload.out += `Something`;
+}
+
export default function Bind_component_snippet($$payload) {
let value = '';
const _snippet = snippet;
-
- function snippet($$payload) {
- $$payload.out += `Something`;
- }
-
let $$settled = true;
let $$inner_payload;