# create-t3-turbo: a Turborepo starter that puts Expo, Next.js and tRPC in one repository

> The T3 Stack monorepo template from t3-oss wires an Expo React Native app, a Next.js 15 app and a Tanstack Start app to shared tRPC, Drizzle and better-auth packages. It is a starting point, not a framework, and the setup steps are where the real work sits.

**t3-oss/create-t3-turbo** — Clean and simple starter repo using the T3 Stack along with Expo React Native

- Repository: https://github.com/t3-oss/create-t3-turbo
- Website: https://turbo.t3.gg
- Stars: 6,110 · Forks: 575
- Language: TypeScript
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/t3-oss-create-t3-turbo

## The problem: one T3 app, two clients, three copies of the same types

The T3 Stack (Next.js, tRPC, Tailwind, and a database layer) assumes a single web app. The moment you add a mobile client, the types, the router and the auth config start to drift. create-t3-turbo exists to answer the question its README poses directly: how do you migrate a T3 application into a monorepo? The audience is developers who already know they want pnpm workspaces and Turborepo, and who want the wiring done before they write product code. It is a template repository, not a library. Nothing is published to npm for you to depend on. You either use GitHub's template button or let Turbo's CLI clone it, and from that point the code is yours to edit. That distinction matters: there is no upgrade path where you pull in a new version of create-t3-turbo and get the improvements for free. The repository layout is the deliverable. It ships apps/expo, apps/nextjs and apps/tanstack-start, plus packages/api, packages/auth, packages/db and packages/ui, with a tooling directory holding shared eslint, prettier, tailwind and typescript configs. Package names use @acme as a placeholder, and the README suggests a find-and-replace to your own scope before you start.

## How the monorepo is wired: tRPC as the seam between Expo and the web apps

The central mechanism is that packages/api holds a tRPC v11 router definition, and every app consumes it as a workspace dependency. The Expo app makes typesafe API calls through tRPC; the Next.js and Tanstack Start apps each run an end-to-end typesafe API server and client. There is one router, so a procedure added in packages/api is immediately callable from the mobile app and from both web apps without a code generation step. Authentication lives in packages/auth and is built on better-auth, while packages/db holds typesafe database calls using Drizzle against Supabase. packages/ui is described as the start of a UI package for the web app using shadcn-ui. Turborepo sits above all of it: the root dev script is turbo watch dev --continue, so running it from the root starts every workspace's dev task and keeps watching. The README notes that although the repo contains both a Next.js and a Tanstack Start version of the web app, you can pick one and delete the other folder before setup. That is a deliberate design choice: the template ships two web front ends to show that the shared packages are not coupled to Next.js, at the cost of a tree that is slightly larger than what any single project needs.

## Installing create-t3-turbo and getting the database and auth schema in place

Start from the repository. The README gives two routes: use the GitHub template button, or run Turbo's CLI with pnpm as the package manager. The CLI form is:

```bash
npx create-turbo@latest -e https://github.com/t3-oss/create-t3-turbo
```

Before anything else, check package.json#engines as the README instructs. The root package.json pins node ^22.21.0 and pnpm ^10.19.0, and declares packageManager pnpm@10.19.0. If your Node version is older, the install will not behave as documented.

Once inside the project, install dependencies, copy the environment template and push the Drizzle schema:

```bash
pnpm i
cp .env.example .env
pnpm db:push
```

The root .env.example documents three things you must fill in: POSTGRES_URL, a Supabase pooler connection string; AUTH_SECRET, which the comment says you can generate with openssl rand -base64 32; and AUTH_DISCORD_ID plus AUTH_DISCORD_SECRET for the preconfigured Discord OAuth provider. Then generate the better-auth schema, which must happen before authentication works at all:

```bash
pnpm --filter @acme/auth generate
```

The README states this runs the Better Auth CLI against packages/auth/script/auth-cli.ts and writes a Drizzle schema to packages/db/src/auth-schema.ts. That file is generated, and the script directory exists specifically so auth-cli.ts is not imported accidentally at runtime; the runtime configuration lives in packages/auth/src/index.ts. For the Expo dev script, the README shows a diff against apps/expo/package.json: set "dev": "expo start --ios" for the iOS simulator or "dev": "expo start --android" for the Android emulator, then run pnpm dev from the root.

## Better-auth and Expo: the OAuth proxy is the part that bites

This is the least optional part of the setup and the one most likely to waste an afternoon. The README is explicit that to get better-auth working with Expo you must either deploy the auth proxy or add your local IP to your OAuth provider. The recommended path is the proxy plugin: deploy the Next.js app, and it forwards auth requests to the proxy server, which handles the OAuth flow and redirects back. The stated benefit is a stable, publicly accessible URL that does not change per deployment and does not depend on which port your app happens to bind. The README gives a concrete example: if port 3000 is taken and Next.js starts on 3001, auth still works without reconfiguring the provider. The alternative, adding something like 192.168.x.y:$PORT to the provider, is described as less reliable because a local IP changes when you change networks, and some providers only allow one callback URL per app. GitHub is named as an example of a provider where that single-callback limit makes the local-IP approach unviable. If you are building a mobile app with OAuth and you have not planned for a deployed proxy, budget for it before you start.

## The database package is edge-bound, and that is a constraint you inherit

The Quick Start note is blunt: packages/db is preconfigured for Supabase and is edge-bound with the Vercel Postgres driver. If you use something else, the README tells you to modify the schema in packages/db/src/schema.ts, the client in packages/db/src/index.ts and the drizzle config in packages/db/drizzle.config.ts. It also points to a GitHub issue comment for the recipe to switch to a non-edge driver: remove export const runtime = "edge"; from all pages and API routes. This is the clearest trade-off in the template. An edge runtime shapes what your database client can do, and the connection string in .env.example even carries a workaround=supabase-pooler.vercel query parameter. If your team runs Postgres on its own hardware, or you need a long-lived connection pool, you are not just changing a URL: you are changing the runtime declaration across the app and re-testing every route that touches the database. The same applies to authentication. better-auth is a specific choice, and swapping it means replacing packages/auth, regenerating the schema and redoing the Expo proxy work described above.

## create-t3-turbo against create-t3-app and a hand-rolled Turborepo

The obvious alternative is create-t3-app, the single-app T3 starter from the same organization. The difference is scope, not quality. create-t3-app scaffolds one Next.js application; create-t3-turbo scaffolds a workspace with three apps and four packages, and its whole purpose is the sharing between them. If you do not have a second client, create-t3-turbo gives you a Turborepo configuration, a tooling directory and a UI package you will not use. The second alternative is building the monorepo yourself: pnpm-workspace.yaml, turbo.json, shared tsconfig and eslint presets, and a tRPC package. That is a day or two of work, and the result is a tree you understand completely. create-t3-turbo is worth taking when you want the better-auth and Expo integration decisions already made, because that combination is the part that is genuinely fiddly. It is not worth taking if your team has already standardized on a different auth library or a different ORM, since you would be deleting the packages that justify the template.

## Maintenance cost, licence and what you own after cloning

The repository is MIT licensed and is not archived. Its last push was on 2026-09-21, one day before this writing, and the README reflects current major versions across the tree: Expo SDK 54, React Native 0.81 on React 19, Next.js 15, tRPC v11, Tailwind CSS v4 with NativeWind v5 on mobile, and Tanstack Start v1 at release-candidate stage. Note that rc designation: the README itself labels Tanstack Start v1 as (rc), so the third web app is the least settled part of the template. Because there are no retrieved releases, there is no versioned upgrade path to follow. The practical maintenance model is that you fork, and you track upstream manually. The root package.json shows how much surface that involves: turbo, typescript, prettier, @turbo/gen and dotenv-cli are dev dependencies, and a postinstall hook runs pnpm dlx sherif@latest to lint the workspace. Every one of those, plus the framework majors listed above, is yours to upgrade. On licensing, MIT places few conditions on reuse, but the template bundles dependencies under their own licences, and better-auth, Supabase and any OAuth provider you connect carry their own terms. That is a question for your own review, not something the README settles.

## Conclusion

Adopt create-t3-turbo if you already want pnpm workspaces, Turborepo and the T3 Stack, and you need a React Native app to share the same tRPC router and database package as your web app. Skip it if you only need a web app (use create-t3-app), if you cannot run Node ^22.21.0 and pnpm ^10.19.0, or if you are not willing to configure OAuth callbacks and a Supabase connection string before anything runs. Before committing, verify that packages/db is still edge-bound to the Vercel Postgres driver, since that choice dictates whether you can use a normal Node server for your API routes.

## FAQ

### What does T3 mean on a turbo?

In this repository, T3 refers to the T3 Stack, the combination of Next.js, tRPC, Tailwind and a database layer that the template builds on. Turbo refers to Turborepo, which the README lists as the tool that runs the monorepo's tasks, including the root dev script turbo watch dev --continue.

### What is a T3 stack?

The README lists the stack used here as Turborepo, tRPC v11, better-auth, Drizzle with Supabase, Tailwind CSS v4, Next.js 15 and Expo with React Native 0.81 and Expo Router. The shared packages are api, auth, db and ui, with tooling configs for eslint, prettier, tailwind and typescript.

### What is T3 software?

In this context T3 software means the T3 Stack and its starter repositories from t3-oss. create-t3-turbo is the monorepo variant, described in its README as the starter repo for migrating a T3 application into a monorepo with Turborepo.

### How do I install T3 code?

For create-t3-turbo, the README gives two routes: use the repository as a GitHub template, or run npx create-turbo@latest -e https://github.com/t3-oss/create-t3-turbo with pnpm. It asks you to check package.json#engines first, since the project pins node ^22.21.0 and pnpm ^10.19.0.

## Sources

- [Issues](https://github.com/t3-oss/create-t3-turbo/issues)
- [License: MIT](https://github.com/t3-oss/create-t3-turbo/blob/main/LICENSE)
- [Project website](https://turbo.t3.gg)
- [README](https://github.com/t3-oss/create-t3-turbo/blob/main/README.md)
- [t3-oss/create-t3-turbo on GitHub](https://github.com/t3-oss/create-t3-turbo)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/t3-oss-create-t3-turbo
