diff --git a/examples/ssr/src/pages/products/[id].astro b/examples/ssr/src/pages/products/[id].astro
index 37fe7e0b46..317cea6352 100644
--- a/examples/ssr/src/pages/products/[id].astro
+++ b/examples/ssr/src/pages/products/[id].astro
@@ -5,7 +5,7 @@ import AddToCart from '../../components/AddToCart.svelte';
 import { getProduct } from '../../api';
 import '../../styles/common.css';
 
-const id = Number(Astro.request.params.id);
+const id = Number(Astro.params.id);
 const product = await getProduct(id);
 ---
 
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index 988bec9b0e..c29f3f60f8 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -4,7 +4,6 @@ import type * as vite from 'vite';
 import type { z } from 'zod';
 import type { AstroConfigSchema } from '../core/config';
 import type { AstroComponentFactory, Metadata } from '../runtime/server';
-import type { AstroRequest } from '../core/render/request';
 export type { SSRManifest } from '../core/app/types';
 
 export interface AstroBuiltinProps {
@@ -50,10 +49,14 @@ export interface BuildConfig {
  * Docs: https://docs.astro.build/reference/api-reference/#astro-global
  */
 export interface AstroGlobal extends AstroGlobalPartial {
+	/** get the current canonical URL */
+	canonicalURL: URL;
+	/** get page params (dynamic pages only) */
+	params: Params;
 	/** set props for this astro component (along with default values) */
 	props: Record<string, number | string | any>;
 	/** get information about this page */
-	request: AstroRequest;
+	request: Request;
 	/** see if slots are used */
 	slots: Record<string, true | undefined> & { has(slotName: string): boolean; render(slotName: string): Promise<string> };
 }
@@ -628,7 +631,7 @@ export interface EndpointOutput<Output extends Body = Body> {
 }
 
 export interface EndpointHandler {
-	[method: string]: (params: any, request: AstroRequest) => EndpointOutput | Response;
+	[method: string]: (params: any, request: Request) => EndpointOutput | Response;
 }
 
 export interface AstroRenderer {
diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts
index 119274e76d..ad122596c2 100644
--- a/packages/astro/src/core/build/generate.ts
+++ b/packages/astro/src/core/build/generate.ts
@@ -17,6 +17,7 @@ import { getOutFile, getOutRoot, getOutFolder } from './common.js';
 import { getPageDataByComponent, eachPageData } from './internal.js';
 import { bgMagenta, black, cyan, dim, magenta } from 'kleur/colors';
 import { getTimeStat } from './util.js';
+import { createRequest } from '../request.js';
 
 // Render is usually compute, which Node.js can't parallelize well.
 // In real world testing, dropping from 10->1 showed a notiable perf
@@ -176,6 +177,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
 	}
 
 	try {
+		const url = new URL(origin + pathname);
 		const options: RenderOptions = {
 			legacyBuild: false,
 			links,
@@ -203,8 +205,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
 				const fullyRelativePath = relPath[0] === '.' ? relPath : './' + relPath;
 				return fullyRelativePath;
 			},
-			method: 'GET',
-			headers: new Headers(),
+			request: createRequest(url, new Headers()),
 			route: pageData.route,
 			routeCache,
 			site: astroConfig.buildOptions.site,
diff --git a/packages/astro/src/core/endpoint/index.ts b/packages/astro/src/core/endpoint/index.ts
index 745811354f..fb525066c9 100644
--- a/packages/astro/src/core/endpoint/index.ts
+++ b/packages/astro/src/core/endpoint/index.ts
@@ -2,9 +2,9 @@ import type { EndpointHandler } from '../../@types/astro';
 import type { RenderOptions } from '../render/core';
 import { renderEndpoint } from '../../runtime/server/index.js';
 import { getParamsAndProps, GetParamsAndPropsError } from '../render/core.js';
-import { createRequest } from '../render/request.js';
 
-export type EndpointOptions = Pick<RenderOptions, 'logging' | 'headers' | 'method' | 'origin' | 'route' | 'routeCache' | 'pathname' | 'route' | 'site' | 'ssr'>;
+export type EndpointOptions = Pick<RenderOptions, 'logging' | 'origin' | 
+	'request' | 'route' | 'routeCache' | 'pathname' | 'route' | 'site' | 'ssr'>;
 
 type EndpointCallResult =
 	| {
@@ -23,9 +23,8 @@ export async function call(mod: EndpointHandler, opts: EndpointOptions): Promise
 		throw new Error(`[getStaticPath] route pattern matched, but no matching static path found. (${opts.pathname})`);
 	}
 	const [params] = paramsAndPropsResp;
-	const request = createRequest(opts.method, opts.pathname, opts.headers, opts.origin, opts.site, opts.ssr);
 
-	const response = await renderEndpoint(mod, request, params);
+	const response = await renderEndpoint(mod, opts.request, params);
 
 	if (response instanceof Response) {
 		return {
diff --git a/packages/astro/src/core/render/core.ts b/packages/astro/src/core/render/core.ts
index a1ea94f65d..3cb109b768 100644
--- a/packages/astro/src/core/render/core.ts
+++ b/packages/astro/src/core/render/core.ts
@@ -1,6 +1,5 @@
 import type { ComponentInstance, EndpointHandler, MarkdownRenderOptions, Params, Props, SSRLoadedRenderer, RouteData, SSRElement } from '../../@types/astro';
 import type { LogOptions } from '../logger.js';
-import type { AstroRequest } from './request';
 
 import { renderHead, renderPage } from '../../runtime/server/index.js';
 import { getParams } from '../routing/index.js';
@@ -71,12 +70,11 @@ export interface RenderOptions {
 	routeCache: RouteCache;
 	site?: string;
 	ssr: boolean;
-	method: string;
-	headers: Headers;
+	request: Request;
 }
 
 export async function render(opts: RenderOptions): Promise<{ type: 'html'; html: string } | { type: 'response'; response: Response }> {
-	const { headers, legacyBuild, links, logging, origin, markdownRender, method, mod, pathname, scripts, renderers, resolve, route, routeCache, site, ssr } = opts;
+	const { legacyBuild, links, logging, origin, markdownRender, mod, pathname, scripts, renderers, request, resolve, route, routeCache, site, ssr } = opts;
 
 	const paramsAndPropsRes = await getParamsAndProps({
 		logging,
@@ -107,11 +105,10 @@ export async function render(opts: RenderOptions): Promise<{ type: 'html'; html:
 		pathname,
 		resolve,
 		renderers,
+		request,
 		site,
 		scripts,
 		ssr,
-		method,
-		headers,
 	});
 
 	let page = await renderPage(result, Component, pageProps, null);
diff --git a/packages/astro/src/core/render/dev/index.ts b/packages/astro/src/core/render/dev/index.ts
index d16cb8923a..97cb402672 100644
--- a/packages/astro/src/core/render/dev/index.ts
+++ b/packages/astro/src/core/render/dev/index.ts
@@ -29,10 +29,8 @@ export interface SSROptions {
 	routeCache: RouteCache;
 	/** Vite instance */
 	viteServer: vite.ViteDevServer;
-	/** Method */
-	method: string;
-	/** Headers */
-	headers: Headers;
+	/** Request */
+	request: Request;
 }
 
 export type ComponentPreload = [SSRLoadedRenderer[], ComponentInstance];
@@ -65,7 +63,7 @@ export async function preload({ astroConfig, filePath, viteServer }: Pick<SSROpt
 
 /** use Vite to SSR */
 export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInstance, ssrOpts: SSROptions): Promise<RenderResponse> {
-	const { astroConfig, filePath, logging, mode, origin, pathname, method, headers, route, routeCache, viteServer } = ssrOpts;
+	const { astroConfig, filePath, logging, mode, origin, pathname, request, route, routeCache, viteServer } = ssrOpts;
 	const legacy = astroConfig.buildOptions.legacyBuild;
 
 	// Add hoisted script tags
@@ -145,12 +143,11 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta
 			}
 		},
 		renderers,
+		request,
 		route,
 		routeCache,
 		site: astroConfig.buildOptions.site,
 		ssr: astroConfig.buildOptions.experimentalSsr,
-		method,
-		headers,
 	});
 
 	if (route?.type === 'endpoint' || content.type === 'response') {
diff --git a/packages/astro/src/core/render/request.ts b/packages/astro/src/core/render/request.ts
deleted file mode 100644
index 5956c78679..0000000000
--- a/packages/astro/src/core/render/request.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import type { Params } from '../../@types/astro';
-import { canonicalURL as utilCanonicalURL } from '../util.js';
-
-type Site = string | undefined;
-
-export interface AstroRequest {
-	/** get the current page URL */
-	url: URL;
-
-	/** get the current canonical URL */
-	canonicalURL: URL;
-
-	/** get page params (dynamic pages only) */
-	params: Params;
-
-	headers: Headers;
-
-	method: string;
-}
-
-export type AstroRequestSSR = AstroRequest;
-
-export function createRequest(method: string, pathname: string, headers: Headers, origin: string, site: Site, ssr: boolean): AstroRequest {
-	const url = new URL('.' + pathname, new URL(origin));
-
-	const canonicalURL = utilCanonicalURL('.' + pathname, site ?? url.origin);
-
-	const request: AstroRequest = {
-		url,
-		canonicalURL,
-		params: {},
-		headers,
-		method,
-	};
-
-	if (!ssr) {
-		// Headers are only readable if using SSR-mode. If not, make it an empty headers
-		// object, so you can't do something bad.
-		request.headers = new Headers();
-
-		// Disallow using query params.
-		request.url = new URL(request.url);
-
-		for (const [key] of request.url.searchParams) {
-			request.url.searchParams.delete(key);
-		}
-	}
-
-	return request;
-}
diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts
index 8b14c99bdd..6f03d48061 100644
--- a/packages/astro/src/core/render/result.ts
+++ b/packages/astro/src/core/render/result.ts
@@ -3,7 +3,7 @@ import type { AstroGlobal, AstroGlobalPartial, MarkdownParser, MarkdownRenderOpt
 import { renderSlot } from '../../runtime/server/index.js';
 import { LogOptions, warn } from '../logger.js';
 import { isCSSRequest } from './dev/css.js';
-import { createRequest } from './request.js';
+import { canonicalURL as utilCanonicalURL } from '../util.js';
 import { isScriptRequest } from './script.js';
 
 function onlyAvailableInSSR(name: string) {
@@ -26,8 +26,7 @@ export interface CreateResultArgs {
 	site: string | undefined;
 	links?: Set<SSRElement>;
 	scripts?: Set<SSRElement>;
-	headers: Headers;
-	method: string;
+	request: Request;
 }
 
 class Slots {
@@ -72,10 +71,10 @@ class Slots {
 }
 
 export function createResult(args: CreateResultArgs): SSRResult {
-	const { legacyBuild, markdownRender, method, origin, headers, params, pathname, renderers, resolve, site } = args;
+	const { legacyBuild, markdownRender, origin, params, pathname, renderers, request, resolve, site } = args;
 
-	const request = createRequest(method, pathname, headers, origin, site, args.ssr);
-	request.params = params;
+	const url = new URL(request.url);
+	const canonicalURL = utilCanonicalURL('.' + pathname, site ?? url.origin);
 
 	// Create the result object that will be passed into the render function.
 	// This object starts here as an empty shell (not yet the result) but then
@@ -90,6 +89,8 @@ export function createResult(args: CreateResultArgs): SSRResult {
 
 			const Astro = {
 				__proto__: astroGlobal,
+				canonicalURL,
+				params,
 				props,
 				request,
 				redirect: args.ssr
diff --git a/packages/astro/src/core/request.ts b/packages/astro/src/core/request.ts
new file mode 100644
index 0000000000..74ce72eec3
--- /dev/null
+++ b/packages/astro/src/core/request.ts
@@ -0,0 +1,32 @@
+import type { IncomingHttpHeaders } from 'http';
+
+type HeaderType = Headers | Record<string, any> | IncomingHttpHeaders;
+
+export function createRequest(url: URL | string, headers: HeaderType, method: string = 'GET'): Request {
+	let headersObj = headers instanceof Headers ? headers :
+		new Headers(Object.entries(headers as Record<string, any>));
+	
+	const request = new Request(url.toString(), {
+		method: method,
+		headers: headersObj
+	});
+
+	Object.defineProperties(request, {
+		canonicalURL: {
+			get() {
+				console.warn(`Astro.request.canonicalURL has been moved to Astro.canonicalURL`);
+				return undefined;
+			}
+		},
+		params: {
+			get() {
+				console.warn(`Astro.request.params has been moved to Astro.params`);
+				return undefined;
+			}
+		}
+	});
+
+	// TODO warn
+
+	return request;
+}
diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts
index bc45596dae..ec45ba8d51 100644
--- a/packages/astro/src/vite-plugin-astro-server/index.ts
+++ b/packages/astro/src/vite-plugin-astro-server/index.ts
@@ -10,11 +10,11 @@ import { createSafeError } from '../core/util.js';
 import { ssr, preload } from '../core/render/dev/index.js';
 import { call as callEndpoint } from '../core/endpoint/dev/index.js';
 import * as msg from '../core/messages.js';
+import { createRequest } from '../core/request.js';
 
 import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js';
 import serverErrorTemplate from '../template/5xx.js';
 import { RouteCache } from '../core/render/route-cache.js';
-import { AstroRequest } from '../core/render/request.js';
 
 interface AstroPluginOptions {
 	config: AstroConfig;
@@ -117,9 +117,19 @@ async function handleRequest(
 	const site = config.buildOptions.site ? new URL(config.buildOptions.site) : undefined;
 	const devRoot = site ? site.pathname : '/';
 	const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
+	const buildingToSSR = !!config._ctx.adapter?.serverEntrypoint;
 	const url = new URL(origin + req.url);
 	const pathname = decodeURI(url.pathname);
 	const rootRelativeUrl = pathname.substring(devRoot.length - 1);
+	if(!buildingToSSR) {
+		// Prevent user from depending on search params when not doing SSR.
+		for(const [key] of url.searchParams) {
+			url.searchParams.delete(key);
+		}
+	}
+
+	// Headers are only available when using SSR.
+	const request = createRequest(url, buildingToSSR ? req.headers : new Headers(), req.method);
 
 	try {
 		if (!pathname.startsWith(devRoot)) {
@@ -166,10 +176,9 @@ async function handleRequest(
 					filePath: filePathCustom404,
 					logging,
 					mode: 'development',
-					method: 'GET',
-					headers: new Headers(Object.entries(req.headers as Record<string, any>)),
 					origin,
 					pathname: rootRelativeUrl,
+					request,
 					route: routeCustom404,
 					routeCache,
 					viteServer,
@@ -190,8 +199,7 @@ async function handleRequest(
 			route,
 			routeCache,
 			viteServer,
-			method: req.method || 'GET',
-			headers: new Headers(Object.entries(req.headers as Record<string, any>)),
+			request,
 		};
 
 		// Route successfully matched! Render it.
diff --git a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/blog/[year]/[slug].astro b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/blog/[year]/[slug].astro
index b5c8ec282e..12e686366c 100644
--- a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/blog/[year]/[slug].astro
+++ b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/blog/[year]/[slug].astro
@@ -6,7 +6,7 @@ export async function getStaticPaths() {
     ]
 }
 
-const { year, slug } = Astro.request.params
+const { year, slug } = Astro.params
 ---
 
 <html>
@@ -14,4 +14,4 @@ const { year, slug } = Astro.request.params
     <title>{year} | {slug}</title>
   </head>
   <body></body>
-</html>
\ No newline at end of file
+</html>
diff --git a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/pizza/[...pizza].astro b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/pizza/[...pizza].astro
index 02ef8ef478..a58b314e36 100644
--- a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/pizza/[...pizza].astro
+++ b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/pizza/[...pizza].astro
@@ -8,7 +8,7 @@ export function getStaticPaths() {
 		params: { pizza: 'grimaldis/new-york' },
   }]
 }
-const { pizza } = Astro.request.params
+const { pizza } = Astro.params
 ---
 <html lang="en">
 	<head>
@@ -19,4 +19,4 @@ const { pizza } = Astro.request.params
 	<body>
 		<h1>Welcome to {pizza ?? 'The landing page'}</h1>
 	</body>
-</html>
\ No newline at end of file
+</html>
diff --git a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/pizza/[cheese]-[topping].astro b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/pizza/[cheese]-[topping].astro
index 353805c5cd..a698a76d78 100644
--- a/packages/astro/test/fixtures/astro-get-static-paths/src/pages/pizza/[cheese]-[topping].astro
+++ b/packages/astro/test/fixtures/astro-get-static-paths/src/pages/pizza/[cheese]-[topping].astro
@@ -6,7 +6,7 @@ export function getStaticPaths() {
 		params: { cheese: 'provolone', topping: 'sausage' },
   }]
 }
-const { cheese, topping } = Astro.request.params
+const { cheese, topping } = Astro.params
 ---
 <html lang="en">
 	<head>
@@ -18,4 +18,4 @@ const { cheese, topping } = Astro.request.params
 		<h1>🍕 It's pizza time</h1>
 		<p>{cheese}-{topping}</p>
 	</body>
-</html>
\ No newline at end of file
+</html>
diff --git a/packages/astro/test/fixtures/ssr-dynamic/src/pages/[id].astro b/packages/astro/test/fixtures/ssr-dynamic/src/pages/[id].astro
index b976757e21..e646261729 100644
--- a/packages/astro/test/fixtures/ssr-dynamic/src/pages/[id].astro
+++ b/packages/astro/test/fixtures/ssr-dynamic/src/pages/[id].astro
@@ -1,5 +1,5 @@
 ---
-const val = Number(Astro.request.params.id);
+const val = Number(Astro.params.id);
 ---
 <html>
 <head>