diff --git a/packages/astro/src/content/vite-plugin-content-assets.ts b/packages/astro/src/content/vite-plugin-content-assets.ts
index bbd9749a80..38e1bdc44d 100644
--- a/packages/astro/src/content/vite-plugin-content-assets.ts
+++ b/packages/astro/src/content/vite-plugin-content-assets.ts
@@ -9,8 +9,8 @@ import type { StaticBuildOptions } from '../core/build/types';
 import type { ModuleLoader } from '../core/module-loader/loader.js';
 import { createViteLoader } from '../core/module-loader/vite.js';
 import { joinPaths, prependForwardSlash } from '../core/path.js';
-import { getStylesForURL } from '../core/render/dev/css.js';
-import { getScriptsForURL } from '../core/render/dev/scripts.js';
+import { getStylesForURL } from '../vite-plugin-astro-server/css.js';
+import { getScriptsForURL } from '../vite-plugin-astro-server/scripts.js';
 import {
 	CONTENT_RENDER_FLAG,
 	LINKS_PLACEHOLDER,
diff --git a/packages/astro/src/core/build/plugins/plugin-css.ts b/packages/astro/src/core/build/plugins/plugin-css.ts
index f254b0fe08..87b52cbdb2 100644
--- a/packages/astro/src/core/build/plugins/plugin-css.ts
+++ b/packages/astro/src/core/build/plugins/plugin-css.ts
@@ -2,7 +2,7 @@ import * as crypto from 'node:crypto';
 import * as npath from 'node:path';
 import type { GetModuleInfo } from 'rollup';
 import { type ResolvedConfig, type Plugin as VitePlugin } from 'vite';
-import { isBuildableCSSRequest } from '../../render/dev/util.js';
+import { isBuildableCSSRequest } from '../../../vite-plugin-astro-server/util.js';
 import type { BuildInternals } from '../internal';
 import type { AstroBuildPlugin } from '../plugin';
 import type { PageBuildData, StaticBuildOptions, StylesheetAsset } from '../types';
diff --git a/packages/astro/src/core/endpoint/dev/index.ts b/packages/astro/src/core/endpoint/dev/index.ts
index afbc282915..79e5c1fd52 100644
--- a/packages/astro/src/core/endpoint/dev/index.ts
+++ b/packages/astro/src/core/endpoint/dev/index.ts
@@ -1,6 +1,5 @@
 import type { EndpointHandler } from '../../../@types/astro';
-import type { SSROptions } from '../../render/dev';
-import { createRenderContext } from '../../render/index.js';
+import { createRenderContext, type SSROptions } from '../../render/index.js';
 import { callEndpoint } from '../index.js';
 
 export async function call(options: SSROptions) {
diff --git a/packages/astro/src/core/render/dev/index.ts b/packages/astro/src/core/render/dev/index.ts
deleted file mode 100644
index 40bda55567..0000000000
--- a/packages/astro/src/core/render/dev/index.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import type { AstroMiddlewareInstance, ComponentInstance, RouteData } from '../../../@types/astro';
-import { enhanceViteSSRError } from '../../errors/dev/index.js';
-import { AggregateError, CSSError, MarkdownError } from '../../errors/index.js';
-import { viteID } from '../../util.js';
-import { loadRenderers } from '../index.js';
-import type { DevelopmentEnvironment } from './environment';
-export { createDevelopmentEnvironment } from './environment.js';
-export type { DevelopmentEnvironment };
-
-export interface SSROptions {
-	/** The environment instance */
-	env: DevelopmentEnvironment;
-	/** location of file on disk */
-	filePath: URL;
-	/** the web request (needed for dynamic routes) */
-	pathname: string;
-	/** The runtime component instance */
-	preload: ComponentInstance;
-	/** Request */
-	request: Request;
-	/** optional, in case we need to render something outside of a dev server */
-	route?: RouteData;
-	/**
-	 * Optional middlewares
-	 */
-	middleware?: AstroMiddlewareInstance<unknown>;
-}
-
-export async function preload({
-	env,
-	filePath,
-}: {
-	env: DevelopmentEnvironment;
-	filePath: URL;
-}): Promise<ComponentInstance> {
-	// Important: This needs to happen first, in case a renderer provides polyfills.
-	const renderers = await loadRenderers(env.settings, env.loader);
-	// Override the environment's renderers. This ensures that if renderers change (HMR)
-	// The new instances are passed through.
-	env.renderers = renderers;
-
-	try {
-		// Load the module from the Vite SSR Runtime.
-		const mod = (await env.loader.import(viteID(filePath))) as ComponentInstance;
-
-		return mod;
-	} catch (error) {
-		// If the error came from Markdown or CSS, we already handled it and there's no need to enhance it
-		if (MarkdownError.is(error) || CSSError.is(error) || AggregateError.is(error)) {
-			throw error;
-		}
-
-		throw enhanceViteSSRError({ error, filePath, loader: env.loader });
-	}
-}
diff --git a/packages/astro/src/core/render/environment.ts b/packages/astro/src/core/render/environment.ts
index f38773cfc2..4a8c2c1f74 100644
--- a/packages/astro/src/core/render/environment.ts
+++ b/packages/astro/src/core/render/environment.ts
@@ -1,12 +1,13 @@
 import type { MarkdownRenderingOptions } from '@astrojs/markdown-remark';
-import type { RuntimeMode, SSRLoadedRenderer } from '../../@types/astro';
+import type { RuntimeMode, SSRLoadedRenderer, AstroSettings } from '../../@types/astro';
 import type { LogOptions } from '../logger/core.js';
 import type { RouteCache } from './route-cache.js';
+import type { ModuleLoader } from '../module-loader';
 
 /**
  * An environment represents the static parts of rendering that do not change
  * between requests. These are mostly known when the server first starts up and do not change.
- * Thus they can be created once and passed through to renderPage on each request.
+ * Thus, they can be created once and passed through to renderPage on each request.
  */
 export interface Environment {
 	/**
@@ -42,3 +43,8 @@ export type CreateEnvironmentArgs = Environment;
 export function createEnvironment(options: CreateEnvironmentArgs): Environment {
 	return options;
 }
+
+export type DevelopmentEnvironment = Environment & {
+	loader: ModuleLoader;
+	settings: AstroSettings;
+};
diff --git a/packages/astro/src/core/render/index.ts b/packages/astro/src/core/render/index.ts
index cd0aedbb2b..ac8fb75933 100644
--- a/packages/astro/src/core/render/index.ts
+++ b/packages/astro/src/core/render/index.ts
@@ -1,3 +1,6 @@
+import type { DevelopmentEnvironment } from './environment';
+import type { AstroMiddlewareInstance, ComponentInstance, RouteData } from '../../@types/astro';
+
 export { createRenderContext } from './context.js';
 export type { RenderContext } from './context.js';
 export { tryRenderRoute } from './core.js';
@@ -5,3 +8,23 @@ export type { Environment } from './environment';
 export { createEnvironment } from './environment.js';
 export { getParamsAndProps } from './params-and-props.js';
 export { loadRenderer, loadRenderers } from './renderer.js';
+export type { DevelopmentEnvironment };
+
+export interface SSROptions {
+	/** The environment instance */
+	env: DevelopmentEnvironment;
+	/** location of file on disk */
+	filePath: URL;
+	/** the web request (needed for dynamic routes) */
+	pathname: string;
+	/** The runtime component instance */
+	preload: ComponentInstance;
+	/** Request */
+	request: Request;
+	/** optional, in case we need to render something outside of a dev server */
+	route?: RouteData;
+	/**
+	 * Optional middlewares
+	 */
+	middleware?: AstroMiddlewareInstance<unknown>;
+}
diff --git a/packages/astro/src/prerender/routing.ts b/packages/astro/src/prerender/routing.ts
index 0282a12b4e..beac0b8411 100644
--- a/packages/astro/src/prerender/routing.ts
+++ b/packages/astro/src/prerender/routing.ts
@@ -1,7 +1,8 @@
 import type { AstroSettings, ComponentInstance, RouteData } from '../@types/astro';
 import { RedirectComponentInstance, routeIsRedirect } from '../core/redirects/index.js';
-import { preload, type DevelopmentEnvironment } from '../core/render/dev/index.js';
+import { preload } from '../vite-plugin-astro-server/index.js';
 import { getPrerenderStatus } from './metadata.js';
+import type { DevelopmentEnvironment } from '../core/render';
 
 type GetSortedPreloadedMatchesParams = {
 	env: DevelopmentEnvironment;
diff --git a/packages/astro/src/core/render/dev/css.ts b/packages/astro/src/vite-plugin-astro-server/css.ts
similarity index 89%
rename from packages/astro/src/core/render/dev/css.ts
rename to packages/astro/src/vite-plugin-astro-server/css.ts
index 1d80a85268..41f803acd4 100644
--- a/packages/astro/src/core/render/dev/css.ts
+++ b/packages/astro/src/vite-plugin-astro-server/css.ts
@@ -1,7 +1,6 @@
-import type { ModuleLoader } from '../../module-loader/index';
-
-import type { RuntimeMode } from '../../../@types/astro.js';
-import { viteID } from '../../util.js';
+import type { ModuleLoader } from '../core/module-loader';
+import type { RuntimeMode } from '../@types/astro.js';
+import { viteID } from '../core/util.js';
 import { isBuildableCSSRequest } from './util.js';
 import { crawlGraph } from './vite.js';
 
diff --git a/packages/astro/src/core/render/dev/environment.ts b/packages/astro/src/vite-plugin-astro-server/environment.ts
similarity index 64%
rename from packages/astro/src/core/render/dev/environment.ts
rename to packages/astro/src/vite-plugin-astro-server/environment.ts
index 6d797b5218..0c98878ff6 100644
--- a/packages/astro/src/core/render/dev/environment.ts
+++ b/packages/astro/src/vite-plugin-astro-server/environment.ts
@@ -1,16 +1,11 @@
-import type { AstroSettings, RuntimeMode, SSRManifest } from '../../../@types/astro';
-import { isServerLikeOutput } from '../../../prerender/utils.js';
-import type { LogOptions } from '../../logger/core.js';
-import type { ModuleLoader } from '../../module-loader/index';
-import type { Environment } from '../index';
-import { createEnvironment } from '../index.js';
-import { RouteCache } from '../route-cache.js';
 import { createResolve } from './resolve.js';
-
-export type DevelopmentEnvironment = Environment & {
-	loader: ModuleLoader;
-	settings: AstroSettings;
-};
+import type { ModuleLoader } from '../core/module-loader';
+import type { AstroSettings, RuntimeMode, SSRManifest } from '../@types/astro.js';
+import type { LogOptions } from '../core/logger/core.js';
+import { RouteCache } from '../core/render/route-cache.js';
+import { isServerLikeOutput } from '../prerender/utils.js';
+import type { DevelopmentEnvironment } from '../core/render';
+import { createEnvironment } from '../core/render/index.js';
 
 export function createDevelopmentEnvironment(
 	manifest: SSRManifest,
diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts
index 14172e8ae8..95512c4084 100644
--- a/packages/astro/src/vite-plugin-astro-server/index.ts
+++ b/packages/astro/src/vite-plugin-astro-server/index.ts
@@ -1,3 +1,38 @@
+import type { ComponentInstance } from '../@types/astro.js';
+import { loadRenderers } from '../core/render/index.js';
+import { viteID } from '../core/util.js';
+import { AggregateError, CSSError, MarkdownError } from '../core/errors/index.js';
+import { enhanceViteSSRError } from '../core/errors/dev/index.js';
+import type { DevelopmentEnvironment } from '../core/render/environment';
+
+export async function preload({
+	env,
+	filePath,
+}: {
+	env: DevelopmentEnvironment;
+	filePath: URL;
+}): Promise<ComponentInstance> {
+	// Important: This needs to happen first, in case a renderer provides polyfills.
+	const renderers = await loadRenderers(env.settings, env.loader);
+	// Override the environment's renderers. This ensures that if renderers change (HMR)
+	// The new instances are passed through.
+	env.renderers = renderers;
+
+	try {
+		// Load the module from the Vite SSR Runtime.
+		const mod = (await env.loader.import(viteID(filePath))) as ComponentInstance;
+
+		return mod;
+	} catch (error) {
+		// If the error came from Markdown or CSS, we already handled it and there's no need to enhance it
+		if (MarkdownError.is(error) || CSSError.is(error) || AggregateError.is(error)) {
+			throw error;
+		}
+
+		throw enhanceViteSSRError({ error, filePath, loader: env.loader });
+	}
+}
+
 export { createController, runWithErrorHandling } from './controller.js';
 export { default as vitePluginAstroServer } from './plugin.js';
 export { handleRequest } from './request.js';
diff --git a/packages/astro/src/core/render/dev/metadata.ts b/packages/astro/src/vite-plugin-astro-server/metadata.ts
similarity index 78%
rename from packages/astro/src/core/render/dev/metadata.ts
rename to packages/astro/src/vite-plugin-astro-server/metadata.ts
index bd0205bd90..9ac6e73fe5 100644
--- a/packages/astro/src/core/render/dev/metadata.ts
+++ b/packages/astro/src/vite-plugin-astro-server/metadata.ts
@@ -1,10 +1,8 @@
-import type { SSRComponentMetadata, SSRResult } from '../../../@types/astro';
-
-import type { ModuleInfo, ModuleLoader } from '../../module-loader/index';
-
-import { getAstroMetadata } from '../../../vite-plugin-astro/index.js';
-import { viteID } from '../../util.js';
 import { crawlGraph } from './vite.js';
+import type { ModuleLoader, ModuleInfo } from '../core/module-loader';
+import { viteID } from '../core/util.js';
+import { getAstroMetadata } from '../vite-plugin-astro/index.js';
+import type { SSRComponentMetadata, SSRResult } from '../@types/astro';
 
 export async function getComponentMetadata(
 	filePath: URL,
diff --git a/packages/astro/src/vite-plugin-astro-server/plugin.ts b/packages/astro/src/vite-plugin-astro-server/plugin.ts
index 69e2186a53..713b88e4df 100644
--- a/packages/astro/src/vite-plugin-astro-server/plugin.ts
+++ b/packages/astro/src/vite-plugin-astro-server/plugin.ts
@@ -4,7 +4,7 @@ import type { AstroSettings, ManifestData, SSRManifest } from '../@types/astro';
 import { patchOverlay } from '../core/errors/overlay.js';
 import type { LogOptions } from '../core/logger/core.js';
 import { createViteLoader } from '../core/module-loader/index.js';
-import { createDevelopmentEnvironment } from '../core/render/dev/index.js';
+import { createDevelopmentEnvironment } from './environment.js';
 import { createRouteManifest } from '../core/routing/index.js';
 import { baseMiddleware } from './base.js';
 import { createController } from './controller.js';
diff --git a/packages/astro/src/vite-plugin-astro-server/request.ts b/packages/astro/src/vite-plugin-astro-server/request.ts
index b0696adc58..e334f42fd8 100644
--- a/packages/astro/src/vite-plugin-astro-server/request.ts
+++ b/packages/astro/src/vite-plugin-astro-server/request.ts
@@ -1,7 +1,7 @@
 import type http from 'node:http';
 import type { ManifestData, SSRManifest } from '../@types/astro';
-import type { DevelopmentEnvironment } from '../core/render/dev/index';
 import type { DevServerController } from './controller';
+import type { DevelopmentEnvironment } from '../core/render/index';
 
 import { collectErrorMetadata } from '../core/errors/dev/index.js';
 import { createSafeError } from '../core/errors/index.js';
diff --git a/packages/astro/src/core/render/dev/resolve.ts b/packages/astro/src/vite-plugin-astro-server/resolve.ts
similarity index 77%
rename from packages/astro/src/core/render/dev/resolve.ts
rename to packages/astro/src/vite-plugin-astro-server/resolve.ts
index 1c8204591b..f67d83576d 100644
--- a/packages/astro/src/core/render/dev/resolve.ts
+++ b/packages/astro/src/vite-plugin-astro-server/resolve.ts
@@ -1,5 +1,5 @@
-import type { ModuleLoader } from '../../module-loader/index';
-import { resolveIdToUrl } from '../../util.js';
+import type { ModuleLoader } from '../core/module-loader';
+import { resolveIdToUrl } from '../core/util.js';
 
 export function createResolve(loader: ModuleLoader, root: URL) {
 	// Resolves specifiers in the inline hydrated scripts, such as:
diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts
index 61c85d6922..6160eab715 100644
--- a/packages/astro/src/vite-plugin-astro-server/route.ts
+++ b/packages/astro/src/vite-plugin-astro-server/route.ts
@@ -12,12 +12,17 @@ import { attachToResponse } from '../core/cookies/index.js';
 import { AstroErrorData, isAstroError } from '../core/errors/index.js';
 import { warn } from '../core/logger/core.js';
 import { loadMiddleware } from '../core/middleware/loadMiddleware.js';
-import { getStylesForURL } from '../core/render/dev/css.js';
-import type { DevelopmentEnvironment, SSROptions } from '../core/render/dev/index';
-import { preload } from '../core/render/dev/index.js';
-import { getComponentMetadata } from '../core/render/dev/metadata.js';
-import { getScriptsForURL } from '../core/render/dev/scripts.js';
-import { createRenderContext, getParamsAndProps, tryRenderRoute } from '../core/render/index.js';
+import { getStylesForURL } from './css.js';
+import { preload } from './index.js';
+import { getComponentMetadata } from './metadata.js';
+import { getScriptsForURL } from './scripts.js';
+import {
+	createRenderContext,
+	type DevelopmentEnvironment,
+	type SSROptions,
+	getParamsAndProps,
+	tryRenderRoute,
+} from '../core/render/index.js';
 import { createRequest } from '../core/request.js';
 import { matchAllRoutes } from '../core/routing/index.js';
 import { isPage, resolveIdToUrl, viteID } from '../core/util.js';
diff --git a/packages/astro/src/core/render/dev/scripts.ts b/packages/astro/src/vite-plugin-astro-server/scripts.ts
similarity index 73%
rename from packages/astro/src/core/render/dev/scripts.ts
rename to packages/astro/src/vite-plugin-astro-server/scripts.ts
index 186332ab2a..9e6c587d0c 100644
--- a/packages/astro/src/core/render/dev/scripts.ts
+++ b/packages/astro/src/vite-plugin-astro-server/scripts.ts
@@ -1,10 +1,9 @@
-import type { SSRElement } from '../../../@types/astro';
-import type { PluginMetadata as AstroPluginMetadata } from '../../../vite-plugin-astro/types';
-import type { ModuleInfo, ModuleLoader } from '../../module-loader/index';
-
-import { rootRelativePath, viteID } from '../../util.js';
-import { createModuleScriptElementWithSrc } from '../ssr-element.js';
+import type { PluginMetadata as AstroPluginMetadata } from '../vite-plugin-astro/types';
 import { crawlGraph } from './vite.js';
+import type { ModuleLoader, ModuleInfo } from '../core/module-loader';
+import type { SSRElement } from '../@types/astro';
+import { rootRelativePath, viteID } from '../core/util.js';
+import { createModuleScriptElementWithSrc } from '../core/render/ssr-element.js';
 
 export async function getScriptsForURL(
 	filePath: URL,
diff --git a/packages/astro/src/core/render/dev/util.ts b/packages/astro/src/vite-plugin-astro-server/util.ts
similarity index 100%
rename from packages/astro/src/core/render/dev/util.ts
rename to packages/astro/src/vite-plugin-astro-server/util.ts
diff --git a/packages/astro/src/core/render/dev/vite.ts b/packages/astro/src/vite-plugin-astro-server/vite.ts
similarity index 95%
rename from packages/astro/src/core/render/dev/vite.ts
rename to packages/astro/src/vite-plugin-astro-server/vite.ts
index 252d50fa2f..ac86599824 100644
--- a/packages/astro/src/core/render/dev/vite.ts
+++ b/packages/astro/src/vite-plugin-astro-server/vite.ts
@@ -1,9 +1,8 @@
-import type { ModuleLoader, ModuleNode } from '../../module-loader/index';
-
+import type { ModuleLoader, ModuleNode } from '../core/module-loader/index';
 import npath from 'node:path';
-import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js';
-import { unwrapId } from '../../util.js';
 import { isCSSRequest } from './util.js';
+import { unwrapId } from '../core/util.js';
+import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../core/constants.js';
 
 /**
  * List of file extensions signalling we can (and should) SSR ahead-of-time
diff --git a/packages/astro/test/units/dev/styles.test.js b/packages/astro/test/units/dev/styles.test.js
index ba27a1c8b0..76b38dd437 100644
--- a/packages/astro/test/units/dev/styles.test.js
+++ b/packages/astro/test/units/dev/styles.test.js
@@ -1,6 +1,6 @@
 import { expect } from 'chai';
 
-import { getStylesForURL } from '../../../dist/core/render/dev/css.js';
+import { getStylesForURL } from '../../../dist/vite-plugin-astro-server/css.js';
 import { viteID } from '../../../dist/core/util.js';
 
 const root = new URL('../../fixtures/alias/', import.meta.url);
diff --git a/packages/astro/test/units/routing/route-matching.test.js b/packages/astro/test/units/routing/route-matching.test.js
index 78714202a7..50b8d58c9c 100644
--- a/packages/astro/test/units/routing/route-matching.test.js
+++ b/packages/astro/test/units/routing/route-matching.test.js
@@ -3,12 +3,12 @@ import { createFs, createRequestAndResponse, defaultLogging } from '../test-util
 import { createRouteManifest, matchAllRoutes } from '../../../dist/core/routing/index.js';
 import { fileURLToPath } from 'node:url';
 import { createViteLoader } from '../../../dist/core/module-loader/vite.js';
-import { createDevelopmentEnvironment } from '../../../dist/core/render/dev/environment.js';
 import { expect } from 'chai';
 import { createContainer } from '../../../dist/core/dev/container.js';
 import * as cheerio from 'cheerio';
 import testAdapter from '../../test-adapter.js';
 import { getSortedPreloadedMatches } from '../../../dist/prerender/routing.js';
+import { createDevelopmentEnvironment } from '../../../dist/vite-plugin-astro-server/environment.js';
 import { createDevelopmentManifest } from '../../../dist/vite-plugin-astro-server/plugin.js';
 
 const root = new URL('../../fixtures/alias/', import.meta.url);