Skip to main content
ZeroStarter’s frontend is built with Next.js 16 and React 19, featuring the latest patterns including React Compiler, App Router, and Server Components. The architecture emphasizes type safety, performance, and developer experience.

Tech Stack

The frontend leverages cutting-edge technologies:

Next.js 16

Latest Next.js with App Router, Server Components, and React 19 support

React 19

React 19 with React Compiler for automatic optimizations

TypeScript

Full type safety across the entire application

Bun Runtime

Blazing fast development with Bun as the JavaScript runtime

Key Features

React Compiler

ZeroStarter enables React Compiler out of the box for automatic memoization:
next.config.ts
import type { NextConfig } from "next"

const nextConfig: NextConfig = {
  reactCompiler: true,
  // ... other config
}

export default nextConfig
With React Compiler enabled, you don’t need to manually use useMemo, useCallback, or memo in most cases. The compiler automatically optimizes your components.

App Router Architecture

The project uses Next.js App Router with a well-organized structure:
src/app/
├── (content)/        # Route group for docs and blog
│   ├── blog/
│   └── docs/
├── (protected)/      # Protected routes requiring auth
│   └── dashboard/
├── api/              # API routes
│   ├── og/          # Open Graph image generation
│   └── search/      # Search endpoint
├── layout.tsx        # Root layout
├── page.tsx          # Home page
└── providers.tsx     # Client providers
Route groups (content) and (protected) organize routes without affecting URLs.

Server Components by Default

All components are Server Components unless marked with "use client". This reduces JavaScript bundle size and improves performance:
src/app/layout.tsx
import type { Metadata } from "next"
import { Navbar } from "@/components/navbar/home"
import { InnerProvider, OuterProvider } from "@/app/providers"

export const metadata: Metadata = {
  title: {
    default: `${config.app.name} - ${config.app.tagline}`,
    template: `%s | ${config.app.name}`,
  },
  // ... metadata configuration
}

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode
}>) {
  return (
    <OuterProvider>
      <html lang="en" suppressHydrationWarning>
        <body className="min-h-dvh antialiased">
          <InnerProvider>
            <Navbar />
            {children}
          </InnerProvider>
        </body>
      </html>
    </OuterProvider>
  )
}

Type-Safe API Client

Full end-to-end type safety with Hono RPC:
src/lib/api/client.ts
import type { AppType } from "@api/hono"
import { hc } from "hono/client"
import { config } from "@/lib/config"

type Client = ReturnType<typeof hc<AppType>>

const hcWithType = (...args: Parameters<typeof hc>): Client => hc<AppType>(...args)

const url = config.api.internalUrl ? config.api.internalUrl : config.api.url

const honoClient = hcWithType(url, {
  init: {
    credentials: "include",
  },
})

export const apiClient = honoClient.api
Use it with full type inference:
import { apiClient } from "@/lib/api/client"

// TypeScript knows the exact response type!
const res = await apiClient.health.$get()
const { data } = await res.json()

Project Structure

web/next/
├── src/
│   ├── app/              # Next.js App Router pages
│   ├── components/       # React components
│   │   ├── ui/          # Shadcn UI components
│   │   ├── navbar/      # Navigation components
│   │   └── sidebar/     # Sidebar components
│   ├── hooks/           # Custom React hooks
│   ├── lib/             # Utility functions and configs
│   │   ├── api/         # API client setup
│   │   └── auth/        # Auth client
│   └── styles/          # Global styles
├── public/              # Static assets
├── components.json      # Shadcn UI config
├── next.config.ts       # Next.js configuration
├── package.json         # Dependencies
└── tsconfig.json        # TypeScript config

Path Aliases

Clean imports with TypeScript path aliases:
tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
Usage:
// Instead of: import { Button } from "../../../components/ui/button"
import { Button } from "@/components/ui/button"
import { apiClient } from "@/lib/api/client"
import { config } from "@/lib/config"

Environment Variables

Type-safe environment variables using @packages/env:
next.config.ts
import { getSafeEnv } from "@packages/env"
import { env } from "@packages/env/web-next"

getSafeEnv(env, "@web/next")

const nextConfig: NextConfig = {
  // Access validated env vars
  rewrites: async () => {
    return [
      {
        source: "/api/:path*",
        destination: `${env.NEXT_PUBLIC_API_URL}/api/:path*`,
      },
    ]
  },
}

Performance Optimizations

Image Optimization

Next.js Image component with automatic optimization:
import Image from "next/image"

<Image
  src={tech.icon.light}
  alt={tech.name}
  fill
  sizes="1.25rem"
  className="block dark:hidden"
/>

Font Optimization

Self-hosted fonts with automatic subsetting:
globals.css
@import "@fontsource-variable/dm-sans";
@import "@fontsource-variable/jetbrains-mono";
@import "@fontsource-variable/caveat";
@import "@fontsource-variable/newsreader";

Code Splitting

Automatic code splitting with dynamic imports:
import dynamic from "next/dynamic"

const DevTools = dynamic(() => import("@/components/devtools"), {
  ssr: false,
})

Development Workflow

1

Start Development Server

bun dev
The Next.js dev server runs with fast refresh and React Compiler.
2

Type Checking

bun run check-types
Run TypeScript compiler to catch type errors.
3

Build for Production

bun run build
Creates optimized production build with automatic optimizations.
4

Start Production Server

bun start
Serves the production build locally.

Next Steps

Routing

Learn about Next.js App Router, route groups, and layouts

Components

Explore Shadcn UI components and usage patterns

Data Fetching

Master TanStack Query for server state management

Styling

Understand Tailwind CSS configuration and patterns