- Knowledge
- technology
- OOP
- Tips
- Programming
- Tips
- Tutorial
- SEO
- Ranking
- Knowledge
- Special Day
- Seo
- Bug
- Data science
- Seo
- artificial intelligence
- Machine Learning
- Robotics
- happyNewYear2021
- newYearEve
- 2021
- Automation
- Smart Home
- Career
- Best Practices
- Git
- Logging
- Web Fundamentals
- DNS
- HTTPS
- Performance
- AI Tools
- ChatGPT
- Claude
- Gemini
- Laravel
- Eloquent
- MySQL
- HTTPS
- TLS
- Web Security
- Certificates
- Developer Life
- Debugging
- Docker
- DevOps
- Transactions
- Queues
- LLMs
- AI
- AI Coding
- Developer Tools
- React Native
- Expo
- Kate PMS
- Mobile Apps
- Laravel
- Authentication
- Sanctum
- Cookies
- API Design
- Payments
- Idempotency
- DeepSeek
- Open Source AI
- LLMs
- AI News
- Git
- Version Control
- AI Coding
- Prompting
- PHP
- Checklist
- MCP
- AI Agents
- OpenAI
- Architecture
- Microservices
- Modular Monolith
- Estimation
- Developer Life
- Project Planning
- Humour
- OAuth
- OpenID Connect
- Authentication
- Embeddings
- Vector Search
- RAG
- pgvector
- OpenAI
- GPT-4.1
- Codex CLI
- Events
- Testing
- Clean Code
- Maintainability
- Code Review
- Webhooks
- API
- Security
- Claude Code
- Workflow
- AI
- LLM
- Prompt Injection
- Mobile
- React
- Networking
- TCP
- UDP
- HTTP/3
- CLAUDE.md
- AWS
- Cloud Security
- Backups
- PHPUnit
- Software Engineering
- Leadership
- Communication
- RAG
- Embeddings
- AI Engineering
- IT Infrastructure
- Networking
- Access Control
- CI/CD
- GitHub Actions
- Gemini CLI
- Claude Code
- JavaScript
- Async/Await
- Node.js
- Promises
- Security
- Cryptography
- Passwords
- MySQL
- Database
- Vibe Coding
- Software Quality
- DNS
- Code Reading
- Onboarding
- Productivity
- Background Jobs
- Developer Humour
- Estimates
- Dev Life
- JWT
- o3-mini
- DeepSeek R1
- Rate Limiting
- Kate PMS
- E-Signing
- Audit Trail
- REST
- GraphQL
- API Design
- Laravel 12
- Upgrade Guide
- Open Source
- Self-Hosting
- Task Scheduling
- Cron
- Secrets
- CORS
- PHP
- PHP-FPM
- OPcache
- GitHub Copilot
- Software Architecture
- Engineering
- TypeScript
- JavaScript
- Type Safety
- AI Security
- React Native
- Product Design
- AI Agents
- Kiro
- Queues
- Redis
- RabbitMQ
- AWS SQS
- Nginx
- Apache
- GPT-5
- gpt-oss
- Clean Code
- Architecture
- Naming
- Documentation
- Career
- ADR
- Teamwork
- Supply Chain
- Kate HRM
- HR Software
- Permissions
- System Design
- Pagination
- SSH
- Linux
- Big O
- Databases
- Laravel Boost
- MCP
- Developer Skills
- Validation
- Databases
- Indexes
- Code Quality
- Deployment
- Developer Humour
- Feature Flags
- Code Review
- Pull Requests
- Docker
- Cursor
- Authorization
- RBAC
- Gemini
- Long Context
- PHP 8.4
- Caching
- Dependency Injection
- Web Performance
- Browser
- CSS
- Database
- Migrations
- ChatGPT
- AI for Developers
- Monitoring
- On-Call
- REST
- Backend
- SQL
- NoSQL
- Database Design
- Coding Agents
- Claude 4
- API Resources
- REST API
- Load Balancing
- Scaling
- AWS
- AI Tools
- Claude
- Sora 2
- CTE
- 2FA
- TOTP
- Programming Languages
- Prompts
- Developer Workflow
- API Gateway
- APIs
- Passport
- API Auth
- Learning
- Burnout
- Developer Growth
- Web Development
- SEO
- Kate Mall
- ChatGPT Atlas
- Agent Skills
- Middleware
- Laravel 12
- Collections
- Context Window
- Monitoring
- Commit Messages
- Self Review
- Growth
- Regex
- Programming Basics
- Text Processing
- Database Design
- Normalization
- Linux
- Server Security
- Linux Foundation
- Open Standards
- Legacy Code
- Documentation
- AI Workflow
- File Uploads
- Test Data
- Hashing
- Performance
- Caching
- Enums
- Scope Creep
- Estimation
- Codex
- Gemini CLI
- Timezones
- Carbon
- Bugs
- PHP 8.5
- Gemini 3
- GPT-5.1
- Data Integrity
- Event Loop
- Async
- Opus 4.5
- AI Models
- React
- Forms
- Frontend
- Backups
- AI Images
- DALL-E
- Midjourney
- Race Conditions
- Concurrency
- Legacy Code
- Refactoring
- Senior Engineer
- Scope
- LLM
- CDN
- Web
- Sub-Agents
- Soft Deletes
- Audit Log
- Concurrency
- AI Learning
- NestJS
- AI Evals
- Policies
- SPF DKIM DMARC
- Unicode
- UTF-8
- Knowledge Graph
- Value Objects
- Technical Debt
- Feature Flags
- Laravel Pennant
- Deployment
- Copilot
- Composer
- Dependencies
- Artisan
- Automation
- AWS S3
- Object Storage
- Cloud
- Small Language Models
- Ollama
- Production
- Sessions
- HTTP
- Mentoring
- SQL
- Virtual Machines
- Web Development
- HTTP/2
- QUIC
- Web Performance
- AI Integration
- LLM API
- SOLID
- OOP
- Hosting
- Serverless
- Merge Conflicts
- Temperature
- AI Development
- Reverse Proxy
- Nginx
- Infrastructure
- Verification
- Passkeys
- WebAuthn
- Teams
- Communication
- Stakeholders
- Monorepo
- CI/CD
- Versioning
- JSON Schema
- Livewire
- Inertia
- Meetings
- Distributed Systems
- Privacy
- Full-Stack
- T-Shaped Skills
- Money
- Notifications
- Web Security
- HTTP Headers
- CSP
- Function Calling
- Load Testing
- k6
- Data Extraction
- Debugging
- WebSockets
- SSE
- Real-Time
- Laravel Reverb
- Infrastructure as Code
- Terraform
- Side Projects
- Laravel Pint
- OpenAPI
- Swagger
- UX
- Multimodal
- Jest
- Pair Programming
- APIs
- Rate Limiting
- Resilience
- Dev Humour
- Design Tokens
- JWT
- API Keys
- Sessions
- PHPStan
- Rector
- Incidents
- Reporting
- Dashboards
- Zero Trust
- IAM
- Search
- Laravel Scout
- Junior Developers
- Mentoring
- Images
- WebP
- AVIF
- Bug Reports
- Let's Encrypt
- Design Docs
- Software Design
- Observers
- Replication
- Accountability
- Data Structures
- Reliability
- LLM Memory
- Error Handling
- Payments
- Payment Gateway
- Webhooks
- PCI DSS
- Observability
- OpenTelemetry
- Personal Brand
- Writing
- Conventions
- Dates
- Scheduling
- Disaster Recovery
- Compression
- Brotli
- Deadlines
- Developer Habits
- State Machines
- Tech Roles
- UUID
- ULID
- Horizon
- Planning
- Engineering Culture
- Ownership
- Soft Skills
- Socialite
- Cost Control
- Collations
- Unicode
- Octane
- PostgreSQL
Docker Mistakes That Make Your Images Huge and Your Builds Slow
About Post
You change one line of PHP. You rebuild the image. Docker downloads every Composer package again, reinstalls every npm package, rebuilds every asset, and then pushes an image the size of a small operating system to your registry.
Ten minutes later you can test your one-line change.
Slow builds and huge images are rarely Docker's fault. They come from a handful of small mistakes in the Dockerfile, and almost all of them are easy to fix once you understand one idea: layers and the build cache.
The one idea: layers are cached in order
Each instruction in a Dockerfile (COPY, RUN and so on) creates a layer. Docker caches layers, and when you rebuild, it reuses them until it reaches the first instruction whose inputs changed. From that point on, every layer is rebuilt.
So the order of your Dockerfile decides how much work a rebuild does. Keep that in mind, because most of the mistakes below are really the same mistake.
Mistake 1: no .dockerignore
What happens: COPY . . sends your whole project folder to the build, including .git, node_modules, vendor, logs, local uploads and your .env.
Why it hurts: builds start slowly because of the huge build context, any changed log file invalidates the cache, and your local secrets can end up inside the image. Anyone who can pull the image can read them.
The fix:
.git
.env
node_modules
vendor
storage/logs/*
storage/framework/cache/*
public/build
tests
docker-compose*.yml
Dependencies are installed inside the build, so there's no reason to copy your local ones in.
Mistake 2: copying everything before installing dependencies
What happens:
COPY . .
RUN composer install
Why it hurts: any change to any file invalidates the COPY layer, so composer install runs again on every build, even though composer.json didn't change.
The fix: copy the dependency files first, install, and only then copy the rest of the code. Your dependencies change rarely; your code changes constantly. Put the rarely changing things higher up.
Mistake 3: shipping development tools to production
What happens: the production image includes PHPUnit, debug packages, the Node.js toolchain, node_modules and compilers, because they were needed at some point during the build.
Why it hurts: a bigger image means slower pulls and deploys, and every extra package is extra attack surface. Your production container has no business running a test framework.
The fix: composer install --no-dev for production, and a multi-stage build (below) so build tools never reach the final image.
Mistake 4: cleaning up in a separate layer
What happens:
RUN apt-get update && apt-get install -y build-essential
RUN rm -rf /var/lib/apt/lists/*
Why it hurts: layers are additive. The files deleted in the second layer still exist in the first one, so the image doesn't get any smaller. You've just hidden them.
The fix: install and clean up in the same RUN, and use --no-install-recommends to skip optional packages. Better still, use a multi-stage build so build-only packages are never in the final image at all.
Mistake 5: running as root
What happens: no USER instruction, so the app runs as root inside the container.
Why it hurts: if someone finds a way to run code through your app, they're root in that container, which makes everything else they try easier.
The fix: set file ownership with COPY --chown and switch to an unprivileged user (the official PHP images already include www-data). Make sure that user can only write where it needs to, like storage and bootstrap/cache in Laravel.
Mistake 6: latest tags
What happens: FROM php:latest or FROM node:latest.
Why it hurts: the same Dockerfile builds a different image next month. One day latest moves to a new major version, and your build breaks, or worse, it builds fine and fails at runtime.
The fix: pin versions, like php:8.4-fpm-alpine and node:22-alpine. Upgrade on purpose, in a pull request, with tests.
Putting it together: a multi-stage build
Multi-stage builds solve most of these at once. Each stage does one job, and the final stage copies in only the results. Here's a simplified version for a Laravel app with Vite assets:
FROM composer:2 AS vendor
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --no-scripts --no-autoloader --prefer-dist
COPY . .
RUN composer dump-autoload --optimize --no-dev
FROM node:22-alpine AS assets
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM php:8.4-fpm-alpine
WORKDIR /var/www/html
COPY --chown=www-data:www-data . .
COPY --from=vendor --chown=www-data:www-data /app/vendor ./vendor
COPY --from=assets --chown=www-data:www-data /app/public/build ./public/build
USER www-data
Composer and Node live only in their own stages. The final image has PHP, your code, production dependencies and compiled assets, and nothing else. Changing a PHP file leaves the composer install and npm ci layers cached. In a real project you'd also install the PHP extensions your app needs in the final stage and handle the web server, but the structure stays the same. (One gotcha: the composer image doesn't have every PHP extension your app requires, so Composer may refuse to install. Checking platform requirements in the final stage instead is a common workaround.)
Order your Dockerfile by how often things change: base image first, then system packages, then dependency files and installs, and your application code last. That single habit fixes most slow builds.
Quick checklist
- A
.dockerignorethat excludes.git,.envand local dependencies. - Dependency files copied and installed before the rest of the code.
- No dev dependencies or build tools in the final image.
- Install and clean up in the same layer, or use stages.
- A non-root user.
- Pinned base image versions.
- Run
docker history your-imageonce in a while to see which layers are heavy.
Which of these was hiding in your Dockerfile? And what's the biggest image you've ever had to slim down?

Be first to comment it...