DEV Community

Cover image for Why I Built 5 Docker Projects After My First Client Deployment Failed
Arbythecoder
Arbythecoder

Posted on • Edited on

1 1 1 1

Why I Built 5 Docker Projects After My First Client Deployment Failed

How turning a 3-day deployment disaster into 5 personal projects saved my freelance career


The Disaster That Changed Everything

Imagine you've just landed your first major client. The app works perfectly on your machine. You're confident, maybe even a little cocky. You type git push origin main and wait for the magic to happen.

Three days later, you're still debugging why your Node.js app refuses to run on the client's server.

That was me six months ago. And it was humiliating.

What Actually Happened

My "deployment process" looked like this:

# My brilliant deployment strategy
git push origin main
# ✨ Magic happens ✨
# Client gets working application
Enter fullscreen mode Exit fullscreen mode

Reality: My app worked on my MacBook but crashed on the client's Ubuntu server. Different Node versions, missing dependencies, wrong file paths—everything that could go wrong, did.

The client was patient (thankfully), but I knew I couldn't survive another deployment like this.

The Learning Path: 5 Projects That Fixed Everything

Instead of diving into boring Docker tutorials, I built 5 real projects. Each one taught me something crucial about containers and deployment.

Project 1: Simple Todo App

The Goal: Just get something running in a container.

FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

What I Learned:

  • Containers are like shipping boxes—everything your app needs goes inside
  • FROM = your starting point
  • WORKDIR = where your app lives
  • COPY = move files into the container

The Win: My todo app ran the same way on my laptop and my client's server. First time ever.

Project 2: Blog API with Database

The Goal: Connect containers together.

# docker-compose.yml
version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DB_URL=mongodb://mongo:27017/blog
  mongo:
    image: mongo:4.4
    ports:
      - "27017:27017"
Enter fullscreen mode Exit fullscreen mode

What I Learned:

  • Docker Compose = multiple containers working together
  • Services can talk to each other by name (like mongo:27017)
  • Environment variables make your app flexible

The Win: No more "database connection failed" errors. The database was part of the deployment.

Project 3: File Upload Service

The Goal: Handle files that need to persist.

FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
VOLUME ["/app/uploads"]
EXPOSE 3000
CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

What I Learned:

  • Containers are temporary—files disappear when they restart
  • Volumes = permanent storage
  • User uploads need special handling

The Win: Files uploaded by users didn't vanish when I restarted the app.

Project 4: Real-time Chat App

The Goal: Handle external services like Redis.

version: '3.8'
services:
  app:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - redis
  redis:
    image: redis:alpine
    ports:
      - "6379:6379"
Enter fullscreen mode Exit fullscreen mode

What I Learned:

  • depends_on = start services in the right order
  • Redis, databases, and other services are just more containers
  • Networking between containers is automatic

The Win: My chat app's real-time features worked perfectly on any server.

Project 5: Full E-commerce Platform

The Goal: Put it all together—frontend, backend, database.

version: '3.8'
services:
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
  backend:
    build: ./backend
    ports:
      - "5000:5000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/ecommerce
  db:
    image: postgres:13
    environment:
      - POSTGRES_DB=ecommerce
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
Enter fullscreen mode Exit fullscreen mode

What I Learned:

  • Complex apps are just multiple simple containers
  • Environment variables control everything
  • Docker Compose makes orchestration easy

The Win: I could deploy a full e-commerce site with one command: docker-compose up -d

The Transformation

Before Docker:

  • ❌ Deployment success rate: ~30%
  • ❌ Time to deploy: 2-3 days of debugging
  • ❌ Client confidence: "When will it actually work?"
  • ❌ Server debugging: My weekends were ruined

After Docker:

  • ✅ Deployment success rate: 95%+
  • ✅ Time to deploy: 20 minutes
  • ✅ Client confidence: "This developer knows what they're doing"
  • ✅ Server debugging: Almost never

The Code That Changed My Career

# This one command replaced 3 days of pain
docker-compose up -d

# ✅ Application running
# ✅ Database connected  
# ✅ Files persistent
# ✅ Client happy
Enter fullscreen mode Exit fullscreen mode

Working From Lagos: Why Docker Mattered More

As a Nigerian developer competing globally, Docker solved unique challenges:

  • Inconsistent hosting environments: My container ran the same on Heroku, DigitalOcean, or any VPS
  • Limited debugging access: No more SSH-ing into servers to fix things
  • Remote client demos: "Here's the live link" instead of "Let me screen share"
  • Professional credibility: Clients trusted my technical expertise

The Docker Pattern That Actually Works

Stop writing basic Dockerfiles. This multi-stage build pattern optimizes for production:

# Build stage
FROM node:16-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

# Production stage  
FROM node:16-alpine AS production
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
USER node
CMD ["npm", "start"]
Enter fullscreen mode Exit fullscreen mode

Why this matters:

  • Smaller image size = faster deployments
  • Security: Don't run as root
  • Efficiency: Only production dependencies

What I Wish Someone Had Told Me

  1. Environment variables are everything: Don't hardcode database URLs or API keys
  2. Health checks save you: Docker can restart failed containers automatically
  3. Alpine images are your friend: Smaller, faster, more secure
  4. Test locally first: docker run -p 3000:3000 your-app before deploying

The Professional Impact

Before: "Let me bring my laptop to demo the app"
After: "Here's the live application link"

That shift in presentation changed how clients perceived my expertise. I went from "junior developer with deployment issues" to "professional who delivers working solutions."

Your Next Steps (Start Today)

  1. Pick your simplest app (even a "Hello World" Express server)
  2. Write a basic Dockerfile (use my Todo app example)
  3. Test locally: docker build -t my-app . && docker run -p 3000:3000 my-app
  4. Deploy somewhere: DigitalOcean, Railway, or Render
  5. Celebrate: You just containerized your first application

Let's Connect

What's your worst deployment story? Which Docker concept confused you the most?

Drop your experiences in the comments—let's learn together and help other developers avoid the 3-day debugging nightmare I went through.


Building these 5 projects took me 2 weeks. It's been 6 months since my last deployment disaster. Docker didn't just fix my technical problems—it fixed my confidence as a developer.

A developer toolkit for building lightning-fast dashboards into SaaS apps

A developer toolkit for building lightning-fast dashboards into SaaS apps

Embed in minutes, load in milliseconds, extend infinitely. Import any chart, connect to any database, embed anywhere. Scale elegantly, monitor effortlessly, CI/CD & version control.

Get early access

Top comments (0)

Feature flag article image

Create a feature flag in your IDE in 5 minutes with LaunchDarkly’s MCP server 🏁

How to create, evaluate, and modify flags from within your IDE or AI client using natural language with LaunchDarkly's new MCP server. Follow along with this tutorial for step by step instructions.

Read full post

👋 Kindness is contagious

Dive into this insightful article, celebrated by the caring DEV Community. Programmers from all walks of life are invited to share and expand our collective wisdom.

A simple thank-you can make someone’s day—drop your kudos in the comments!

On DEV, spreading knowledge paves the way and strengthens our community ties. If this piece helped you, a brief note of appreciation to the author truly counts.

Let’s Go!