Building Apps with Claude Code
End-to-end walkthrough: build a task manager app from a blank folder to a working app with an API, a React UI, and a passing test — using nothing but Claude Code prompts.
What we're building
A simple task manager: add tasks, check them off, delete them. Small enough to finish in one session, real enough to cover the full build flow.
| Layer | Choice |
|---|---|
| Framework | Next.js 15 App Router + TypeScript |
| Styling | Tailwind CSS |
| Data | In-memory store — no database setup |
| Tests | Vitest — one test for the API route |
My Tasks
3 of 5 complete
- ✓Set up project structure
- ✓Create API routes
- ✓Build task list UI
- Add delete functionality
- Write tests
The approach
We follow the habits from the previous lesson: one feature at a time, specific prompts, @-mention files, verify before continuing.
- Scaffold the project
- Write CLAUDE.md
- Build the API
- Build the UI
- Add delete functionality
- Write a test
Build steps
Scaffold the project
Create the project folder and let Claude set up the Next.js scaffold.
Scaffold a new Next.js 15 app with TypeScript and Tailwind. Use the App Router. Call it my-tasks. Do not add any example content — just the clean starter files.
I'll scaffold a clean Next.js 15 app with TypeScript and Tailwind using the App Router. Running npx create-next-app@latest with those options now.
npm run dev and open localhost:3000. You should see a blank page before continuing.Write CLAUDE.md
Before writing feature code, give Claude the project conventions once. Every future prompt in this project inherits them automatically.
Create a CLAUDE.md at the project root. Document: stack is Next.js 15 App Router + TypeScript + Tailwind. API routes go in src/app/api/. Components go in src/components/. Use 'use client' only when needed. No console.log in production code. Tests use Vitest, colocated in src/__tests__/.
I'll create CLAUDE.md at the root with those conventions now.
Build the API route
One API route handles all task operations. We use an in-memory array to keep things simple.
Create src/app/api/tasks/route.ts. It should export GET (return all tasks), POST (add a task with id and text), PATCH (toggle done by id), and DELETE (remove by id). Use an in-memory array. Each task has: id (number), text (string), done (boolean).
I'll create the API route at src/app/api/tasks/route.ts with GET, POST, PATCH, and DELETE handlers using an in-memory array.
localhost:3000/api/tasks in your browser. You should see [].Build the task UI
Two components: a form to add tasks and a list to display them.
Create src/components/TaskList.tsx — a 'use client' component. It fetches tasks from /api/tasks on load and re-fetches after any change. Each task shows a checkbox (toggles done via PATCH), the task text (strikethrough when done), and a delete button (DELETE). Style with Tailwind — clean, minimal.
I'll create TaskList.tsx as a client component with fetch calls for GET, PATCH, and DELETE.
Create src/components/AddTaskForm.tsx — a 'use client' component with a text input and an Add button. On submit, POST to /api/tasks with the input value, clear the field, then call an onTaskAdded() prop so TaskList can re-fetch.
I'll create AddTaskForm.tsx with a controlled input, POST on submit, and an onTaskAdded callback prop.
Update @src/app/page.tsx to render AddTaskForm and TaskList together. Centre them on the page with a heading 'My Tasks'.
I'll update page.tsx to import and render both components with a centred layout and the heading.
localhost:3000, add a task, check it off. Both actions should update the list instantly.Write a test
Ask Claude to write a test for the API route and verify it passes before finishing.
Write a Vitest test in src/__tests__/tasks.test.ts for the /api/tasks route. Test that POST creates a task and that GET returns it. Install Vitest if not already in package.json.
I'll create the test file and add Vitest to devDependencies. The tests will call the route handlers directly without a running server.
Where everything lives
Quick reference
| Practice | What we did |
|---|---|
| One feature per prompt | Each prompt asked for exactly one thing |
| @filename for precise edits | Updating page.tsx used @src/app/page.tsx |
| Verify after each step | Checked localhost before moving on |
| CLAUDE.md once | Stack and conventions stated once, inherited by every prompt |
Before you continue
- Scaffold first, then write CLAUDE.md before any feature code.
- One feature per prompt — API, then UI components, then page wiring, then tests.
- Verify at localhost after each step so bugs do not compound.
- Six prompts, five features, one working app with a passing test — that is the build loop.
- Next: use Claude as your code reviewer.
What's Next
You've built a real app end-to-end with Claude Code. The next lesson shows how to use Claude as your code reviewer — catching issues before they ship.