diff --git a/examples/with-firebase/.firebaserc b/examples/with-firebase/.firebaserc
new file mode 100644
index 0000000000000..a4ab0f4157211
--- /dev/null
+++ b/examples/with-firebase/.firebaserc
@@ -0,0 +1,5 @@
+{
+ "projects": {
+ "default": "turborepo-firebase-example"
+ }
+}
diff --git a/examples/with-firebase/README.md b/examples/with-firebase/README.md
new file mode 100644
index 0000000000000..7545e96d04bfc
--- /dev/null
+++ b/examples/with-firebase/README.md
@@ -0,0 +1,37 @@
+# `Turborepo` Vite starter
+
+This is an official starter Turborepo.
+
+## What's inside?
+
+This Turborepo includes the following packages and apps:
+
+### Apps and Packages
+
+- `api`: a firebase clould function using express, built with rollup
+- `web`: a vanilla [vite](https://vitejs.dev) ts app
+- `config`: eslint shared config
+- `shared`: shared util lib that you share code with various apps
+- `tsconfig`: `tsconfig.json`s used throughout the monorepo
+
+Each package and app is 100% [TypeScript](https://www.typescriptlang.org/).
+
+### Utilities
+
+This Turborepo has some additional tools already setup for you:
+
+- [TypeScript](https://www.typescriptlang.org/) for static type checking
+- [ESLint](https://eslint.org/) for code linting
+- [Jest](https://jestjs.io) test runner for all things JavaScript
+- [Prettier](https://prettier.io) for code formatting
+
+## Using this example
+
+Run the following command:
+
+```sh
+npx degit vercel/turborepo/examples/with-firebase with-firebase
+cd with-firebase
+yarn
+git init . && git add . && git commit -m "Init"
+```
diff --git a/examples/with-firebase/apps/api/.gitignore b/examples/with-firebase/apps/api/.gitignore
new file mode 100644
index 0000000000000..ffab5d12e9070
--- /dev/null
+++ b/examples/with-firebase/apps/api/.gitignore
@@ -0,0 +1,3 @@
+*.log
+.runtimeconfig.json
+dist/
\ No newline at end of file
diff --git a/examples/with-firebase/apps/api/jest.config.ts b/examples/with-firebase/apps/api/jest.config.ts
new file mode 100644
index 0000000000000..b5865bcc90db0
--- /dev/null
+++ b/examples/with-firebase/apps/api/jest.config.ts
@@ -0,0 +1,15 @@
+import type { Config } from "@jest/types";
+
+// Sync object
+const config: Config.InitialOptions = {
+ verbose: true,
+ transform: {
+ "^.+\\.(ts|tsx)$": "ts-jest",
+ },
+ globals: {
+ "ts-jest": {
+ tsconfig: "tsconfig.json",
+ },
+ },
+};
+export default config;
diff --git a/examples/with-firebase/apps/api/package.json b/examples/with-firebase/apps/api/package.json
new file mode 100644
index 0000000000000..037577ce11c18
--- /dev/null
+++ b/examples/with-firebase/apps/api/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "api",
+ "scripts": {
+ "dev": "rollup -w -c rollup.config.js",
+ "build": "rimraf ./dist/**/* && rollup -c rollup.config.js",
+ "deploy": "firebase deploy --only functions"
+ },
+ "engines": {
+ "node": "16"
+ },
+ "type": "module",
+ "main": "dist/index.js",
+ "dependencies": {
+ "express": "^4.17.3",
+ "firebase-admin": "^10.1.0",
+ "firebase-functions": "^3.20.1",
+ "rollup": "^2.70.2",
+ "shared": "*"
+ },
+ "devDependencies": {
+ "@rollup/plugin-node-resolve": "^13.2.1",
+ "@rollup/plugin-typescript": "^8.3.2",
+ "eslint": "^8.11.0",
+ "rimraf": "^3.0.2",
+ "ts-node": "^10.7.0",
+ "typescript": "^4.6.3"
+ },
+ "private": true
+}
diff --git a/examples/with-firebase/apps/api/rollup.config.js b/examples/with-firebase/apps/api/rollup.config.js
new file mode 100644
index 0000000000000..36da9ee3df4b8
--- /dev/null
+++ b/examples/with-firebase/apps/api/rollup.config.js
@@ -0,0 +1,17 @@
+import typescript from "@rollup/plugin-typescript";
+import nodeResolve from "@rollup/plugin-node-resolve";
+import pkg from "./package.json";
+
+export default {
+ input: "src/index.ts",
+ external: [...Object.keys(pkg.dependencies)],
+ plugins: [typescript(), nodeResolve()],
+ onwarn: () => {
+ return;
+ },
+ output: {
+ file: "dist/index.js",
+ format: "es",
+ sourcemap: true,
+ },
+};
diff --git a/examples/with-firebase/apps/api/src/index.ts b/examples/with-firebase/apps/api/src/index.ts
new file mode 100644
index 0000000000000..bb28d25f80881
--- /dev/null
+++ b/examples/with-firebase/apps/api/src/index.ts
@@ -0,0 +1,11 @@
+import express from "express";
+import * as functions from "firebase-functions";
+import { exampleConfigFromShared } from "shared/util";
+
+const app = express();
+
+app.get("*", (req, res) => {
+ res.send(exampleConfigFromShared);
+});
+
+export const server = functions.https.onRequest(app);
diff --git a/examples/with-firebase/apps/api/tsconfig.json b/examples/with-firebase/apps/api/tsconfig.json
new file mode 100644
index 0000000000000..76e5bfd005931
--- /dev/null
+++ b/examples/with-firebase/apps/api/tsconfig.json
@@ -0,0 +1,15 @@
+{
+ "compilerOptions": {
+ "lib": ["ES2021"],
+ "module": "ES2020",
+ "moduleResolution": "node",
+ "target": "ES2021",
+ "outDir": "dist",
+ "sourceMap": true,
+ "rootDir": "../../",
+ "typeRoots": ["node_modules/@types"],
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true
+ },
+ "include": ["../../packages/shared/**/*.ts", "src"]
+}
diff --git a/examples/with-firebase/apps/web/.gitignore b/examples/with-firebase/apps/web/.gitignore
new file mode 100644
index 0000000000000..a547bf36d8d11
--- /dev/null
+++ b/examples/with-firebase/apps/web/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/examples/with-firebase/apps/web/index.html b/examples/with-firebase/apps/web/index.html
new file mode 100644
index 0000000000000..0710cc2399bf6
--- /dev/null
+++ b/examples/with-firebase/apps/web/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+ Firebase + Turborepo
+
+
+
+
+
+
diff --git a/examples/with-firebase/apps/web/package.json b/examples/with-firebase/apps/web/package.json
new file mode 100644
index 0000000000000..8a9d73d447c72
--- /dev/null
+++ b/examples/with-firebase/apps/web/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "web",
+ "private": true,
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview",
+ "deploy": "firebase deploy --only hosting"
+ },
+ "dependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0",
+ "shared": "*"
+ },
+ "devDependencies": {
+ "@types/react": "^18.0.0",
+ "@types/react-dom": "^18.0.0",
+ "@vitejs/plugin-react": "^1.3.0",
+ "typescript": "^4.6.3",
+ "vite": "^2.9.7"
+ }
+}
diff --git a/examples/with-firebase/apps/web/src/App.css b/examples/with-firebase/apps/web/src/App.css
new file mode 100644
index 0000000000000..2ae6bc987166b
--- /dev/null
+++ b/examples/with-firebase/apps/web/src/App.css
@@ -0,0 +1,11 @@
+.App {
+ background-color: #282c34;
+ min-height: 100vh;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ font-size: calc(10px + 2vmin);
+ color: white;
+ padding: 80px;
+}
diff --git a/examples/with-firebase/apps/web/src/App.tsx b/examples/with-firebase/apps/web/src/App.tsx
new file mode 100644
index 0000000000000..abe94ad783b03
--- /dev/null
+++ b/examples/with-firebase/apps/web/src/App.tsx
@@ -0,0 +1,22 @@
+import { useEffect, useState } from "react";
+import { exampleConfigFromShared } from "shared/util";
+
+import "./App.css";
+
+function App() {
+ const [data, setData] = useState({});
+ useEffect(() => {
+ fetch("/api/test")
+ .then((res) => res.json())
+ .then((res) => setData(res));
+ }, []);
+
+ return (
+
+
API: {JSON.stringify(data)}
+
Shared: {JSON.stringify(exampleConfigFromShared)}
+
+ );
+}
+
+export default App;
diff --git a/examples/with-firebase/apps/web/src/favicon.svg b/examples/with-firebase/apps/web/src/favicon.svg
new file mode 100644
index 0000000000000..de4aeddc12bdf
--- /dev/null
+++ b/examples/with-firebase/apps/web/src/favicon.svg
@@ -0,0 +1,15 @@
+
diff --git a/examples/with-firebase/apps/web/src/index.css b/examples/with-firebase/apps/web/src/index.css
new file mode 100644
index 0000000000000..e8c77d2921d3f
--- /dev/null
+++ b/examples/with-firebase/apps/web/src/index.css
@@ -0,0 +1,14 @@
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ background-color: #282c34;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
+}
diff --git a/examples/with-firebase/apps/web/src/logo.svg b/examples/with-firebase/apps/web/src/logo.svg
new file mode 100644
index 0000000000000..6b60c1042f58d
--- /dev/null
+++ b/examples/with-firebase/apps/web/src/logo.svg
@@ -0,0 +1,7 @@
+
diff --git a/examples/with-firebase/apps/web/src/main.tsx b/examples/with-firebase/apps/web/src/main.tsx
new file mode 100644
index 0000000000000..9b67590a06915
--- /dev/null
+++ b/examples/with-firebase/apps/web/src/main.tsx
@@ -0,0 +1,10 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+import App from "./App";
+import "./index.css";
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+
+
+
+);
diff --git a/examples/with-firebase/apps/web/src/vite-env.d.ts b/examples/with-firebase/apps/web/src/vite-env.d.ts
new file mode 100644
index 0000000000000..11f02fe2a0061
--- /dev/null
+++ b/examples/with-firebase/apps/web/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/examples/with-firebase/apps/web/tsconfig.json b/examples/with-firebase/apps/web/tsconfig.json
new file mode 100644
index 0000000000000..3d0a51a86e202
--- /dev/null
+++ b/examples/with-firebase/apps/web/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
+ "allowJs": false,
+ "skipLibCheck": true,
+ "esModuleInterop": false,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx"
+ },
+ "include": ["src"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/examples/with-firebase/apps/web/tsconfig.node.json b/examples/with-firebase/apps/web/tsconfig.node.json
new file mode 100644
index 0000000000000..e993792cb12c9
--- /dev/null
+++ b/examples/with-firebase/apps/web/tsconfig.node.json
@@ -0,0 +1,8 @@
+{
+ "compilerOptions": {
+ "composite": true,
+ "module": "esnext",
+ "moduleResolution": "node"
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/examples/with-firebase/apps/web/vite.config.ts b/examples/with-firebase/apps/web/vite.config.ts
new file mode 100644
index 0000000000000..5e8d581e89ac7
--- /dev/null
+++ b/examples/with-firebase/apps/web/vite.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [react()],
+ server: {
+ proxy: {
+ "/api": {
+ target: "http://localhost:5000",
+ changeOrigin: true,
+ },
+ },
+ },
+});
diff --git a/examples/with-firebase/firebase.json b/examples/with-firebase/firebase.json
new file mode 100644
index 0000000000000..5c603e2f5e5d0
--- /dev/null
+++ b/examples/with-firebase/firebase.json
@@ -0,0 +1,31 @@
+{
+ "functions": {
+ "source": "apps/api"
+ },
+ "hosting": {
+ "public": "apps/web/dist",
+ "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
+ "rewrites": [
+ {
+ "source": "/api/**",
+ "function": "server"
+ },
+ {
+ "source": "**",
+ "destination": "/index.html"
+ }
+ ]
+ },
+ "emulators": {
+ "ui": {
+ "enabled": true
+ },
+ "functions": {
+ "port": 5001
+ },
+ "hosting": {
+ "enabled": true,
+ "port": 5000
+ }
+ }
+}
diff --git a/examples/with-firebase/package.json b/examples/with-firebase/package.json
new file mode 100644
index 0000000000000..5a80eed40a4ea
--- /dev/null
+++ b/examples/with-firebase/package.json
@@ -0,0 +1,29 @@
+{
+ "name": "turborepo-firebase",
+ "version": "0.0.0",
+ "private": true,
+ "workspaces": [
+ "apps/*",
+ "packages/*"
+ ],
+ "scripts": {
+ "start": "concurrently npm:dev npm:emulators",
+ "dev": "turbo run dev --parallel",
+ "build": "turbo run build",
+ "emulators": "firebase emulators:start",
+ "deploy": "turbo run build --parallel && turbo run deploy --filter=web --filter=api",
+ "lint": "turbo run lint",
+ "format": "prettier --write \"**/*.{ts,tsx,md}\""
+ },
+ "devDependencies": {
+ "concurrently": "^7.1.0",
+ "firebase-tools": "^11.9.0",
+ "prettier": "latest",
+ "turbo": "latest"
+ },
+ "engines": {
+ "npm": ">=7.0.0",
+ "node": ">=14.0.0"
+ },
+ "packageManager": "npm@7.24.0"
+}
diff --git a/examples/with-firebase/packages/config/eslint-preset.js b/examples/with-firebase/packages/config/eslint-preset.js
new file mode 100644
index 0000000000000..cedc38df2ccfc
--- /dev/null
+++ b/examples/with-firebase/packages/config/eslint-preset.js
@@ -0,0 +1,12 @@
+module.exports = {
+ extends: ["next", "prettier"],
+ settings: {
+ next: {
+ rootDir: ["apps/*/", "packages/*/"],
+ },
+ },
+ rules: {
+ "@next/next/no-html-link-for-pages": "off",
+ "react/jsx-key": "off",
+ },
+};
diff --git a/examples/with-firebase/packages/config/package.json b/examples/with-firebase/packages/config/package.json
new file mode 100644
index 0000000000000..cdcaeea47ae35
--- /dev/null
+++ b/examples/with-firebase/packages/config/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "config",
+ "version": "0.0.0",
+ "main": "index.js",
+ "license": "MIT",
+ "files": [
+ "eslint-preset.js"
+ ],
+ "dependencies": {
+ "eslint-config-next": "^12.0.8",
+ "eslint-config-prettier": "^8.3.0",
+ "eslint-plugin-react": "7.28.0"
+ }
+}
diff --git a/examples/with-firebase/packages/shared/package.json b/examples/with-firebase/packages/shared/package.json
new file mode 100644
index 0000000000000..f16d73c13b7a9
--- /dev/null
+++ b/examples/with-firebase/packages/shared/package.json
@@ -0,0 +1,8 @@
+{
+ "name": "shared",
+ "version": "0.0.0",
+ "private": true,
+ "files": [
+ "*"
+ ]
+}
\ No newline at end of file
diff --git a/examples/with-firebase/packages/shared/util.ts b/examples/with-firebase/packages/shared/util.ts
new file mode 100644
index 0000000000000..734462ade2409
--- /dev/null
+++ b/examples/with-firebase/packages/shared/util.ts
@@ -0,0 +1,3 @@
+export const exampleConfigFromShared = {
+ turbo: "blazingly fastâ„¢"
+};
diff --git a/examples/with-firebase/packages/tsconfig/README.md b/examples/with-firebase/packages/tsconfig/README.md
new file mode 100644
index 0000000000000..0da79cf231837
--- /dev/null
+++ b/examples/with-firebase/packages/tsconfig/README.md
@@ -0,0 +1,3 @@
+# `tsconfig`
+
+These are base shared `tsconfig.json`s from which all other `tsconfig.json`'s inherit from.
diff --git a/examples/with-firebase/packages/tsconfig/base.json b/examples/with-firebase/packages/tsconfig/base.json
new file mode 100644
index 0000000000000..d72a9f3a27835
--- /dev/null
+++ b/examples/with-firebase/packages/tsconfig/base.json
@@ -0,0 +1,20 @@
+{
+ "$schema": "https://json.schemastore.org/tsconfig",
+ "display": "Default",
+ "compilerOptions": {
+ "composite": false,
+ "declaration": true,
+ "declarationMap": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
+ "inlineSources": false,
+ "isolatedModules": true,
+ "moduleResolution": "node",
+ "noUnusedLocals": false,
+ "noUnusedParameters": false,
+ "preserveWatchOutput": true,
+ "skipLibCheck": true,
+ "strict": true
+ },
+ "exclude": ["node_modules"]
+}
diff --git a/examples/with-firebase/packages/tsconfig/package.json b/examples/with-firebase/packages/tsconfig/package.json
new file mode 100644
index 0000000000000..d49a4c6ee807e
--- /dev/null
+++ b/examples/with-firebase/packages/tsconfig/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "tsconfig",
+ "version": "0.0.0",
+ "private": true,
+ "main": "index.js",
+ "files": [
+ "base.json",
+ "nextjs.json",
+ "react-library.json"
+ ]
+}
diff --git a/examples/with-firebase/turbo.json b/examples/with-firebase/turbo.json
new file mode 100644
index 0000000000000..3782e77314aec
--- /dev/null
+++ b/examples/with-firebase/turbo.json
@@ -0,0 +1,18 @@
+{
+ "pipeline": {
+ "build": {
+ "dependsOn": ["^build"],
+ "outputs": ["dist/**"]
+ },
+ "deploy": {
+ "dependsOn": ["^build"],
+ "outputs": []
+ },
+ "lint": {
+ "outputs": []
+ },
+ "dev": {
+ "cache": false
+ }
+ }
+}