├── .npmrc ├── packages ├── trpc │ ├── client │ │ ├── index.ts │ │ └── links │ │ │ └── httpBatchLink.ts │ ├── index.ts │ ├── server │ │ ├── procedures │ │ │ ├── index.ts │ │ │ ├── publicProcedure.ts │ │ │ └── protectedProcedure.ts │ │ ├── middlewares │ │ │ ├── openapi │ │ │ │ └── expressMiddleware.ts │ │ │ ├── express │ │ │ │ └── trpcExressMiddleware.ts │ │ │ └── auth.ts │ │ ├── openapi.ts │ │ ├── trpc.ts │ │ ├── routers │ │ │ ├── root.ts │ │ │ └── exampleRouter.ts │ │ └── context.ts │ └── package.json ├── prisma │ ├── index.ts │ ├── .gitignore │ ├── docker-compose.yaml │ ├── schema.prisma │ ├── package.json │ └── tsconfig.json ├── ui │ ├── postcss.config.js │ ├── tailwind.config.js │ ├── .eslintrc.js │ ├── index.tsx │ ├── header.tsx │ ├── tsconfig.json │ ├── button.tsx │ ├── turbo │ │ └── generators │ │ │ ├── templates │ │ │ └── component.hbs │ │ │ └── config.ts │ └── package.json ├── eslint-config-custom │ ├── README.md │ ├── package.json │ ├── library.js │ ├── react-internal.js │ └── next.js ├── tailwind-config │ ├── postcss.config.js │ ├── package.json │ └── tailwind.config.js ├── tsconfig │ ├── package.json │ ├── react-library.json │ ├── base.json │ └── nextjs.json └── prettier-config │ ├── package.json │ └── prettier-config.js ├── tsconfig.json ├── .prettierrc.js ├── apps ├── docs │ ├── .eslintrc.js │ ├── next.config.js │ ├── app │ │ ├── page.tsx │ │ └── layout.tsx │ ├── next-env.d.ts │ ├── tsconfig.json │ ├── .gitignore │ ├── package.json │ └── README.md ├── web │ ├── postcss.config.js │ ├── .eslintrc.json │ ├── styles │ │ └── globals.css │ ├── tailwind.config.js │ ├── next.config.js │ ├── next-env.d.ts │ ├── pages │ │ ├── _app.tsx │ │ ├── _document.tsx │ │ ├── api │ │ │ └── hello.ts │ │ └── index.tsx │ ├── tsconfig.json │ ├── .gitignore │ ├── package.json │ ├── utils │ │ └── trpc.ts │ └── README.md └── server │ ├── tsconfig.json │ ├── package.json │ └── index.ts ├── .env.example ├── .prettierignore ├── .gitignore ├── package.json ├── turbo.json ├── LICENSE └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers = true 2 | -------------------------------------------------------------------------------- /packages/trpc/client/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./"; -------------------------------------------------------------------------------- /packages/trpc/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./"; 2 | -------------------------------------------------------------------------------- /packages/prisma/index.ts: -------------------------------------------------------------------------------- 1 | export * from "@prisma/client"; 2 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/base.json" 3 | } 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = require("prettier-config/prettier-config.js"); -------------------------------------------------------------------------------- /apps/docs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/next"], 3 | }; 4 | -------------------------------------------------------------------------------- /apps/web/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("tailwind-config/postcss.config.js") -------------------------------------------------------------------------------- /apps/web/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["next/core-web-vitals", "prettier"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/web/styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /apps/web/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("tailwind-config/tailwind.config.js") -------------------------------------------------------------------------------- /packages/trpc/client/links/httpBatchLink.ts: -------------------------------------------------------------------------------- 1 | export { httpBatchLink } from "@trpc/client"; 2 | -------------------------------------------------------------------------------- /packages/ui/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("tailwind-config/postcss.config.js") -------------------------------------------------------------------------------- /packages/ui/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = require("tailwind-config/tailwind.config.js") -------------------------------------------------------------------------------- /packages/ui/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["custom/react-internal"], 3 | }; 4 | -------------------------------------------------------------------------------- /packages/prisma/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | # Keep environment variables out of version control 3 | .env 4 | -------------------------------------------------------------------------------- /packages/ui/index.tsx: -------------------------------------------------------------------------------- 1 | // component exports 2 | export * from "./button"; 3 | export * from "./header"; 4 | -------------------------------------------------------------------------------- /apps/docs/next.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | reactStrictMode: true, 3 | transpilePackages: ["ui"], 4 | }; 5 | -------------------------------------------------------------------------------- /packages/trpc/server/procedures/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./protectedProcedure"; 2 | export * from "./publicProcedure"; -------------------------------------------------------------------------------- /packages/eslint-config-custom/README.md: -------------------------------------------------------------------------------- 1 | # `@turbo/eslint-config` 2 | 3 | Collection of internal eslint configurations. 4 | -------------------------------------------------------------------------------- /packages/trpc/server/middlewares/openapi/expressMiddleware.ts: -------------------------------------------------------------------------------- 1 | export { createOpenApiExpressMiddleware } from "trpc-openapi"; 2 | -------------------------------------------------------------------------------- /packages/ui/header.tsx: -------------------------------------------------------------------------------- 1 | export function Header({ text }: { text: string }): JSX.Element { 2 | return

{text}

; 3 | } 4 | -------------------------------------------------------------------------------- /packages/trpc/server/procedures/publicProcedure.ts: -------------------------------------------------------------------------------- 1 | import { t } from "../trpc"; 2 | 3 | export const publicProcedure = t.procedure; 4 | -------------------------------------------------------------------------------- /packages/trpc/server/middlewares/express/trpcExressMiddleware.ts: -------------------------------------------------------------------------------- 1 | export { createExpressMiddleware } from "@trpc/server/adapters/express"; 2 | -------------------------------------------------------------------------------- /packages/tailwind-config/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/react-library.json", 3 | "include": ["."], 4 | "exclude": ["dist", "build", "node_modules"] 5 | } 6 | -------------------------------------------------------------------------------- /apps/web/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | transpilePackages: ["ui"] 5 | } 6 | 7 | module.exports = nextConfig 8 | -------------------------------------------------------------------------------- /packages/trpc/server/procedures/protectedProcedure.ts: -------------------------------------------------------------------------------- 1 | import { isAuthed } from "../middlewares/auth"; 2 | import { t } from "../trpc"; 3 | 4 | export const protectedProcedure = t.procedure.use(isAuthed); 5 | -------------------------------------------------------------------------------- /packages/tsconfig/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tsconfig", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/tailwind-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwind-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /apps/server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/base.json", 3 | "compilerOptions": { 4 | "target": "es6", 5 | "module": "commonjs", 6 | "rootDir": "./", 7 | "outDir": "./build" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /apps/docs/app/page.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Header } from "ui"; 2 | 3 | export default function Page(): JSX.Element { 4 | return ( 5 | <> 6 |
7 | 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/trpc/server/openapi.ts: -------------------------------------------------------------------------------- 1 | import { generateOpenApiDocument } from "trpc-openapi"; 2 | import { appRouter } from "./routers/root"; 3 | 4 | export const openApiDocument = generateOpenApiDocument(appRouter, { 5 | title: "tRPC OpenAPI", 6 | version: "1.0.0", 7 | baseUrl: "http://localhost:3002/api", 8 | }); 9 | -------------------------------------------------------------------------------- /apps/web/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from "next/document"; 2 | 3 | export default function Document() { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .next 3 | public 4 | **/**/node_modules 5 | **/**/.next 6 | **/**/public 7 | 8 | *.lock 9 | *.log 10 | *.test.ts 11 | 12 | .gitignore 13 | .npmignore 14 | .prettierignore 15 | .DS_Store 16 | .eslintignore 17 | packages/prisma/zod 18 | packages/prisma/enums 19 | apps/web/public/embed 20 | -------------------------------------------------------------------------------- /packages/tsconfig/react-library.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "jsx": "react-jsx", 7 | "lib": ["ES2015", "DOM"], 8 | "module": "ESNext", 9 | "target": "es6" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/prisma/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | database: 3 | image: postgres 4 | ports: 5 | - 5001:5432 6 | environment: 7 | - POSTGRES_USER=postgres 8 | - POSTGRES_PASSWORD=postgres 9 | - POSTGRES_DB=prisma 10 | volumes: 11 | - pgdata:/var/lib/postgresql/data 12 | volumes: 13 | pgdata: -------------------------------------------------------------------------------- /packages/trpc/server/trpc.ts: -------------------------------------------------------------------------------- 1 | import { inferAsyncReturnType, initTRPC } from "@trpc/server"; 2 | import { OpenApiMeta } from "trpc-openapi"; 3 | import { createContext } from "./context"; 4 | 5 | export type Context = inferAsyncReturnType; 6 | export const t = initTRPC.context().meta().create(); 7 | -------------------------------------------------------------------------------- /packages/ui/turbo/generators/templates/component.hbs: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | interface Props { 4 | children?: React.ReactNode; 5 | } 6 | 7 | export const {{ pascalCase name }} = ({ children }: Props) => { 8 | return ( 9 |
10 |

{{ name }}

11 | {children} 12 |
13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/trpc/server/routers/root.ts: -------------------------------------------------------------------------------- 1 | import { t } from "../trpc"; 2 | import { exampleRouter } from "./exampleRouter"; 3 | 4 | // Create routes in /routers and add them in appRouter/index.ts 5 | export const appRouter = t.router({ 6 | // Add new routes here 7 | example: exampleRouter, 8 | }); 9 | 10 | export type AppRouter = typeof appRouter; 11 | -------------------------------------------------------------------------------- /apps/web/pages/api/hello.ts: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | import type { NextApiRequest, NextApiResponse } from 'next' 3 | 4 | type Data = { 5 | name: string 6 | } 7 | 8 | export default function handler( 9 | req: NextApiRequest, 10 | res: NextApiResponse 11 | ) { 12 | res.status(200).json({ name: 'Example call from NextJs server' }) 13 | } 14 | -------------------------------------------------------------------------------- /packages/tailwind-config/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | // apps content 5 | `src/**/*.{js,ts,jsx,tsx}`, 6 | `./pages/**/*.{js,ts,jsx,tsx}`, 7 | `./components/**/*.{js,ts,jsx,tsx}`, 8 | // packages content 9 | '../../packages/**/*.{js,ts,jsx,tsx}', 10 | ], 11 | theme: { 12 | extend: {}, 13 | }, 14 | plugins: [], 15 | } 16 | 17 | -------------------------------------------------------------------------------- /packages/prettier-config/prettier-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | bracketSpacing: true, 4 | bracketSameLine: true, 5 | singleQuote: false, 6 | printWidth: 110, 7 | plugins: [ 8 | /** 9 | * **NOTE** tailwind plugin must come last! 10 | * @see https://github.com/tailwindlabs/prettier-plugin-tailwindcss#compatibility-with-other-prettier-plugins 11 | */ 12 | "prettier-plugin-tailwindcss", 13 | ], 14 | }; 15 | -------------------------------------------------------------------------------- /packages/prisma/schema.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | } 7 | 8 | datasource db { 9 | provider = "postgresql" 10 | url = env("DATABASE_URL") 11 | } 12 | 13 | model Example { 14 | id Int @id @default(autoincrement()) 15 | createdAt DateTime @default(now()) 16 | name String @unique 17 | } -------------------------------------------------------------------------------- /packages/trpc/server/middlewares/auth.ts: -------------------------------------------------------------------------------- 1 | import { TRPCError } from "@trpc/server"; 2 | import { t } from "../trpc"; 3 | 4 | // Middleware 5 | export const isAuthed = t.middleware(({ next, ctx }) => { 6 | if (!ctx.userSession) { 7 | throw new TRPCError({ 8 | code: "UNAUTHORIZED", 9 | }); 10 | } 11 | 12 | return next({ 13 | ctx: { 14 | // Infers the `userSession` as non-nullable 15 | userSession: ctx.userSession, 16 | }, 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /apps/web/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/nextjs.json", 3 | "compilerOptions": { 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "noEmit": true, 11 | "incremental": true, 12 | "module": "esnext", 13 | "resolveJsonModule": true, 14 | "jsx": "preserve", 15 | "strict": true 16 | }, 17 | "include": [ 18 | "next-env.d.ts", 19 | "**/*.ts", 20 | "**/*.tsx" 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env*.local 29 | 30 | # vercel 31 | .vercel 32 | 33 | # typescript 34 | *.tsbuildinfo 35 | next-env.d.ts 36 | -------------------------------------------------------------------------------- /apps/docs/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # testing 9 | coverage 10 | 11 | # next.js 12 | .next/ 13 | out/ 14 | build 15 | 16 | # misc 17 | .DS_Store 18 | *.pem 19 | 20 | # debug 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | 25 | # local env files 26 | .env 27 | .env.local 28 | .env.development.local 29 | .env.test.local 30 | .env.production.local 31 | 32 | # turbo 33 | .turbo 34 | 35 | # vercel 36 | .vercel 37 | 38 | # misc 39 | local_notes.txt 40 | -------------------------------------------------------------------------------- /packages/trpc/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@template/trpc", 3 | "version": "1.0.0", 4 | "main": "index.ts", 5 | "private": true, 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@trpc/client": "^10.38.2", 14 | "@trpc/server": "^10.38.2", 15 | "@types/express": "^4.17.17", 16 | "@types/node": "^20.6.0", 17 | "trpc-openapi": "^1.2.0", 18 | "zod": "^3.22.2", 19 | "@template/prisma": "*" 20 | }, 21 | "description": "" 22 | } 23 | -------------------------------------------------------------------------------- /packages/trpc/server/context.ts: -------------------------------------------------------------------------------- 1 | import type { CreateExpressContextOptions } from "@trpc/server/adapters/express"; 2 | import { PrismaClient } from "@template/prisma"; 3 | 4 | // created for each request 5 | export const createContext = ({ req, res }: CreateExpressContextOptions) => { 6 | const prisma = new PrismaClient(); 7 | // return { } // No Context 8 | 9 | // Example context 10 | // Hardcoding userSession, normally you would call getSession from something like nextAuth to populate this 11 | // Check ./routers/exampleInput.exampleInput 12 | return { userSession: true, prisma: prisma }; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui", 3 | "version": "0.0.0", 4 | "main": "./index.tsx", 5 | "types": "./index.tsx", 6 | "license": "MIT", 7 | "scripts": { 8 | "lint": "eslint .", 9 | "generate:component": "turbo gen react-component" 10 | }, 11 | "devDependencies": { 12 | "@turbo/gen": "^1.10.12", 13 | "@types/node": "^20.5.2", 14 | "@types/react": "^18.2.0", 15 | "@types/react-dom": "^18.2.0", 16 | "eslint-config-custom": "*", 17 | "react": "^18.2.0", 18 | "tsconfig": "*", 19 | "typescript": "^4.5.2", 20 | "tailwind-config": "*" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/tsconfig/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "composite": false, 6 | "declaration": true, 7 | "declarationMap": true, 8 | "esModuleInterop": true, 9 | "forceConsistentCasingInFileNames": true, 10 | "inlineSources": false, 11 | "isolatedModules": true, 12 | "moduleResolution": "node", 13 | "noUnusedLocals": false, 14 | "noUnusedParameters": false, 15 | "preserveWatchOutput": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "strictNullChecks": true 19 | }, 20 | "exclude": ["node_modules"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/tsconfig/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "plugins": [{ "name": "next" }], 7 | "allowJs": true, 8 | "declaration": false, 9 | "declarationMap": false, 10 | "incremental": true, 11 | "jsx": "preserve", 12 | "lib": ["dom", "dom.iterable", "esnext"], 13 | "module": "esnext", 14 | "noEmit": true, 15 | "resolveJsonModule": true, 16 | "strictNullChecks": true, 17 | "strict": true, 18 | "target": "es5" 19 | }, 20 | "include": ["src", "next-env.d.ts"], 21 | "exclude": ["node_modules"] 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "build": "turbo run build", 5 | "dev": "dotenv -- turbo run dev", 6 | "prisma": "dotenv -- yarn workspace @template/prisma", 7 | "lint": "turbo run lint", 8 | "format": "prettier --write \"**/*.{ts,tsx,md}\"" 9 | }, 10 | "devDependencies": { 11 | "eslint": "^8.47.0", 12 | "prettier": "^3.0.2", 13 | "prettier-config": "*", 14 | "tsconfig": "*", 15 | "turbo": "latest", 16 | "dotenv-cli": "^7.3.0" 17 | }, 18 | "name": "trpc-server-client-turborepo-template", 19 | "packageManager": "yarn@1.22.19", 20 | "workspaces": [ 21 | "apps/*", 22 | "packages/*" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "1.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev --port 3001", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "next": "^13.4.19", 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0", 15 | "ui": "*" 16 | }, 17 | "devDependencies": { 18 | "@next/eslint-plugin-next": "^13.4.19", 19 | "@types/node": "^17.0.12", 20 | "@types/react": "^18.0.22", 21 | "@types/react-dom": "^18.0.7", 22 | "eslint-config-custom": "*", 23 | "tsconfig": "*", 24 | "typescript": "^4.5.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/prisma/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@template/prisma", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "./index.ts", 6 | "types": "./index.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "migrate": "prisma migrate dev", 10 | "studio": "prisma studio", 11 | "db-up": "docker-compose up -d" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "dependencies": { 17 | "@prisma/client": "^5.3.1", 18 | "@types/node": "^20.6.2", 19 | "prisma": "^5.3.1", 20 | "ts-node": "^10.9.1", 21 | "typescript": "^5.2.2" 22 | }, 23 | "devDependencies": { 24 | "dotenv-cli": "^7.3.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/prisma/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tsconfig/base.json", 3 | "compilerOptions": { 4 | "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 5 | "module": "commonjs" /* Specify what module code is generated. */, 6 | "outDir": "./dist" /* Specify an output folder for all emitted files. */, 7 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 8 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 9 | "strict": true /* Enable all strict type-checking options. */, 10 | "skipLibCheck": true /* Skip type checking all .d.ts files. */ 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalDotEnv": [".env"], 4 | "globalDependencies": ["**/.env.*local"], 5 | "pipeline": { 6 | "build": { 7 | "dependsOn": ["^build"], 8 | "outputs": [".next/**", "!.next/cache/**"], 9 | "dotEnv": [ 10 | ".env.production.local", 11 | ".env.local", 12 | ".env.production", 13 | ".env" 14 | ] 15 | }, 16 | "dev": { 17 | "cache": false, 18 | "persistent": false, 19 | "dotEnv": [ 20 | ".env.development.local", 21 | ".env.local", 22 | ".env.development", 23 | ".env" 24 | ] 25 | }, 26 | "test": { 27 | "dotEnv": [".env.test.local", ".env.test", ".env"] 28 | }, 29 | "migrate":{ 30 | "cache": false 31 | }, 32 | "lint": {} 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/library.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /* 6 | * This is a custom ESLint configuration for use with 7 | * typescript packages. 8 | * 9 | * This config extends the Vercel Engineering Style Guide. 10 | * For more information, see https://github.com/vercel/style-guide 11 | * 12 | */ 13 | 14 | module.exports = { 15 | extends: [ 16 | "@vercel/style-guide/eslint/node", 17 | "@vercel/style-guide/eslint/typescript", 18 | ].map(require.resolve), 19 | parserOptions: { 20 | project, 21 | }, 22 | globals: { 23 | React: true, 24 | JSX: true, 25 | }, 26 | settings: { 27 | "import/resolver": { 28 | typescript: { 29 | project, 30 | }, 31 | }, 32 | }, 33 | ignorePatterns: ["node_modules/", "dist/"], 34 | }; 35 | -------------------------------------------------------------------------------- /apps/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.ts", 6 | "scripts": { 7 | "build": "esbuild index.ts --bundle --platform=node --outfile=build/index.js --external:swagger-ui-dist", 8 | "dev": "nodemon index.ts", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "@template/trpc": "*", 16 | "@types/express": "^4.17.17", 17 | "@types/node": "^20.5.8", 18 | "@types/swagger-ui-express": "^4.1.3", 19 | "cors": "^2.8.5", 20 | "express": "^4.18.2", 21 | "nodemon": "^3.0.1", 22 | "swagger-ui-express": "^5.0.0", 23 | "ts-node": "^10.9.1", 24 | "typescript": "^5.2.2" 25 | }, 26 | "devDependencies": { 27 | "@types/cors": "^2.8.13", 28 | "esbuild": "^0.19.3", 29 | "tsconfig": "*" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/ui/turbo/generators/config.ts: -------------------------------------------------------------------------------- 1 | import type { PlopTypes } from "@turbo/gen"; 2 | 3 | // Learn more about Turborepo Generators at https://turbo.build/repo/docs/core-concepts/monorepos/code-generation 4 | 5 | export default function generator(plop: PlopTypes.NodePlopAPI): void { 6 | // A simple generator to add a new React component to the internal UI library 7 | plop.setGenerator("react-component", { 8 | description: "Adds a new react component", 9 | prompts: [ 10 | { 11 | type: "input", 12 | name: "name", 13 | message: "What is the name of the component?", 14 | }, 15 | ], 16 | actions: [ 17 | { 18 | type: "add", 19 | path: "{{pascalCase name}}.tsx", 20 | templateFile: "templates/component.hbs", 21 | }, 22 | { 23 | type: "append", 24 | path: "index.tsx", 25 | pattern: /(?\/\/ component exports)/g, 26 | template: 'export * from "./{{pascalCase name}}";', 27 | }, 28 | ], 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /apps/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@tanstack/react-query": "^4.33.0", 13 | "@trpc/client": "^10.38.1", 14 | "@trpc/next": "^10.38.1", 15 | "@trpc/react-query": "^10.38.1", 16 | "@types/node": "20.5.6", 17 | "@types/react": "18.2.21", 18 | "@types/react-dom": "18.2.7", 19 | "eslint": "8.48.0", 20 | "eslint-config-next": "13.4.19", 21 | "eslint-plugin-prettier": "^5.0.0", 22 | "next": "13.4.19", 23 | "react": "18.2.0", 24 | "react-dom": "18.2.0", 25 | "typescript": "5.2.2", 26 | "ui": "*", 27 | "zod": "^3.22.2", 28 | "@template/trpc": "*" 29 | }, 30 | "devDependencies": { 31 | "autoprefixer": "^10.4.15", 32 | "eslint-config-custom": "*", 33 | "postcss": "^8.4.28", 34 | "tailwind-config": "*", 35 | "tailwindcss": "^3.3.3", 36 | "tsconfig": "*" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/react-internal.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /* 6 | * This is a custom ESLint configuration for use with 7 | * internal (bundled by their consumer) libraries 8 | * that utilize React. 9 | * 10 | * This config extends the Vercel Engineering Style Guide. 11 | * For more information, see https://github.com/vercel/style-guide 12 | * 13 | */ 14 | 15 | module.exports = { 16 | extends: [ 17 | "@vercel/style-guide/eslint/browser", 18 | "@vercel/style-guide/eslint/typescript", 19 | "@vercel/style-guide/eslint/react", 20 | ].map(require.resolve), 21 | parserOptions: { 22 | project, 23 | }, 24 | globals: { 25 | JSX: true, 26 | }, 27 | settings: { 28 | "import/resolver": { 29 | typescript: { 30 | project, 31 | }, 32 | }, 33 | }, 34 | ignorePatterns: ["node_modules/", "dist/", ".eslintrc.js"], 35 | // add rules configurations here 36 | rules: { 37 | "import/no-default-export": "off", 38 | }, 39 | }; 40 | -------------------------------------------------------------------------------- /packages/eslint-config-custom/next.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /* 6 | * This is a custom ESLint configuration for use with 7 | * Next.js apps. 8 | * 9 | * This config extends the Vercel Engineering Style Guide. 10 | * For more information, see https://github.com/vercel/style-guide 11 | * 12 | */ 13 | 14 | module.exports = { 15 | extends: [ 16 | "@vercel/style-guide/eslint/typescript", 17 | "@vercel/style-guide/eslint/browser", 18 | "@vercel/style-guide/eslint/react", 19 | "@vercel/style-guide/eslint/next", 20 | "eslint-config-turbo", 21 | ].map(require.resolve), 22 | parserOptions: { 23 | project, 24 | }, 25 | globals: { 26 | React: true, 27 | JSX: true, 28 | }, 29 | settings: { 30 | "import/resolver": { 31 | typescript: { 32 | project, 33 | }, 34 | }, 35 | }, 36 | ignorePatterns: ["node_modules/", "dist/"], 37 | // add rules configurations here 38 | rules: { 39 | "import/no-default-export": "off", 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Manak Kumar Singh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /apps/web/utils/trpc.ts: -------------------------------------------------------------------------------- 1 | import { httpBatchLink } from '@template/trpc/client/links/httpBatchLink'; 2 | import { createTRPCNext } from '@trpc/next'; 3 | import type { AppRouter } from '@template/trpc/server/routers/root'; 4 | 5 | function getBaseUrl() { 6 | if (process.env.SERVER_DEPLOY_URL) 7 | return `https://${process.env.SERVER_DEPLOY_URL}`; 8 | 9 | // assume localhost 10 | return `http://localhost:${process.env.NEXT_PUBLIC_SERVER_PORT}`; 11 | } 12 | 13 | export const trpc = createTRPCNext({ 14 | config(opts) { 15 | return { 16 | links: [ 17 | httpBatchLink({ 18 | /** 19 | * If you want to use SSR, you need to use the server's full URL 20 | * @link https://trpc.io/docs/ssr 21 | **/ 22 | url: `${getBaseUrl()}/api/trpc`, 23 | 24 | // You can pass any HTTP headers you wish here 25 | async headers() { 26 | return { 27 | // authorization: getAuthCookie(), 28 | }; 29 | }, 30 | }), 31 | ], 32 | }; 33 | }, 34 | /** 35 | * @link https://trpc.io/docs/ssr 36 | **/ 37 | ssr: false, 38 | }); -------------------------------------------------------------------------------- /apps/server/index.ts: -------------------------------------------------------------------------------- 1 | import { createContext } from "@template/trpc/server/context"; 2 | import { createExpressMiddleware } from "@template/trpc/server/middlewares/express/trpcExressMiddleware"; 3 | import { appRouter } from "@template/trpc/server/routers/root"; 4 | import cors from "cors"; 5 | import express from "express"; 6 | 7 | import swaggerUi from "swagger-ui-express"; 8 | 9 | import { createOpenApiExpressMiddleware } from "@template/trpc/server/middlewares/openapi/expressMiddleware"; 10 | import { openApiDocument } from "@template/trpc/server/openapi"; 11 | 12 | const port: number = 3002 as const; 13 | 14 | // Initialize the express engine 15 | const app: express.Application = express(); 16 | 17 | app.use(cors()); 18 | 19 | // Handle incoming tRPC requests 20 | app.use( 21 | "/api/trpc", 22 | createExpressMiddleware({ 23 | router: appRouter, 24 | createContext, 25 | }), 26 | ); 27 | 28 | // Handle incoming OpenAPI requests 29 | app.use("/api", createOpenApiExpressMiddleware({ router: appRouter, createContext })); 30 | 31 | // Serve Swagger UI with our OpenAPI schema 32 | app.use("/", swaggerUi.serve); 33 | app.get("/", swaggerUi.setup(openApiDocument)); 34 | 35 | // Server setup 36 | app.listen(port, () => { 37 | console.log(`started server on [::]:${port}, url: http://localhost:${port}`); 38 | }); 39 | -------------------------------------------------------------------------------- /apps/docs/README.md: -------------------------------------------------------------------------------- 1 | ## Getting Started 2 | 3 | First, run the development server: 4 | 5 | ```bash 6 | yarn dev 7 | ``` 8 | 9 | Open [http://localhost:3001](http://localhost:3001) with your browser to see the result. 10 | 11 | You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. 12 | 13 | To create [API routes](https://nextjs.org/docs/app/building-your-application/routing/router-handlers) add an `api/` directory to the `app/` directory with a `route.ts` file. For individual endpoints, create a subfolder in the `api` directory, like `api/hello/route.ts` would map to [http://localhost:3001/api/hello](http://localhost:3001/api/hello). 14 | 15 | ## Learn More 16 | 17 | To learn more about Next.js, take a look at the following resources: 18 | 19 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 20 | - [Learn Next.js](https://nextjs.org/learn/foundations/about-nextjs) - an interactive Next.js tutorial. 21 | 22 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 23 | 24 | ## Deploy on Vercel 25 | 26 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_source=github.com&utm_medium=referral&utm_campaign=turborepo-readme) from the creators of Next.js. 27 | 28 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 29 | -------------------------------------------------------------------------------- /apps/web/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | ``` 14 | 15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 16 | 17 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. 18 | 19 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 20 | 21 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 22 | 23 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 24 | 25 | ## Learn More 26 | 27 | To learn more about Next.js, take a look at the following resources: 28 | 29 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 30 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 31 | 32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 33 | 34 | ## Deploy on Vercel 35 | 36 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 37 | 38 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 39 | -------------------------------------------------------------------------------- /apps/web/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { Button } from "ui"; 3 | import { trpc } from "../utils/trpc"; 4 | 5 | export default function Home() { 6 | useEffect(() => { 7 | const asyncFn = async () => { 8 | // An API call for NextJS Server 9 | const sendRequest = await fetch("http://localhost:3000/api/hello"); 10 | const data = await sendRequest.json(); 11 | console.log(data); 12 | }; 13 | 14 | asyncFn(); 15 | }, []); 16 | 17 | // API call for apps/api Express tRPC server 18 | const { 19 | data: exampleCall, 20 | isLoading: isExampleCallLoading, 21 | isError: isExampleCallError, 22 | } = trpc.example.exampleInput.useQuery({ 23 | id: "someStringId", 24 | }); 25 | 26 | // Database call 27 | const { 28 | data: exampleDbCall, 29 | isLoading: isDbCallLoading, 30 | isError: dbCallError, 31 | } = trpc.example.prismaExample.useQuery(); 32 | 33 | return ( 34 |
35 |
36 | Web Page 37 | {isExampleCallError ? ( 38 |
Something went wrong
39 | ) : isExampleCallLoading ? ( 40 |
Loading...
41 | ) : ( 42 |
43 | User Details 44 |
45 | ID : {exampleCall?.id} 46 |
47 |
48 | User Session : {exampleCall?.hasSession ? "true" : "false"} 49 |
50 |
51 | )} 52 |
53 | 54 |
55 | Database Call 56 | {dbCallError ? ( 57 |
Something is wrong with the database
58 | ) : isDbCallLoading ? ( 59 |
Calling database...
60 | ) : ( 61 |
{JSON.stringify(exampleDbCall)}
62 | )} 63 |
64 | 65 |
66 |
68 |
69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /packages/trpc/server/routers/exampleRouter.ts: -------------------------------------------------------------------------------- 1 | import { z } from "zod"; 2 | import { protectedProcedure, publicProcedure } from "../procedures"; 3 | import { t } from "../trpc"; 4 | 5 | export const exampleRouter = t.router({ 6 | // http://localhost:3002/api/example.exampleApi 7 | exampleApi: publicProcedure 8 | .meta({ 9 | openapi: { 10 | method: "GET", 11 | path: "/example.exampleApi", 12 | tags: ["example"], 13 | description: "Calling exampleApi", 14 | }, 15 | }) 16 | .input(z.void()) 17 | .output(z.object({ message: z.string() })) 18 | .query(() => { 19 | return { message: "Sending message from route" }; 20 | }), 21 | 22 | // http://localhost:3002/api/example.exampleInput?id=123123 23 | exampleInput: publicProcedure 24 | .meta({ openapi: { method: "GET", path: "/example.exampleInput", tags: ["example"] } }) 25 | .input(z.object({ id: z.string() })) 26 | .output(z.object({ id: z.string(), hasSession: z.boolean() })) 27 | .query(({ input, ctx }) => { 28 | // return { id: req.input, name: 'Bilbo'}; 29 | 30 | // Add context in context.ts file and call it using req.ctx 31 | return { id: input.id, hasSession: ctx.userSession }; 32 | }), 33 | 34 | superSimple: publicProcedure 35 | .meta({ openapi: { method: "POST", path: "/example.superSimple", tags: ["example"] } }) 36 | .input(z.object({ simpleInput: z.string() })) 37 | .output(z.object({ givenString: z.string() })) 38 | .mutation(({ input }) => { 39 | return { givenString: input.simpleInput }; 40 | }), 41 | 42 | // Change userSession to true / false in /context.ts for this procedure to work 43 | protectedExample: protectedProcedure 44 | .meta({ openapi: { method: "GET", path: "/example.protectedExample", tags: ["example"] } }) 45 | .input(z.void()) 46 | .output(z.object({ context: z.boolean(), message: z.string() })) 47 | .query(({ ctx }) => { 48 | return { context: ctx.userSession, message: "Protected example message" }; 49 | }), 50 | 51 | prismaExample: publicProcedure 52 | .meta({ openapi: { method: "GET", path: "/example.prismaExample", tags: ["exampleDB"] } }) 53 | .input(z.void()) 54 | .output( 55 | z.object({ 56 | context: z.boolean(), 57 | dbData: z.array(z.object({ id: z.number(), createdAt: z.date(), name: z.string() })), 58 | }), 59 | ) 60 | .query(async ({ ctx }) => { 61 | const getExampleData = await ctx.prisma.example.findMany(); 62 | console.log("Database Data : ", getExampleData); 63 | return { context: ctx.userSession, dbData: getExampleData }; 64 | }), 65 | }); 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tRPC Server Client Turborepo Template 2 | 3 | 🚧 **This is a TEMPLATE** 🚧 4 | 5 | A clean **template** designed to kickstart your project, sparing you the effort of configuring everything from scratch. 6 | 7 | This is a straightforward monorepo that includes an Express tRPC server with Prisma ORM. The server interacts with a Next.js application and provides a wide range of features through tRPC. 8 | 9 | With this template, you can quickly set up a powerful server-client architecture for your web application. The combination of Express, tRPC, Prisma and Next.js offers a seamless development experience and enables you to build robust and efficient applications with the ease of adding API documentation through OpenApi and SwaggerUI which comes integrated into this template. 10 | 11 | Feel free to use this template as a starting point for your projects and customize it according to your specific requirements. 12 | 13 | ## What's inside? 14 | 15 | This Turborepo includes the following packages/apps: 16 | 17 | ### Apps and Packages 18 | 19 | - `apps/docs`: A simple [Next.js](https://nextjs.org/) app that can be used to compare changes made to the `apps/web` application. It serves as a reference to understand the modifications. 20 | - `apps/server`: This is a TypeScript Express [tRPC](https://trpc.io/) server with [swaggerUI](https://github.com/swagger-api/swagger-ui). It provides the backend functionality for your application and handles API requests. `packages/trpc` is connected to the server and contains all the procedures. 21 | - `apps/web`: another [Next.js](https://nextjs.org/) app with [tRPC](https://trpc.io/) Client which interacts with `api` package. It also incorporates [TailwindCSS](https://tailwindcss.com/) for styling. 22 | - `packages/trpc`: everything related to [tRPC](https://trpc.io/) including procedures and [trpc-openapi](https://github.com/jlalmes/trpc-openapi) exists in this package folder which is currently being used by `server`. 23 | - `packages/ui`: a stub React component library shared by both `web` and `docs` applications. It includes reusable components and is styled using [TailwindCSS](https://tailwindcss.com/). 24 | - `packages/prisma`: A powerful database ORM that offers type safety and is utilized by the `trpc` package to enhance the developer experience. 25 | - `packages/eslint-config-custom`: `eslint` configurations (includes `eslint-config-next` and `eslint-config-prettier`) 26 | - `packages/tsconfig`: `tsconfig.json`s used throughout the monorepo 27 | - `packages/tailwind-config`: tailwind configuration which is used throughout the monorepo 28 | - `packages/prettier-config`: This package includes the styling configuration for Prettier, ensuring consistent code formatting throughout the monorepo 29 | 30 | ### Project Setup 31 | 32 | In the root directory, install dependencies by running. 33 | 34 | ``` 35 | cd trpc-server-client-turborepo-template 36 | yarn 37 | ``` 38 | 39 | **Setting up .env file** - Copy .env.example file and rename it to .env in the root directory 40 | 41 | #### Setting up Database 42 | 43 | To configure the database for your project, you have two options: 44 | 45 | 1. If you have postgresql database ready, add the connection string to `DATABASE_URL`. 46 | 47 | 2. If you don't have a database and have Docker installed on your system, you can easily set it up using the following script command in your CLI: 48 | 49 | ``` 50 | yarn prisma db-up 51 | ``` 52 | 53 | Note : To check the environment details you can find the docker-compose file in `packages/prisma/docker-compose.yaml` 54 | 55 | ### Scripts 56 | 57 | Scripts can be ran in the root directory by typing the following in cli. 58 | 59 | - `yarn run dev` : Runs the entire monorepo. 60 | - `yarn prisma studio` : Runs prisma studio from `package/prisma` 61 | - `yarn prisma migrate` : Runs prisma database migrations from `package/prisma` 62 | - `yarn prisma db-up` : Installs/Runs postgresql image from `package/prisma` in Docker. 63 | 64 | ### Build 65 | 66 | To build all apps and packages, run the following command: 67 | 68 | ``` 69 | cd trpc-server-client-turborepo-template 70 | yarn 71 | ``` 72 | 73 | ### Remote Caching 74 | 75 | Turborepo can use a technique known as [Remote Caching](https://turbo.build/repo/docs/core-concepts/remote-caching) to share cache artifacts across machines, enabling you to share build caches with your team and CI/CD pipelines. 76 | 77 | By default, Turborepo will cache locally. To enable Remote Caching you will need an account with Vercel. If you don't have an account you can [create one](https://vercel.com/signup), then enter the following commands: 78 | 79 | ``` 80 | cd trpc-server-client-turborepo-template 81 | npx turbo login 82 | ``` 83 | 84 | This will authenticate the Turborepo CLI with your [Vercel account](https://vercel.com/docs/concepts/personal-accounts/overview). 85 | 86 | Next, you can link your Turborepo to your Remote Cache by running the following command from the root of your Turborepo: 87 | 88 | ``` 89 | npx turbo link 90 | ``` 91 | 92 | ## Contributions 93 | 94 | I welcome contributions to help improve this template! If you have any issues or recommendations for enhancements, please feel free to raise them. Your feedback is valuable and will help me make this template even better. 95 | 96 | To contribute, you can: 97 | 98 | - **Raise an issue**: If you encounter any problems or have suggestions for improvements, please create an issue on this GitHub repository. I will review it and work together with you to find a solution. 99 | 100 | - **Submit a pull request**: If you have a specific improvement in mind, you can fork the repository, make your changes, and submit a pull request. I will review your changes and merge them if they align with the project's goals. 101 | 102 | By contributing to this template, you'll be helping not only me but also the community by making it more robust and user-friendly! 103 | At the moment I would really appreciate some help with file structure recommendations for Turborepo for the technologies inside the repository. 104 | 105 | Thank you for your support! 106 | --------------------------------------------------------------------------------