This guide will help you set up your local development environment and understand the development workflow.
⚠️ Important: All commands should be run from the monorepo root directory unless specified otherwise.
- Node.js (v22+ recommended)
- pnpm (required package manager)
- Docker (optional, for local PostgreSQL database)
- Git
If you just cloned the repository, run the initialization script first:
pnpm run setupThis interactive script will:
- Prompt for your organization name (e.g.,
@my-company) - Let you choose between Drizzle or Prisma ORM
- Let you choose between Turso or PostgreSQL database
- Update all package names throughout the monorepo
- Generate a secure SESSION_SECRET
- Copy
.env.exampleto.envand.env.docker - Format code and update the lockfile
Note: This replaces the old
pnpm remix initcommand that no longer works with React Router v7+.
pnpm installThis monorepo uses pnpm catalogs to manage dependency versions centrally. This is a powerful workspace feature that helps maintain consistent versions across all packages.
Catalogs define dependency version ranges as reusable constants in the pnpm-workspace.yaml file. Instead of specifying version numbers in each package.json, packages can reference the catalog using the catalog: protocol.
Example from pnpm-workspace.yaml:
catalog:
isbot: 5.1.31
chalk: 5.6.2
dotenv: 17.2.3
catalogs:
typescript:
typescript: 5.9.3
tsx: 4.20.6
tsup: 8.5.0
react19:
react: 19.2.0
react-dom: 19.2.0
"@types/react": 19.2.2
prisma:
prisma: 6.18.0
"@prisma/client": 6.18.0Instead of hard-coding versions, packages reference the catalog:
{
"dependencies": {
"react": "catalog:react19",
"typescript": "catalog:typescript",
"chalk": "catalog:"
}
}- Single source of truth - All versions defined in one place
- Easier upgrades - Update one line to upgrade across all packages
- Fewer merge conflicts - No need to update multiple
package.jsonfiles - Consistency - Ensures all packages use the same versions
When adding a dependency that should be shared across packages:
-
Add to catalog in
pnpm-workspace.yaml:catalog: my-new-package: ^1.0.0
-
Reference in package.json:
pnpm add my-new-package@catalog: --filter @your-org/your-package
Or for a specific named catalog:
pnpm add typescript@catalog:typescript --filter @your-org/your-packageThe stack uses named catalogs to group related dependencies:
typescript- TypeScript and build toolsreact19- React and related packagesreact-router- React Router frameworktailwindcss- Tailwind and styling toolsprisma- Prisma ORM packages (if using Prisma)hono- Server middleware
This organization makes it easy to upgrade entire technology stacks together.
Copy the example environment files:
cp .env.example .env
cp .env.example .env.dockerEdit .env to match your setup. See the Database Guide for database-specific configuration.
Database setup varies based on your ORM (Drizzle or Prisma) and database (Turso or PostgreSQL) choices.
For complete database setup instructions, see the Database Guide.
Quick reference:
- Turso: Configure
.envwithDATABASE_URL="file:../../local.db", then runpnpm run db:migrate:apply - PostgreSQL: Run
pnpm run docker:db, then runpnpm run db:migrate:apply
Run the first build with dependencies:
pnpm run build --filter=@react-router-gospel-stack/webapp...The ... suffix tells Turborepo to also build all dependencies of the webapp.
Tip: Running
pnpm run buildwithout filters will build everything in the monorepo.
Start the React Router dev server:
pnpm run dev --filter=@react-router-gospel-stack/webappYour app should now be running at http://localhost:5173 (or another port if 5173 is taken).
# Run only the webapp
pnpm run dev --filter=@react-router-gospel-stack/webapp
# Run with dependencies in watch mode (recommended for package development)
pnpm run dev --filter=@react-router-gospel-stack/webapp...# Build everything
pnpm run build
# Build specific package
pnpm run build --filter=@react-router-gospel-stack/ui
# Build package and its dependencies
pnpm run build --filter=@react-router-gospel-stack/webapp...To install an npm package in a specific workspace:
# Install in the webapp
pnpm add dayjs --filter @react-router-gospel-stack/webapp
# Install in the ui package
pnpm add lucide-react --filter @react-router-gospel-stack/ui
# Install in workspace root
pnpm add -w <package-name>turbo gen workspace --name @react-router-gospel-stack/foobarbaz --type package --copyThen follow the prompts. See the web-utils package as an example.
Use one of the existing packages (ui, database, business) as a template and copy its structure.
Turborepo caches task outputs to speed up your workflow. Check turbo.json at the monorepo root to see available pipelines:
build- Build packages and appsdev- Start development serverslint- Run ESLinttypecheck- Run TypeScript compilertest- Run unit teststest:e2e:dev- Run Playwright e2e tests
Once a task completes, Turborepo caches its output. If you run the same task again without changing relevant files, it will be instant!
For detailed database operations, see the Database Guide.
Quick reference:
After schema changes:
# Drizzle: Generate new migration (interactive)
pnpm run db:migrate:new
# Prisma: Generate TypeScript client first
pnpm run db:generate
pnpm run db:migrate:new
# Apply migrations (both ORMs)
pnpm run db:migrate:applyView your database:
# Drizzle
pnpm --filter @react-router-gospel-stack/infrastructure db:studio
# Prisma
pnpm --filter @react-router-gospel-stack/infrastructure prisma:studioSwitch ORM or database:
pnpm turbo gen scaffold-database# Create docker network (first time only)
docker network create app_network
# Build the webapp docker image
pnpm docker:build:webapp
# Run the docker image
pnpm docker:run:webappTypeScript configurations are in the config/tsconfig package:
base.json- Base configreact.json- For React appsnode22.json- For Node.js projects
Apps and packages extend these configs in their tsconfig.json:
{
"extends": "@react-router-gospel-stack/tsconfig/react.json",
"compilerOptions": {
// ... specific overrides
}
}ESLint configurations are in the config/eslint package:
base.js- Base rulesreact-router.js- React Router specific rulesplugin.js- Custom ESLint plugin
Apps and packages extend these configs in their eslint.config.js:
import baseConfig from "@react-router-gospel-stack/eslint-config/base";
export default [
...baseConfig,
// ... specific rules
];Tailwind configuration is in the config/tailwind package, exported as a Tailwind plugin and preset.
The ui package defines the design system theme and exports it for use in other packages.
React Router's dev server supports HMR. Changes to your code will be reflected immediately in the browser.
The monorepo uses TypeScript path mappings for internal packages. This allows you to import from packages without building them first during development:
import { db } from "@react-router-gospel-stack/infrastructure";React Router's build step handles compiling these dependencies.
- Always install from root - Run
pnpm installfrom the monorepo root - Use filters - Leverage
--filterto run commands on specific packages - Build dependencies - Use the
...suffix to include dependencies:--filter=webapp... - Cache awareness - Turborepo caches based on file changes. Commit often to avoid cache invalidation
If you see build errors after installing a package, try:
pnpm run generate
pnpm run build --filter=@react-router-gospel-stack/webapp...If port 5173 is already in use, React Router will automatically try the next available port.
Ensure Docker Desktop is running and check container status:
docker ps- Learn about the Architecture of the monorepo
- Configure your Database for production
- Set up Testing in your workflow
- Prepare for Deployment to Fly.io