diff --git a/packages/docs/src/App.tsx b/packages/docs/src/App.tsx
index 1fabe24..ef3fbdd 100644
--- a/packages/docs/src/App.tsx
+++ b/packages/docs/src/App.tsx
@@ -11,6 +11,7 @@ import RSCConcept from "./pages/learn/RSC.mdx";
import SSR from "./pages/learn/SSR.mdx";
import FAQ from "./pages/FAQ.mdx";
import GettingStarted from "./pages/GettingStarted.mdx";
+import MigratingFromViteSPA from "./pages/MigratingFromViteSPA.mdx";
import { Home } from "./pages/Home";
import { NotFound } from "./pages/NotFound";
import { Router } from "./Router";
@@ -36,6 +37,14 @@ const routes: RouteDefinition[] = [
),
}),
+ route({
+ path: "/getting-started/migrating-from-vite-spa",
+ component: (
+
+ {defer(, { name: "MigratingFromViteSPA" })}
+
+ ),
+ }),
route({
path: "/faq",
component: {defer(, { name: "FAQ" })},
diff --git a/packages/docs/src/components/Sidebar/Sidebar.tsx b/packages/docs/src/components/Sidebar/Sidebar.tsx
index 36fcf85..a69ab39 100644
--- a/packages/docs/src/components/Sidebar/Sidebar.tsx
+++ b/packages/docs/src/components/Sidebar/Sidebar.tsx
@@ -15,6 +15,10 @@ export const navigation: NavSection[] = [
title: "Getting Started",
items: [
{ label: "Introduction", href: "/funstack-static/getting-started" },
+ {
+ label: "Migrating from Vite SPA",
+ href: "/funstack-static/getting-started/migrating-from-vite-spa",
+ },
],
},
{
diff --git a/packages/docs/src/pages/MigratingFromViteSPA.mdx b/packages/docs/src/pages/MigratingFromViteSPA.mdx
new file mode 100644
index 0000000..f157403
--- /dev/null
+++ b/packages/docs/src/pages/MigratingFromViteSPA.mdx
@@ -0,0 +1,305 @@
+# Migrating from Vite SPA
+
+Already have a Vite-powered React SPA? This guide walks you through migrating to FUNSTACK Static to unlock React Server Components and improved performance.
+
+## Overview
+
+Migrating from a standard Vite React SPA to FUNSTACK Static involves:
+
+1. Installing FUNSTACK Static
+2. Adding the Vite plugin
+3. Restructuring your entry point into Root and App components
+4. Converting appropriate components to Server Components
+
+The good news: your existing client components work as-is. You can migrate incrementally.
+
+## Step 1: Install Dependencies
+
+Add FUNSTACK Static to your existing project:
+
+```bash
+npm install @funstack/static
+```
+
+Or with pnpm:
+
+```bash
+pnpm add @funstack/static
+```
+
+## Step 2: Update Vite Config
+
+Modify your `vite.config.ts` to add the FUNSTACK Static plugin:
+
+```typescript
+import { funstackStatic } from "@funstack/static";
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ plugins: [
+ funstackStatic({
+ root: "./src/Root.tsx",
+ app: "./src/App.tsx",
+ }),
+ react(),
+ ],
+});
+```
+
+## Step 3: Create the Root Component
+
+The Root component replaces your `index.html` file. Create `src/Root.tsx`:
+
+```tsx
+// src/Root.tsx
+import type React from "react";
+
+export default function Root({ children }: { children: React.ReactNode }) {
+ return (
+
+
+
+
+ My App
+ {/* Add your existing content here */}
+
+
+
{children}
+
+
+ );
+}
+```
+
+Move any content from your `index.html` `` section into this component.
+
+## Step 4: Update Your App Entry Point
+
+Your existing `main.tsx` or `index.tsx` likely looks like this:
+
+```tsx
+// Before: src/main.tsx
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
+import "./index.css";
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+
+
+ ,
+);
+```
+
+With FUNSTACK Static, you no longer need this file. Instead, your `App.tsx` becomes the entry point and is automatically rendered as a Server Component:
+
+```tsx
+// After: src/App.tsx
+import "./index.css";
+import { HomePage } from "./pages/HomePage";
+
+export default function App() {
+ return ;
+}
+```
+
+You can delete `main.tsx` - FUNSTACK Static handles the rendering.
+
+## Step 5: Mark Client Component Boundaries
+
+In a standard Vite SPA, all components are client components. With FUNSTACK Static, components are Server Components by default.
+
+You only need to add `"use client"` to components that are **directly imported by Server Components**. This marks the boundary between server and client code. Components imported by other client components don't need the directive.
+
+```tsx
+// src/components/Counter.tsx
+"use client";
+
+import { useState } from "react";
+import { Button } from "./Button"; // No "use client" needed in Button.tsx
+
+export function Counter() {
+ const [count, setCount] = useState(0);
+ return ;
+}
+```
+
+In this example, `Counter.tsx` needs `"use client"` because it's imported by a Server Component. But `Button.tsx` doesn't need it since it's only imported by `Counter`, which is already a client component.
+
+A component is a client component if it:
+
+- Use React hooks (`useState`, `useEffect`, `useContext`, etc.)
+- Attach event handlers (`onClick`, `onChange`, etc.)
+- Use browser-only APIs (`window`, `document`, `localStorage`, etc.)
+
+## Step 6: Update Your Router (If Applicable)
+
+If you're using React Router or another client-side router, you have two options:
+
+### Option A: Keep Your Existing Router
+
+You can continue using your existing router as a client component:
+
+```tsx
+// src/App.tsx
+import { ClientRouter } from "./ClientRouter";
+
+export default function App() {
+ return ;
+}
+```
+
+```tsx
+// src/ClientRouter.tsx
+"use client";
+
+import { BrowserRouter, Routes, Route } from "react-router-dom";
+import { Home } from "./pages/Home";
+import { About } from "./pages/About";
+
+export function ClientRouter() {
+ return (
+
+
+ } />
+ } />
+
+
+ );
+}
+```
+
+### Option B: Use a Server-Compatible Router
+
+For better performance, consider using `@funstack/router` which supports Server Components:
+
+```bash
+npm install @funstack/router
+```
+
+```tsx
+// src/App.tsx
+import { Router } from "@funstack/router";
+import { route } from "@funstack/router/server";
+import { Home } from "./pages/Home";
+import { About } from "./pages/About";
+
+const routes = [
+ route({ path: "/", component: }),
+ route({ path: "/about", component: }),
+];
+
+export default function App() {
+ return ;
+}
+```
+
+## Step 7: Delete Unnecessary Files
+
+After migration, you can remove:
+
+- `src/main.tsx` (or `src/index.tsx`) - no longer needed
+- `index.html` - replaced by `Root.tsx`
+
+## Common Migration Patterns
+
+### Global Styles
+
+Import global CSS in your `App.tsx`:
+
+```tsx
+// src/App.tsx
+import "./index.css";
+import "./global.css";
+
+export default function App() {
+ // ...
+}
+```
+
+### Context Providers
+
+Wrap client-side providers in a client component:
+
+```tsx
+// src/Providers.tsx
+"use client";
+
+import { ThemeProvider } from "./ThemeContext";
+import { AuthProvider } from "./AuthContext";
+
+export function Providers({ children }: { children: React.ReactNode }) {
+ return (
+
+ {children}
+
+ );
+}
+```
+
+```tsx
+// src/App.tsx
+import { Providers } from "./Providers";
+import { HomePage } from "./pages/HomePage";
+
+export default function App() {
+ return (
+
+
+
+ );
+}
+```
+
+### Environment Variables
+
+Client-side environment variables still work the same way with the `VITE_` prefix:
+
+```tsx
+// In client components
+const apiUrl = import.meta.env.VITE_API_URL;
+```
+
+## Verifying the Migration
+
+Run the development server:
+
+```bash
+npm run dev
+```
+
+Check that:
+
+- Your app loads correctly
+- Interactive components work (clicks, form inputs, etc.)
+- Routing works as expected
+- Styles are applied correctly
+
+Build for production:
+
+```bash
+npm run build
+```
+
+Your static files will be generated in `dist/public`, ready for deployment.
+
+## Troubleshooting
+
+### "Cannot use hooks in Server Component"
+
+Add `"use client"` at the top of components that use React hooks.
+
+### "window is not defined"
+
+Components using browser APIs must be client components. Add `"use client"` directive.
+
+### Styles not loading
+
+Ensure CSS imports are in `App.tsx` or in client components that are actually rendered.
+
+## What's Next?
+
+- Learn about [defer()](/funstack-static/api/defer) for code splitting Server Components
+- Explore [Optimizing RSC Payloads](/funstack-static/learn/optimizing-payloads) for better performance
+- Understand [How It Works](/funstack-static/learn/how-it-works) under the hood