Skip to content

Latest commit

History

151 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

React + TypeScript + Nitro Full-Stack Starter

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!


Features

Frontend

  • 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.)

Backend

  • 🚀 Nitro 3 server with H3 handler
  • 🛣️ File-based API routing in /routes
  • Fast development with hot module replacement
  • 🔧 TypeScript support out of the box

Developer Experience

  • ESLint + Prettier configured
  • 🪝 Husky pre-commit hooks
  • 🐳 Docker setup included
  • 🤖 Dependabot for dependency updates
  • 📝 Workspace settings for team collaboration

Quick Start

# 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 lint

The dev server runs on:


Client-Side Routing (Frontend)

File-Based Routing with vite-plugin-pages

Routes are automatically generated from files in src/pages/. Each .tsx file becomes a route.

Documentation: vite-plugin-pages

Route Structure

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)

Creating Pages

All page components must use default exports:

// src/pages/about.tsxconstAbout=()=>{return(<div><h1>About Page</h1></div>);};exportdefaultAbout;

Dynamic Routes

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;

Catch-All Routes

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;

Navigation

Use React Router hooks (auto-imported):

constMyComponent=()=>{constnavigate=useNavigate();constlocation=useLocation();return<buttononClick={()=>navigate("/about")}>Go to About</button>;};

Server-Side Routing (Backend API)

File-Based API Routing with Nitro

API routes are automatically generated from files in routes/. Powered by Nitro and H3.

Documentation:

Route Structure

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

Creating API Handlers

Use defineEventHandler from H3:

// routes/api/hello.tsexportdefaultdefineEventHandler((event)=>{return{message: "Hello from API!",timestamp: newDate().toISOString(),};});

HTTP Methods

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};});

Dynamic Routes

Use square brackets for dynamic parameters:

// routes/api/users/[id].tsexportdefaultdefineEventHandler((event)=>{constid=getRouterParam(event,"id");return{user: {
id,name: "John Doe",},};});

Request Handling

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};});

Error Handling

exportdefaultdefineEventHandler((event)=>{constid=getRouterParam(event,"id");if(!id){throwcreateError({statusCode: 400,statusMessage: "ID is required",});}// Your logic herereturn{ id };});

Middleware

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"};});

Vite Plugins Guide

vite-plugin-svgr

Import SVGs as React components by adding ?react query:

importLogofrom"@/assets/react.svg?react";exportconstApp=()=>{return(<div><Logo/></div>);};

unplugin-fonts

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",},];

Documentation

unplugin-auto-import

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});

Project Structure

.
├── 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

Path Aliases

Use @/ to import from src/:

import{Button}from"@/components/ui/button";import{cn}from"@/utils/cn";importtype{User}from"@/types";

Deployment

Docker

# Build and run with Docker
docker build -t react-ts-starter .
docker run -p 5000:5000 react-ts-starter

VPS Deployment with nginx

For production deployment on a VPS with nginx, PM2, and SSL configuration, see the complete guide:

📖 VPS Deployment 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

Notes

  • 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

Contributing

Contributions are welcome! Feel free to open issues or submit pull requests.


License

MIT

About

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.

Topics

Resources

Stars

102 stars

Watchers

1 watching

Forks

Used by

Contributors

Languages