Vibe coding with AI course · Module 13: Twitch Clone
Docker & Containers
In this lesson2
Containerizing a Next.js app.
Dockerfile
FROM node:24-alpine AS base
FROM base AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM base AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY /app/.next/standalone ./
COPY /app/.next/static ./.next/static
COPY /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]Docker Compose
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://...See you soon!
Code for this lesson: App.tsx
'use client';
interface StreamCardProps {
title: string;
category: string;
viewerCount: number;
channelName: string;
thumbnail: string;
}
const mockStreams: StreamCardProps[] = [
{
title: 'Coding a Pirate Ship from Scratch!',
category: 'Software & Game Development',
viewerCount: 1247,
channelName: 'Captain Redbeard',
thumbnail: 'https://images.unsplash.com/photo-1544551763-46a013bb70d5?w=400&h=225&fit=crop'
},
{
title: 'JavaScript Tutorial - Building React Apps',
category: 'Software & Game Development',
viewerCount: 892,
channelName: 'Sailor Sam',
thumbnail: 'https://images.unsplash.com/photo-1517694712202-14dd9538aa97?w=400&h=225&fit=crop'
},
{
title: 'TypeScript Advanced Patterns',
category: 'Science & Technology',
viewerCount: 567,
channelName: 'Navigator Nancy',
thumbnail: 'https://images.unsplash.com/photo-1555066931-4365d14bab8c?w=400&h=225&fit=crop'
}
];
function StreamCard({ stream }: { stream: StreamCardProps }) {
return (
<div className="bg-gray-900 rounded overflow-hidden hover:scale-105 transition cursor-pointer">
<div className="relative">
<img
src={stream.thumbnail}
alt={stream.title}
className="w-full aspect-video object-cover"
/>
<div className="absolute top-2 left-2 px-2 py-1 bg-red-600 text-white text-xs font-bold rounded">
LIVE
</div>
<div className="absolute bottom-2 left-2 px-2 py-1 bg-black/70 text-white text-xs rounded">
{stream.viewerCount.toLocaleString()} viewers
</div>
</div>
<div className="p-3">
<h3 className="font-semibold mb-1 line-clamp-2">{stream.title}</h3>
<p className="text-sm text-gray-400 mb-1">{stream.channelName}</p>
<p className="text-xs text-gray-500">{stream.category}</p>
</div>
</div>
);
}
export default function StreamGrid() {
return (
<div className="min-h-screen bg-gray-950 text-white p-8">
<h1 className="text-3xl font-bold mb-6">Live Channels</h1>
<div className="grid grid-cols-3 gap-4">
{mockStreams.map((stream, i) => (
<StreamCard key={i} stream={stream} />
))}
</div>
</div>
);
}Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. Why do we containerize a Next.js app with Docker?
2. Which base image does the Dockerfile from the lesson use?
Hands-on tasks in the game
- Vertical ordering
Order the Dockerfile stages from the top of the file:
- Horizontal ordering
Arrange the port mapping in docker-compose (one line): "3000:3000"