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

AppTechnologyPurpose
apps/webNext.js 16Web application — SSR, caching, Server Components
apps/apiHono + PrismaAPI server — tRPC procedures, database access
apps/mobileExpo + NativeWindMobile application — iOS and Android

Packages

PackagePurpose
@chirp/trpctRPC router and procedures — shared type-safe API layer
@chirp/authBetter Auth configuration — shared auth logic
@chirp/emailReact 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

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.