start-simple
v2.0.1
Published
A minimal full-stack setup with out-of-the-box support for SSR, SSG, and sitemap generation.
Maintainers
Readme
What is Start Simple?
A minimal full-stack monorepo with out-of-the-box SSR, SSG, and routing — powered by Vite, React, and Express. No rewrites needed. Just configure your routes and loaders.
Why Start Simple?
- Zero learning curve — if you know React and Express, you're ready.
- No frontend rewrites — your existing React code works as-is.
- Route-based rendering — declare which routes are SSR or SSG in one config file.
- Loaders — each route can fetch its own data server-side, just like Remix/Next.js.
- Works with any frontend — swap React for Vue/Svelte and the SSR pipeline still works.
Installation
npx start-simple my-app
cd my-app
npm install
npm run devProject Structure
my-app/
├── packages/
│ ├── frontend/ # Vite + React SSR app
│ │ ├── renderingConfig.js # ✨ SSG & SSR route definitions + loaders
│ │ ├── server.js # Express SSR server (dev & prod)
│ │ ├── scripts/
│ │ │ └── prerender.js # Build-time SSG pre-renderer
│ │ └── src/
│ │ ├── entry-client.jsx
│ │ ├── entry-server.jsx
│ │ ├── App.jsx
│ │ ├── context/
│ │ │ └── LoaderDataContext.jsx
│ │ └── pages/
│ │ ├── Home.jsx
│ │ ├── About.jsx
│ │ └── Post.jsx
│ └── backend/ # Express API server
│ └── index.js
├── package.json # Monorepo root (npm workspaces + Turbo)
└── turbo.jsonAvailable Scripts
Run all scripts from the monorepo root (my-app/):
| Script | Description |
| --- | --- |
| npm run dev | Start the SSR frontend and the backend API on concurrent ports |
| npm run frontend | Start only the frontend SSR dev server (node server) |
| npm run backend | Start only the backend API server |
| npm run start | Start the frontend in production SSR mode (pre-rendered SSG pages served from disk) |
| npm run build | Build the frontend for production + pre-render SSG routes (automatically triggered) |
Quick Start: How it Works
1. Define routes in renderingConfig.js
export const ssgRoutes = [
{
path: "/",
loader: async () => ({ title: "Home" }),
},
];
export const ssrRoutes = [
{
path: "/post/:id",
loader: async ({ params }) => {
const res = await fetch(`https://api.example.com/posts/${params.id}`);
return res.json();
},
},
];2. Use loader data in your component
import { useLoaderData } from "./context/LoaderDataContext";
export default function Post() {
const data = useLoaderData();
return <h1>{data.title}</h1>;
}3. That's it!
- SSR routes — loader runs on the server for every request.
- SSG routes — loader runs at build time, HTML is saved to disk.
- Unlisted routes — treated as SSG by default (client-side only in dev).
Rendering Modes
| Mode | When Loader Runs | Best For | | --- | --- | --- | | SSG | Once at build time | Static pages (home, about, blog index) | | SSR | Every request | Dynamic pages (user profiles, posts, search results) | | Default (unlisted) | Client-side only | Pages without data needs |
Deployment
# 1. Build everything
npm run build
# 2. Start the production SSR server
npm run start
# 3. Start the API server
npm run backendFurther Reading
- documentation.md — Full API reference
- tutorial.md — Step-by-step guide to adding routes
- mechanism.md — Deep dive into how SSR/SSG works internally
License
MIT
