惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threatpost
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Engineering at Meta
Engineering at Meta
T
The Blog of Author Tim Ferriss
Recent Announcements
Recent Announcements
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
The Register - Security
The Register - Security
MongoDB | Blog
MongoDB | Blog
U
Unit 42
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
P
Privacy International News Feed
L
LINUX DO - 最新话题
博客园_首页
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Tor Project blog
V
Visual Studio Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
P
Privacy & Cybersecurity Law Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
K
Kaspersky official blog
C
Cisco Blogs
博客园 - 【当耐特】
阮一峰的网络日志
阮一峰的网络日志
I
Intezer
罗磊的独立博客
MyScale Blog
MyScale Blog
Last Week in AI
Last Week in AI
A
About on SuperTechFans
G
GRAHAM CLULEY
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
GbyAI
GbyAI
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
D
DataBreaches.Net
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
AWS News Blog
AWS News Blog
I
InfoQ
T
The Exploit Database - CXSecurity.com
Simon Willison's Weblog
Simon Willison's Weblog
博客园 - 叶小钗
Project Zero
Project Zero

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Build Cache Strategies: The Operational Burden of Speed
Mustafa ERBAY · 2026-05-31 · via DEV Community

Build times, especially in enterprise software projects, are often an overlooked bottleneck that leads to significant inefficiencies. While working on a production ERP, deployments taking hours after merging a new feature branch became a problem that tested developers' patience and slowed down our delivery speed. Building from scratch with every small change was both a waste of resources and a major operational burden.

To solve this problem, I implemented various build cache strategies. My goal was not only to speed up builds but also to manage the operational complexity that comes with this speed. Because speed often brings new problems; issues like the correct functioning, management, and security of the cache require constant attention.

Why Were Build Times a Problem? Symptoms and Initial Observations

In a client project, especially when we transitioned to a microservices architecture, build times started to increase exponentially. Each service had its own dependencies, its own compilation steps, and these were built from scratch every time a CI/CD pipeline ran. The average deployment time after a git push, even for a small change, reached 45 minutes. Sometimes, when there was a major dependency update, this could even extend to 1.5 hours.

This situation prolonged the feedback loop for developers, causing them to wait constantly. A developer who pushed a change first thing in the morning would only see the test results in the afternoon. This was a major obstacle, especially during a period when we expected rapid iterations. The main symptoms I observed were:

  • High CPU and Disk Usage: Build servers were constantly running at 90%+ CPU and IOPS values. Disks were filling up quickly, and storage costs were increasing due to temporary build files.
  • Low Developer Productivity: Developers found it difficult to focus on other tasks while waiting for builds to finish, forcing them to context switch.
  • CI/CD Queues: When multiple developers pushed changes simultaneously, long queues formed in the CI/CD pipelines. This further extended everyone's waiting time.

ℹ️ My Observation

In my experience, as build times increase, developers tend to accumulate small changes. This can lead to larger and riskier integrations. Build cache is one of the keys to breaking this vicious cycle.

At the root of these problems was the fact that each build step ran independently and in isolation. For example, when creating Docker images, each RUN command creates a new layer, and if previous layers haven't changed, it benefits from the cache. However, when dependency files (like package.json, requirements.txt) change frequently or build steps are not well optimized, this cache mechanism was not effective enough. My first goal was to find ways to use this fundamental Docker layer caching principle more efficiently.

Different Build Cache Mechanisms and My Preferences

To optimize build times, I researched and implemented different cache mechanisms in my projects. Each has its own advantages and operational overheads.

1. In-Container (Layer) Caching

Docker's built-in layer caching mechanism is the most basic and often the most effective method. Each command in a Dockerfile creates a layer. If a previous layer and command haven't changed, Docker pulls this layer from the cache instead of rebuilding it.

While working on a production ERP, I learned to better utilize this cache by optimizing Dockerfiles. For example, separating the dependency installation step (which doesn't change often) from the application code (which changes frequently) significantly shortens build times:

# First copy dependency files
COPY package.json package-lock.json ./
# Install dependencies (if package.json hasn't changed, this layer comes from cache)
RUN npm ci

# Now copy application code
COPY . .
# Compile/build the application
RUN npm run build

This simple change ensured that the npm ci step was skipped every time, as long as package.json didn't change. In my ERP project, this small optimization reduced the dependency installation step from 3-5 minutes to mere seconds. However, this method alone wasn't sufficient because the cache was created from scratch every time on different machines or CI/CD runners. Different runners or new machines couldn't benefit from each other's cache, even if they had built the same layer before.

2. External (Shared) Build Cache

To allow multiple CI/CD runners or developers to use the same cache, I turned to external cache mechanisms. At this point, Docker Buildx's remote cache feature was a game-changer for me. Buildx can save build results (layers) to a Docker registry or an external storage unit (e.g., S3-compatible storage) and pull them from there.

In a client project, I set up Buildx with S3-compatible storage in an environment with multiple CI/CD runners. Each build, upon completion, sent its cache to this storage, and a new build, when started, first pulled the cache from there.

docker buildx create --name mybuilder --driver docker-container --use
docker buildx build --builder mybuilder \
  --platform linux/amd64 \
  --cache-from type=registry,ref=myregistry.com/my-app:buildcache \
  --cache-to type=registry,ref=myregistry.com/my-app:buildcache,mode=max \
  -t myregistry.com/my-app:latest . --push

Thanks to this setup, when different runners started the same build, they could instantly benefit from the cache of a previously completed build. In my observation, this method reduced average build times by 60-70%. Specifically, it prevented node_modules or maven dependencies from being downloaded repeatedly.

💡 A Tip from My Experience

When using remote cache with Buildx, it's important to use the mode=max parameter. This attempts to save not only the final layers but also all intermediate layers as cache, providing a more comprehensive cache for the next build.

For my side product's CI/CD pipeline, I also experimented with tools like sccache. These tools can significantly speed up build times for languages like C/C++ by storing compiler outputs on a cache server. This can be particularly useful in large monorepos or projects with many dependencies.

Operational Burden: Cache Management and Maintenance

Implementing build cache strategies not only speeds up builds but also introduces a new operational burden. If we don't manage this burden correctly, we can lose the speed gains to complexity.

Cache Invalidation Strategies

The biggest enemy of cache is "stale" data. Incorrect invalidation can lead to the deployment of old code or erroneous behavior. In my ERP project, we once struggled with strange bugs in the production environment for a week due to a faulty dependency stuck in the cache. The root cause was a build cache holding an incorrect version.

To prevent such situations, I implemented the following strategies:

  • Dependency-Aware Cache: Invalidate the cache completely when the hashes of dependency definition files like package.json or go.mod change.
  • Manual Cache Clearing: Sometimes, especially during major version updates or critical security patches, it's necessary to manually clear the entire cache. I added a step to the CI/CD pipeline to trigger this action.
  • Time-Based Eviction: Automatically delete caches that haven't been used for a certain period.

Disk Space Management and Cost

Build caches, especially in large projects, can occupy significant disk space. When using remote cache, this translates to storage costs. In one of my client's projects, the Buildx cache on S3 reached over 500GB of storage monthly.

To optimize this cost and disk usage:

  • Lifecycle Rules: On storage services like S3, I defined lifecycle rules to automatically delete objects older than a certain period or move them to cheaper storage tiers. For example, deleting cache objects older than 30 days.
  • Periodic Cleanup Scripts: On self-hosted build servers, I created cron jobs that cleaned up unused Docker images, build caches, and temporary files.
#!/bin/bash
# Clean up Docker build caches older than 7 days
docker builder prune --filter "until=7d" --force

# Clean up unused Docker images
docker image prune --all --force

# Clean up unused Docker volumes
docker volume prune --force

These scripts prevented disk fill-ups from reaching critical levels and helped me keep storage costs under control.

Security Risks

Build cache also carries potential security risks. If a build cache contains sensitive data (API keys, passwords, etc.) and this cache is not properly protected, it can create a serious security vulnerability.

In a production environment, an API key was accidentally included in build arguments. This key posed a risk of leaking into the build cache. To prevent such situations:

  • Avoid Caching Sensitive Data: Use secret mounts in Dockerfiles or pass sensitive data as environment variables during build to ensure it's not cached.
  • Access Control: Implement strict access control on remote cache storage (e.g., S3 buckets). Ensure that only CI/CD runners and authorized personnel can access it.

⚠️ Important Note

Avoid directly using sensitive data during RUN commands in your Dockerfile. This data can be cached as layers and later become accessible via docker history or docker save. Buildx's mount=type=secret feature is a good solution for this.

Performance Metrics and Observation

When optimizing the performance of a system, observability is essential. I closely monitored metrics to understand the effectiveness of build cache strategies and to detect operational problems early.

Build Time Tracking

I collected the total build time as a metric by recording the start and end times of each build in CI/CD systems. I visualized this data using Prometheus and Grafana.

# Example Prometheus rule (assuming we collect metrics from a CI/CD system)
- job_name: 'ci_cd_builds'
  metrics_path: /metrics
  static_configs:
    - targets: ['ci-cd-runner-1:9100', 'ci-cd-runner-2:9100']
  relabel_configs:
    - source_labels: [__address__]
      regex: '([^:]+):.*'
      target_label: instance
      replacement: '$1'

In Grafana, I created a graph showing the change in build times over time. This graph allowed me to clearly see unexpected increases in build times overnight or the impact of an optimization. For example, I immediately noticed that build times jumped from 15 minutes to 40 minutes after a dependency update on April 28th, thanks to this graph.

Cache Hit/Miss Ratios

The most critical metric showing how effectively a build cache is working is the cache hit/miss ratio. Tools like Buildx can provide this information in their output with the --progress=plain flag.

# Example docker build output
...
#10 [build 5/5] RUN npm run build
#10 CACHED
#10 DONE 0.0s
...

By parsing these outputs or collecting these ratios from Buildx's build reports, I observed how frequently the cache was used. If the cache hit ratio dropped below 80%, it usually indicated a cache invalidation strategy issue or a deficiency in Buildx settings. When the cache hit ratio dropped to 50% in my side product's CI/CD, I found that the reason was Buildx not having write permissions to the remote cache. After correcting the permissions, the ratio quickly rose above 95%.

Anomaly Detection and Alerts

I set up alerting systems to automatically detect anomalous changes in build time and cache hit/miss ratios. Using Prometheus Alertmanager, I configured notifications to be sent to a Slack channel or via email if certain thresholds were exceeded (e.g., "build time increased by more than 50% in the last 1 hour" or "cache hit ratio dropped below 70% in the last 4 hours").

ℹ️ Related Post

I previously wrote a post on [related: system metrics collection and alerting mechanisms]. These principles also apply to build cache metrics.

This proactive monitoring allowed us to address problems before developers noticed them or before the operational burden became severe. For example, when a build time alarm went off at 03:14, I immediately intervened, resolved a disk space issue, and prevented a potential outage.

Trade-offs and Choosing the Right Strategy

When choosing build cache strategies, we always encounter a trade-off. There is no single "one-size-fits-all" solution. In my experience, these decisions were usually based on a balance of speed, complexity, cost, and security.

Speed vs. Complexity

The simplest Docker layer caching method is fast and easy to set up but does not allow cache sharing between different CI/CD runners. This might be sufficient for small projects or single-runner environments. However, it falls short in larger and distributed CI/CD infrastructures.

Remote cache (Buildx + registry/S3) offers much higher speeds because it makes the cache shareable. However, its setup and management are more complex. Setting up a registry or an S3 bucket, managing access permissions, and configuring lifecycle rules add to the operational burden. While developing a production company's ERP, we initially managed with simple layer caching. But as the project grew and the number of developers increased, we had to switch to Buildx. This transition initially required several days of setup and configuration.

Cost vs. Efficiency

Faster builds generally require more resources. If you use cloud storage services like S3 for remote cache, storage and data transfer costs increase. Additionally, build servers might need more CPU and RAM.

For the backend of my side product, I initially self-hosted everything on my own VPS. Instead of using external S3 storage for the build cache, I preferred to keep the cache on my local disk. This saved me storage costs, but build times were longer, and if I ever needed to reinstall the VPS, the cache would be completely lost. At some point, the inefficiency caused by longer build times outweighed the S3 storage cost, and I switched to remote cache.

My cost analysis for a client's project was as follows:

  • Option A (Zero Cache): Average build time 45 min. 10 builds per day = 450 min (~7.5 hours) build time. Developer waiting cost (average hourly rate x waiting time) + need for more CI/CD runners.
  • Option B (Remote Cache): Average build time 10 min. 10 builds per day = 100 min (~1.6 hours) build time. S3 storage cost (monthly ~50 USD) + Buildx setup/management time.

My calculations showed that Option B's total cost, especially in terms of developer productivity, was much lower. For 5 developers doing 10 builds a day, a 35-minute gain translated to thousands of dollars in productivity increase per month.

💡 My Preference

Generally, I prefer to use remote build cache in CI/CD pipelines. Although there's an initial operational overhead, it more than pays for itself in the long run in terms of developer productivity and resource optimization. Especially when creating Docker images, Buildx has become an indispensable tool.

Conclusion

Build cache strategies are a critical part of increasing performance and ensuring developer productivity in modern software development processes. However, it's not just about "turning on the cache." Choosing the right cache mechanism, defining invalidation strategies, and managing disk space and security risks require significant operational overhead and attention.

In my experience, what's important in this process is always considering the trade-offs and finding the most suitable solution for the project's needs. From a simple setup for a side product to a complex Buildx integration in a large enterprise ERP, I found different balance points in each project. I always acted on the principle that "speed has a cost" and continuously sought new ways to make this cost manageable. The next step is to work on AI-powered cache invalidation mechanisms to make build caches even smarter.