Skip to content
/ rt-stack Public template

Turborepo with modular components, shared configs, containerised deployments and 100% type-safety.

License

Notifications You must be signed in to change notification settings

nktnet1/rt-stack

Repository files navigation

RT Stack

A modern turborepo template for building fullstack projects with modular components, shared configs, containerised deployments and 100% type-safety.

About

Stack overview

Below is an overview of all the components in the stack:

apps
  ├─ web
  |   ├─ react (vite)
  |   ├─ tanstack (router, query, form)
  |   └─ tailwindcss
  ├─ server
  |   └─ hono (wrapper for api & auth)
packages
  ├─ api
  |   └─ trpc with valibot
  ├─ auth
  |   └─ better auth
  ├─ db
  |   └─ drizzle orm (postgresql database)
  ├─ ui
  |   ├─ tailwindcss
  |   └─ shadcn & radix ui
tools
  ├─ eslint
  ├─ prettier
  ├─ tailwind
  └─ typescript

View all catalog dependencies in pnpm-workspace.yaml.

Base Functionalities

The following features are implemented out-of-the-box:

Inspirations & Goals

Many aspects of the RT Stack were derived from the t3-oss/create-t3-turbo. However, there is a preference for:

Additionally, the aim of this project is to always adopting the latest releases of dependencies and tools. For example:

  • react v19
  • tailwindcss v4 & shadcn-ui (canary)
  • trpc v11
  • eslint v9
  • pnpm v10

Quick Start

Prerequisites

Ensure the following tools are available on your system:

  1. node (version 22+)
  2. pnpm (version 10+)
  3. postgres database, which you can easily run using tools like:

Setup

# Create a repository using the rt-stack template (replace YOUR_PROJECT)
pnpm dlx create-turbo@latest -m pnpm -e https://github.com/nktnet1/rt-stack YOUR_PROJECT

# Enter the directory or open in your IDE (replace YOUR_PROJECT)
cd YOUR_PROJECT

# Install all dependencies for apps and packages
pnpm install

# Copy .env.example to .env for all applications and the @repo/db package
pnpm env:copy-example

# Start a local postgres instance in the background (e.g. using docker)
docker compose up db --detach

# Push drizzle schema to your database
pnpm db:push

You can then start all applications with

pnpm dev

By default the following URLs will be accesibile:

Using an External Database

When using an external postgres database (e.g. from supabase), you can skip the step that spins up a local postgres instance with docker.

Instead, you will need to modify the following environment variables:

  1. SERVER_POSTGRES_URL in the file apps/server/.env

    • used at runtime by the backend server in pnpm dev
  2. DB_POSTGRES_URL in the file packages/db/.env

    • used in database schema migrations with pnpm db:push

Developing

Working with a single package

Use pnpm --filter=<name> (where <name> is defined in the package.json of each package).

Example usage:

# Install the nuqs package for our web application:
pnpm --filter=web install nuqs

# Format only the ui package:
pnpm --filter=@repo/ui format

You can get a list of all package names using the command below:

find . -maxdepth 3 -name "package.json" -exec grep '"name":' {} \;

Adding new shadcn components

To install a single Shadcn/UI component, e.g. button, use the command

pnpm ui-add button

You can also open an intera

pnpm ui-add
  • press i to enter interactive mode on startup
  • use j/k (or arrow keys) to navigate up and down.
  • use <Space> to toggle select your desired component(s)
  • hit <Enter> to install all selected components

Tooling Scripts

All scripts are defined in package.json and turbo.json:

pnpm typecheck              # repot typescript isses

pnpm format                 # report prettier issues
pnpm format:fix             # auto-fix prettier issues

pnpm lint                   # report eslint issues
pnpm lint:fix               # auto-fix eslint issues

pnpm clean                  # remove all .cache, .turbo, dist, node_modules

pnpx codemod pnpm/catalog   # migrate dependencies to pnpm-workspace.yaml

Containerisation (Docker/Podman)

Both the web and server applications have been containerised. You can start see this in action by running the commands:

# Start all applications
docker-compose up

# Push drizzle schema to your database - while you can use `pnpm db:push` on
# the host machine if you have installed all the required dependencies, it is
# also possible to do everything within docker.
# Open a second terminal and run the command:
docker compose run --rm drizzle

# Upon completion, you will be inside the `drizzle` docker container instead
# of the host machine. It is now possible to push the schema with:
pnpm db:push

You can then open the web link below in your browser:

Please note that these containers are run in production mode. For further details, see

Deployment

Using Containers

You can deploy applications to any services that supports docker deployment.

Using docker compose (see compose.yaml) is also an option, although this alone may not be production-ready at scale. However, it can be paired with

Personally, I recommend deploying on a Virtual Private Server that has one of these Self-hostable PaaS installed, which automatically handles the complexity of deployment mentioned above for you:

Do note that for the web application, the PUBLIC_SERVER_URL variable available at build time (as a docker build argument), rather than an environment variable at runtime.

Also, both the server application's PUBLIC_WEB_URL and the web application's PUBLIC_SERVER_URL needs to be set as internet-accessible URLs when deployed, e.g. https://mycompany.com and https://api.mycompany.com, rather than referencing http://localhost:8085 like in development.

Using Major Platforms

The web application is a simple React static site powered by Vite, which is easily deployed to platforms such as GitHub/GitLab pages, Vercel and Netlify. You can refer to the vite documentation for deployment guides on all major platforms.

The server application uses the hono web framework with the NodeJS runtime. However, this can be exchanged with other runtimes before deploying to your chosen platforms. For example, deploying to Netlify is covered within Hono's documentations.

Other Notes

Tanstack Router Layout

The following is configured in vite.config.ts web application:

TanStackRouterVite({
  routeToken: 'layout',
}),

This is to allow for a layout.tsx file in each directory similar to NextJS. You can read more about this here.

Server API

There is an artificial delay added in development mode to simulate API usage in real-world environments. You can disable this by removing the timingMiddleware in ./packages/api/src/server/trpc.ts

Environment Variables

This template was made to follow the the recommendation of

In using this template, it is recommended that

  1. each application has a local .env file instead of a global .env at the root of your repository
  2. packages should be pure, i.e. rely on factory methods and receiving inputs to instantiate rather than consuming environment variables directly
    • one exception is the @repo/db package, which requires the DB_POSTGRES_URL variable for schema migration with pnpm db:push
  3. environent variables are prefixed, e.g. SERVER_AUTH_SECRET instead of AUTH_SECRET. Caching in the app's turbo.json can then be configured to use wildcards such as:
    "tasks": {
       "build": {
         "env": ["SERVER_*"],
       }
     }

There is also a script that creates a .env from .env.example of each app/package, which can be run with:

# NOTE: This will not overwrite existing local .env files
pnpm env:copy-example

# To reset any modifications to your .env and restore the examples, run:
pnpm env:remove
pnpm env:copy-example

It is recommended that any new apps that uses environment variables follow the example script set in apps/server/package.json.