Chirp
Chirp is a Twitter clone built as a full-stack application with a web app, an API, and a mobile app — all living in a single monorepo. This is the capstone exercise for the Node + React track.
Requirements
Check the project requirements and their estimates: Requirements spreadsheet
UI
Check the UI designs on Figma: Figma
Core Features
At a high level, Chirp includes:
- Authentication — sign up, log in, social sign-on.
- Tweets — create, read, and delete tweets.
- Timeline — a paginated feed of tweets from users you follow.
- User profiles — view any user's profile and their tweets.
- Follow / Unfollow — follow and unfollow other users.
- Likes — like and unlike tweets.
- Search — search for users and tweets.
- Notifications & Emails — in-app notifications and transactional emails.
Apps
| App | Technology | Purpose |
|---|---|---|
apps/web | Next.js 16 | Web application — SSR, caching, Server Components |
apps/api | Hono + Prisma | API server — tRPC procedures, database access |
apps/mobile | Expo + NativeWind | Mobile application — iOS and Android |
Packages
| Package | Purpose |
|---|---|
@chirp/trpc | tRPC router and procedures — shared type-safe API layer |
@chirp/auth | Better Auth configuration — shared auth logic |
@chirp/email | React Email templates + Resend sending |
Additional packages (e.g., @chirp/db, @chirp/config) are your decision. Extract shared concerns as you see fit.
Methodology
Create an account on Linear or any other ticket management tool, and add all the user stories to a board. We will use this to keep track of the progress and communicate any possible question to the client. In this exercise the client is eagerworks.
In the board we will have 5 columns:
- Backlog — all the platform user stories.
- Current Sprint — user stories selected for this sprint iteration.
- In Progress — the user story you are currently developing.
- To Check — user stories ready to be tested by the client.
- Done — user stories validated by the client.
Every time you start developing a new user story, move it to In Progress. When it is ready for review, move it to To Check. If the client validates it, they move it to Done.
Monorepo
A monorepo is a single repository that contains multiple projects (apps, packages, libraries) that can depend on each other. Instead of scattering code across many repositories and publishing packages to a registry, everything lives together and shares tooling, configuration, and types.
Why it matters:
- Shared code — extract common logic into packages that multiple apps import directly, with no publish step.
- Atomic changes — a single PR can update the API, the web app, and the mobile app together.
- Consistent tooling — one ESLint config, one TypeScript config, one CI pipeline.
Turborepo
Turborepo is a build system for JavaScript and TypeScript monorepos. It orchestrates tasks (build, lint, test) across all packages, understands the dependency graph between them, and caches results so unchanged packages are never rebuilt.
Key concepts:
turbo.json— defines your task pipeline: which tasks exist, what they depend on, and what outputs to cache.- Task dependencies —
"dependsOn": ["^build"]means "build my dependencies before building me". The^prefix means "dependencies in other packages". - Caching — Turborepo hashes your source files and configuration. If nothing changed, it replays the cached output instead of re-running the task.
- Filtering — run tasks for a specific package with
turbo run build --filter=@chirp/web.
Bun Workspaces
Bun supports workspaces natively. You declare them in the root package.json:
{
"name": "chirp",
"workspaces": ["apps/*", "packages/*"]
}
Then packages can reference each other using the workspace:* protocol:
{
"name": "@chirp/web",
"dependencies": {
"@chirp/trpc": "workspace:*",
"@chirp/auth": "workspace:*"
}
}
When you run bun install at the root, Bun links workspace packages together so imports resolve instantly — no publishing or version bumping needed.
Resources
- Turborepo — Documentation
- Turborepo — Structuring a repository
- Turborepo — Configuring tasks
- Bun — Workspaces
Getting Started
1. Create the monorepo
bunx create-turbo@latest chirp
This gives you a working monorepo with apps/ and packages/ directories, a root turbo.json, and workspace configuration already set up.
2. Clean up the boilerplate
The scaffolded project comes with example apps and packages. Remove them — delete everything inside apps/ and packages/ so you start with empty directories. You will add each app and package yourself in the sections that follow.
3. Configure turbo.json
Define your task pipeline so turbo run dev starts all apps, turbo run build builds them in the correct order, and turbo run lint checks everything:
{
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"dev": {
"persistent": true,
"cache": false
},
"lint": {
"dependsOn": ["^build"]
}
}
}
Project structure
Once you complete all the sections, the monorepo will look like this:
chirp/
├── apps/
│ ├── web/ # Next.js
│ ├── api/ # Hono
│ └── mobile/ # Expo
├── packages/
│ ├── trpc/ # tRPC router + procedures
│ ├── auth/ # Better Auth configuration
│ ├── email/ # Email templates + sending
│ └── ... # Other shared packages
├── turbo.json
├── package.json
└── bun.lock
Now continue to the Next.js section to set up the web and API apps.