Skip to main content
This guide covers everything you need to install and configure the WhatsApp Chat application, from initial setup to understanding the complete dependency tree.

System requirements

Before installing, verify your system meets these requirements:
  • Node.js 20.0.0 or higher
  • npm 10+ / yarn 1.22+ / pnpm 8+
  • Operating system: macOS, Windows, or Linux
  • Memory: 4GB RAM minimum (8GB recommended)
  • Disk space: 500MB for dependencies

Quick installation

Get started in three commands:
1

Clone or create project

If starting fresh, create a new directory:
mkdir whatsapp-chat
cd whatsapp-chat
2

Install dependencies

Choose your package manager:
npm install
This installs all packages defined in package.json.
3

Start development server

Launch the app with hot reload:
npm run dev
The server starts on http://localhost:3000

Package overview

The application uses these core dependencies:

Framework & runtime

package.json
{
  "dependencies": {
    "next": "15.5.4",
    "react": "19.1.0",
    "react-dom": "19.1.0"
  }
}
  • Next.js 15 – React framework with App Router, Server Components, and Turbopack
  • React 19 – Latest React with improved hooks and concurrent features
  • React DOM 19 – React renderer for web browsers

State management

package.json
{
  "dependencies": {
    "zustand": "^5.0.8"
  }
}
  • Zustand – Lightweight state management with localStorage persistence
Used for managing chats, messages, contacts, drafts, and typing indicators:
import { create } from 'zustand'
import { persist, createJSONStorage } from 'zustand/middleware'

const useChatStore = create<ChatStore>()(persist(
  (set, get) => ({
    chats: {},
    messages: {},
    contacts: {},
    sendMessage: (chatId, payload) => { /* ... */ },
  }),
  { 
    name: 'chat-store',
    storage: createJSONStorage(() => localStorage)
  }
))

UI components

package.json
{
  "dependencies": {
    "@radix-ui/react-avatar": "^1.1.10",
    "@radix-ui/react-dialog": "^1.1.15",
    "@radix-ui/react-dropdown-menu": "^2.1.16",
    "@radix-ui/react-popover": "^1.1.15",
    "@radix-ui/react-scroll-area": "^1.2.10",
    "@radix-ui/react-separator": "^1.1.7",
    "@radix-ui/react-slot": "^1.2.3",
    "@radix-ui/react-tooltip": "^1.2.8"
  }
}
  • Radix UI – Unstyled, accessible component primitives
  • All components follow WAI-ARIA patterns for keyboard navigation and screen readers

Icons & media

package.json
{
  "dependencies": {
    "@phosphor-icons/react": "^2.1.10",
    "@emoji-mart/react": "^1.1.1",
    "@emoji-mart/data": "^1.2.1",
    "lucide-react": "^0.544.0"
  }
}
  • Phosphor Icons – Primary icon set with 6,000+ icons
  • Emoji Mart – Emoji picker with search and categories
  • Lucide React – Additional icon alternatives
Example usage:
import { PaperPlaneTilt, Paperclip, Smiley } from '@phosphor-icons/react'

<Button>
  <PaperPlaneTilt className="h-5 w-5" weight="fill" />
  Send
</Button>

File handling

package.json
{
  "dependencies": {
    "react-dropzone": "^14.3.8"
  }
}
  • react-dropzone – Drag-and-drop file uploads with validation
Implemented in the message composer:
import { useDropzone } from 'react-dropzone'

const { getRootProps, getInputProps, isDragActive } = useDropzone({
  onDrop: (files) => {
    const media = files.map(file => ({
      id: `upload-${file.name}`,
      type: 'image',
      url: URL.createObjectURL(file),
      sizeInBytes: file.size
    }))
    setAttachments(prev => [...prev, ...media])
  },
  accept: { 'image/*': [] },
  multiple: true
})

Date & time formatting

package.json
{
  "dependencies": {
    "date-fns": "^4.1.0"
  }
}
  • date-fns – Modern date utility library
Used for message timestamps and activity formatting:
import { format, formatDistanceToNow, isToday } from 'date-fns'

const timeLabel = format(new Date(message.createdAt), 'HH:mm')
const lastSeen = formatDistanceToNow(new Date(contact.lastSeenAt), { 
  addSuffix: true 
})

Styling

package.json
{
  "dependencies": {
    "tailwindcss": "^4",
    "class-variance-authority": "^0.7.1",
    "tailwind-merge": "^3.3.1",
    "clsx": "^2.1.1"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4",
    "tw-animate-css": "^1.4.0"
  }
}
  • Tailwind CSS v4 – Utility-first CSS framework with custom theming
  • CVA – Component variant utilities
  • tailwind-merge – Merge Tailwind classes without conflicts
  • clsx – Conditional className builder
The app uses custom color tokens for WhatsApp-like theming:
app/globals.css
:root {
  --bubble-outgoing: oklch(0.92 0.04 145);
  --bubble-incoming: oklch(0.995 0.015 95);
  --status-sent: oklch(0.65 0.02 140);
  --status-delivered: oklch(0.55 0.18 145);
  --status-read: oklch(0.6 0.2 210);
  --sidebar: oklch(0.992 0.004 140);
}

Form handling

package.json
{
  "dependencies": {
    "react-hook-form": "^7.63.0",
    "@hookform/resolvers": "^5.2.2",
    "zod": "^4.1.11"
  }
}
  • React Hook Form – Performant form state management
  • Zod – TypeScript-first schema validation

Additional UI utilities

package.json
{
  "dependencies": {
    "react-virtuoso": "^4.14.1",
    "react-resizable-panels": "^3.0.6",
    "sonner": "^2.0.7",
    "vaul": "^1.1.2"
  }
}
  • react-virtuoso – Virtual scrolling for large message lists
  • react-resizable-panels – Resizable split layouts
  • sonner – Toast notifications
  • vaul – Drawer/bottom sheet component

Configuration files

TypeScript configuration

The project uses strict TypeScript with path aliases:
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}
Path aliases allow clean imports:
import { useChatStore } from '@/lib/chat/state'
import { ChatApp } from '@/components/chat/chat-app'
import { Button } from '@/components/ui/button'

Next.js configuration

next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  // Configuration options
};

export default nextConfig;

Component library setup

The project uses shadcn/ui component patterns:
components.json
{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "default",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "app/globals.css",
    "baseColor": "slate",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils"
  }
}

Build commands

Available npm scripts:

Development

npm run dev
Starts the Next.js development server with Turbopack for fast refresh. Hot Module Replacement (HMR) automatically updates the browser when you edit files.

Production build

npm run build
Creates an optimized production build with:
  • Static page generation for better performance
  • Tree shaking to remove unused code
  • Code splitting for smaller bundle sizes
  • Image optimization

Production server

npm run start
Serves the production build. Run npm run build first.

Linting

npm run lint
Runs ESLint to check code quality and catch errors.

Troubleshooting

Port already in use

If port 3000 is occupied, specify a different port:
PORT=3001 npm run dev

Clear node_modules

If you encounter dependency issues:
rm -rf node_modules package-lock.json
npm install

TypeScript errors

Regenerate TypeScript definitions:
npm run dev
# Wait for the server to start, then stop it
# Next.js will regenerate .next/types

Build errors

Check Node.js version:
node --version
# Should be v20.0.0 or higher

Next steps

Quickstart

Build your first chat feature in 5 minutes

Project structure

Explore the codebase organization and architecture

Components

Learn about the UI component library

State management

Deep dive into Zustand store patterns
Development tip: Use pnpm for faster installs and better disk space efficiency compared to npm or yarn.

Build docs developers (and LLMs) love