TanStarter Documentation

repository·main·Indexed 23 days ago

https://github.com/mugnavo/tanstarter

A minimal, high-performance starter template for TanStack Start. It provides a production-ready foundation for full-stack React applications using a tech stack that includes React 19, Vite 8, Nitro v3, Drizzle ORM, PostgreSQL, and Better Auth. The template includes a custom vpr CLI for managing dependencies, database migrations, and UI components via shadcn/ui.

Tokens
4K
Snippets
9
Records
26
Agent score
79%

What's inside TanStarter

  1. TanStarter Tech Stack Overview

    main

    TanStarter is a minimal starter template for TanStack Start featuring the following stack:

    • Core: React 19 + React Compiler, TanStack Start, TanStack Router, TanStack Query.
    • Styling: Tailwind CSS, shadcn/ui, Base UI.
    • Runtime/Build: Vite 8, Nitro v3, Vite Plus (vp).
    • Database/ORM: Drizzle ORM, PostgreSQL.
    • Authentication: Better Auth.
    • Linting/Formatting: Oxlint, Oxfmt.
  2. Configure and set up TanStarter

    main

    After scaffolding your project, follow these steps to complete the setup:

    1. Environment Variables: Create a .env file based on the provided .env.example file in your project root.
    2. Database Migrations: Generate and apply your initial Drizzle ORM migrations using the vpr CLI:
      • vpr db generate to generate the migration.
      • vpr db migrate to apply it to your database.
    3. Development Server: Start the local development server with:
      vpr dev
       The server will be available at `http://localhost:3000`.
    
    vpr db generate
    vpr db migrate
    vpr dev
  3. Access authentication data in loaders or beforeLoad

    main

    When you need access to the authenticated user's data within other loaders or beforeLoad hooks, do not rely on passing the user object through the router context. Instead, use authQueryOptions() in conjunction with context.queryClient.

    This pattern leverages TanStack Query's centralized revalidation and caching, ensuring that authentication state is consistent across the application and minimizing unnecessary client-to-server calls.

    // Example pattern for accessing auth data in a child route
    const user = await context.queryClient.ensureQueryData({
      ...authQueryOptions(),
      revalidateIfStale: true,
    });
  4. Implement protected routes using the _auth layout

    main

    In TanStarter, protected routes are implemented using a layout route named _auth. This layout uses the beforeLoad hook to intercept navigation and ensure a user is authenticated before allowing access to any child routes (e.g., _auth/app/*).

    To protect a route tree, define a _auth layout route that uses context.queryClient.ensureQueryData with authQueryOptions() to check for an active session. If no user is found, the route throws a redirect to the /login page.

    Important Security Note: The beforeLoad check is optimized for UX using TanStack Query caching and Better Auth's cookieCache. While this provides fast client-side navigation, it is not a server-side security guarantee. For secure data fetching, mutations, or API routes, you must use authMiddleware (see /lib/auth/middleware.ts).

    import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
    import { authQueryOptions } from "#/lib/auth/queries";
    
    export const Route = createFileRoute("/_auth")({
      component: Outlet,
      beforeLoad: async ({ context }) => {
        const user = await context.queryClient.ensureQueryData({
          ...authQueryOptions(),
          revalidateIfStale: true,
        });
        if (!user) {
          throw redirect({ to: "/login" });
        }
      },
    });
  5. Configure the PostgreSQL database service via Docker Compose

    main

    The docker-compose.yml file defines a db service using the postgres:alpine image. This service is used to provide a local PostgreSQL database instance for the TanStarter application.

    Key configuration details:

    • Port: Maps host port 5432 to container port 5432.
    • Persistence: Uses a named volume postgres_data_tanstarter mapped to /var/lib/postgresql to ensure data persists across container restarts.
    • Credentials:
      • POSTGRES_USER: postgres
      • POSTGRES_PASSWORD: password
      • POSTGRES_DB: tanstarter
    services:
      db:
        image: postgres:alpine
        ports:
          - 5432:5432
        volumes:
          - postgres_data_tanstarter:/var/lib/postgresql
        environment:
          - POSTGRES_USER=postgres
          - POSTGRES_PASSWORD=password
          - POSTGRES_DB=tanstarter
    
    volumes:
      postgres_data_tanstarter:
  6. Configure Drizzle Kit for PostgreSQL

    main

    The drizzle.config.ts file defines the configuration for drizzle-kit used to manage database migrations and schema synchronization. This project uses PostgreSQL as the database dialect and expects the connection string to be provided via the DATABASE_URL environment variable through the #/env/server module.

    Key configuration settings include:

    • out: The directory where migration files are generated (set to ./drizzle).
    • schema: The entry point for the database schema definitions (set to ./src/lib/db/schema/index.ts).
    • dialect: Set to postgresql.
    • dbCredentials: Contains the url required to connect to the database.
    • breakpoints, verbose, and strict: Enabled to provide detailed output and strict schema validation during migration processes.
    import type { Config } from "drizzle-kit";
    
    import { env } from "#/env/server";
    
    export default {
      out: "./drizzle",
      schema: "./src/lib/db/schema/index.ts",
      breakpoints: true,
      verbose: true,
      strict: true,
    
    dialect: "postgresql",
      dbCredentials: {
        url: env.DATABASE_URL,
      },
    } satisfies Config;
  7. Manage TanStarter dependencies and scripts

    main

    TanStarter uses the vpr CLI to wrap common tasks. Use these commands to manage your project:

    Dependency Management

    • vpr deps: Selectively upgrade dependencies using taze.
    • vpx taze@latest -Ilw --maturity-period 3: An alternative way to upgrade packages.

    Database and Auth

    • vpr db <command>: Run drizzle-kit commands (e.g., vpr db generate, vpr db studio).
    • vpr auth:generate: Regenerate the auth database schema located at src/lib/db/schema/auth.schema.ts if you have modified your Better Auth configuration.

    UI and Code Quality

    • vpr ui <command>: Access the shadcn/ui CLI (e.g., vpr ui add button).
    • vpr check: Run both Oxfmt and Oxlint for formatting and linting.
    • vpr format: Run Oxfmt.
    • vpr lint: Run Oxlint.
    vpr db generate
    vpr db migrate
    vpr dev
    vpr ui add button
    vpr check
    vpr deps
  8. Access the aggregated database schema

    main
    The src/lib/db/schema/index.ts file serves as the central entry point for all database schema definitions in the project. It aggregates exports from individual schema files (such as auth.schema.ts) to provide a single import location for database operations and type definitions.
  9. Use authMiddleware to protect routes and fetch user context

    main

    Use authMiddleware to enforce authentication on server requests and server functions. This middleware checks for an active user session and, if found, injects the user object into the request context. If no user is found, it sets the response status to 401 and throws an "Unauthorized" error.

    This middleware utilizes the cookieCache option from your auth configuration (defaulting to 5 minutes in this template), making it suitable for route-level data fetching where slight staleness is acceptable in exchange for reduced database load.