A production-ready full-stack starter template combining React 19 with TypeScript on the frontend and Nitro for the backend API. Built with Vite for blazing-fast development and optimized builds.
⭐ Don't forget to star this repo if you find it useful!
- ⚡ React 19 with TypeScript and Vite
- 🎨 Tailwind CSS 4 + shadcn/ui components
- 🗂️ File-based routing with
vite-plugin-pages - 🔄 Auto-imports for React hooks and components
- 🖼️ SVG as React components with
vite-plugin-svgr - 🔤 Google Fonts integration
- 📦 Path aliases (
@/components, etc.)
- 🚀 Nitro 3 server with H3 handler
- 🛣️ File-based API routing in
/routes - ⚡ Fast development with hot module replacement
- 🔧 TypeScript support out of the box
- ✅ ESLint + Prettier configured
- 🪝 Husky pre-commit hooks
- 🐳 Docker setup included
- 🤖 Dependabot for dependency updates
- 📝 Workspace settings for team collaboration
# Install dependencies
npm install
# Start development server (frontend + backend)
npm run dev
# Build for production
npm run build
# Preview production build
npm run preview
# Lint code
npm run lintThe dev server runs on:
- Frontend: http://localhost:5000
- API: http://localhost:5000/api/\*
Routes are automatically generated from files in src/pages/. Each .tsx file becomes a route.
Documentation: vite-plugin-pages
src/pages/
├── index.tsx → /
├── about.tsx → /about
├── users/
│ ├── index.tsx → /users
│ ├── [id].tsx → /users/:id (dynamic route)
│ └── profile.tsx → /users/profile
└── [...all].tsx → /* (catch-all/404)
All page components must use default exports:
// src/pages/about.tsxconstAbout=()=>{return(<div><h1>About Page</h1></div>);};exportdefaultAbout;Use square brackets for dynamic segments:
// src/pages/users/[id].tsxconstUserDetail=()=>{const{ id }=useParams();// auto-imported from react-routerreturn(<div><h1>User ID: {id}</h1></div>);};exportdefaultUserDetail;Use [...all].tsx for 404 pages or catch-all routes:
// src/pages/[...all].tsx or NotFound.tsxconstNotFound=()=>{return(<div><h1>404 - Page Not Found</h1></div>);};exportdefaultNotFound;Use React Router hooks (auto-imported):
constMyComponent=()=>{constnavigate=useNavigate();constlocation=useLocation();return<buttononClick={()=>navigate("/about")}>Go to About</button>;};API routes are automatically generated from files in routes/. Powered by Nitro and H3.
Documentation:
routes/
├── api/
│ ├── hello.ts → GET/POST /api/hello
│ ├── users/
│ │ ├── index.ts → GET/POST /api/users
│ │ └── [id].ts → GET/POST /api/users/:id
│ └── auth/
│ ├── login.ts → POST /api/auth/login
│ └── logout.ts → POST /api/auth/logout
└── health.ts → GET /health
Use defineEventHandler from H3:
// routes/api/hello.tsexportdefaultdefineEventHandler((event)=>{return{message: "Hello from API!",timestamp: newDate().toISOString(),};});Handle different HTTP methods:
// routes/api/users/index.tsexportdefaultdefineEventHandler(async(event)=>{constmethod=event.method;if(method==="GET"){return{users: []};}if(method==="POST"){constbody=awaitreadBody(event);return{created: true,user: body};}return{error: "Method not allowed"};});Or use method-specific handlers:
// routes/api/users/index.get.tsexportdefaultdefineEventHandler(()=>{return{users: []};});// routes/api/users/index.post.tsexportdefaultdefineEventHandler(async(event)=>{constbody=awaitreadBody(event);return{created: true,user: body};});Use square brackets for dynamic parameters:
// routes/api/users/[id].tsexportdefaultdefineEventHandler((event)=>{constid=getRouterParam(event,"id");return{user: {
id,name: "John Doe",},};});Common H3 utilities:
import{readBody,// Parse request bodygetQuery,// Get query parametersgetRouterParam,// Get route parametersgetCookie,// Get cookiessetCookie,// Set cookiesgetHeader,// Get headerssetResponseStatus,// Set response statussendRedirect,// Send redirect}from"h3";exportdefaultdefineEventHandler(async(event)=>{// Get query params: /api/search?q=testconstquery=getQuery(event);console.log(query.q);// 'test'// Get route params: /api/users/123constid=getRouterParam(event,"id");// Parse JSON bodyconstbody=awaitreadBody(event);// Get headersconstauth=getHeader(event,"authorization");// Set response statussetResponseStatus(event,201);return{success: true};});exportdefaultdefineEventHandler((event)=>{constid=getRouterParam(event,"id");if(!id){throwcreateError({statusCode: 400,statusMessage: "ID is required",});}// Your logic herereturn{ id };});Create middleware in routes/ with .ts extension:
// routes/middleware/auth.tsexportdefaultdefineEventHandler((event)=>{consttoken=getHeader(event,"authorization");if(!token){throwcreateError({statusCode: 401,statusMessage: "Unauthorized",});}// Add user to contextevent.context.user={name: "John"};});Import SVGs as React components by adding ?react query:
importLogofrom"@/assets/react.svg?react";exportconstApp=()=>{return(<div><Logo/></div>);};Configure Google Fonts in configs/fonts.config.ts:
exportconstfonts=[{name: "Inter",styles: "wght@300;400;500;600;700",},{name: "Space Grotesk",styles: "wght@300;400;500;700",},];Automatically imports React hooks and React Router hooks. No need to import useState, useEffect, useNavigate, etc.
// No imports needed!exportfunctionCounter(){const[count,setCount]=useState(0);constnavigate=useNavigate();return(<div><ButtononClick={()=>setCount(count+1)}>Count: {count}</Button></div>);}To enable auto-import for shadcn/ui components, uncomment in vite.config.ts:
AutoImport({imports: ["react","react-router"],dirs: ["./src/components/ui"],// Uncomment this line});.
├── src/
│ ├── assets/ # Static assets (images, SVGs)
│ ├── components/ # React components
│ │ └── ui/ # shadcn/ui components
│ ├── pages/ # Frontend routes (file-based)
│ ├── hooks/ # Custom React hooks
│ ├── utils/ # Utility functions
│ ├── types/ # TypeScript types
│ ├── constants/ # App constants
│ ├── data/ # Static data
│ ├── store/ # State management
│ └── main.tsx # App entry point
├── routes/ # Backend API routes (file-based)
│ └── api/ # API endpoints
├── configs/ # Configuration files
│ └── fonts.config.ts
├── vite.config.ts # Vite configuration
├── tsconfig.json # TypeScript config
└── package.json
Use @/ to import from src/:
import{Button}from"@/components/ui/button";import{cn}from"@/utils/cn";importtype{User}from"@/types";# Build and run with Docker
docker build -t react-ts-starter .
docker run -p 5000:5000 react-ts-starterFor production deployment on a VPS with nginx, PM2, and SSL configuration, see the complete guide:
The guide includes:
- nginx configuration for serving static files and proxying API requests
- PM2 or systemd setup for running the Nitro server
- SSL certificate setup with Let's Encrypt
- Monitoring and troubleshooting tips
- Update and maintenance procedures
- This is a client-side rendered (CSR) application
- For SEO or Server-Side Rendering, consider Next.js, Remix, or Astro
- The Nitro backend is perfect for APIs, serverless functions, and edge deployments
Contributions are welcome! Feel free to open issues or submit pull requests.
MIT