<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Rebuild &#8211; Best DevOps</title>
	<atom:link href="https://www.bestdevops.com/tag/rebuild/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bestdevops.com</link>
	<description>Lets Learn, Do it &#38; Share! Thats a Best DevOps!!!</description>
	<lastBuildDate>Mon, 12 Oct 2026 11:14:57 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.3</generator>
	<item>
		<title>How to Rebuild a Go Project Efficiently with Docker Compose</title>
		<link>https://www.bestdevops.com/how-to-rebuild-go-project-efficiently-while-using-docker-compose/</link>
					<comments>https://www.bestdevops.com/how-to-rebuild-go-project-efficiently-while-using-docker-compose/#respond</comments>
		
		<dc:creator><![CDATA[anil]]></dc:creator>
		<pubDate>Mon, 12 Jun 2017 07:47:45 +0000</pubDate>
				<category><![CDATA[DevOps]]></category>
		<category><![CDATA[DevOps Tools]]></category>
		<category><![CDATA[BestDevOps]]></category>
		<category><![CDATA[Build]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker Compose]]></category>
		<category><![CDATA[Rebuild]]></category>
		<guid isPermaLink="false">http://www.bestdevops.com/?p=1801</guid>

					<description><![CDATA[Rebuilding a Go project inside Docker Compose on every code change is slow. Learn the root cause and practical strategies—volumes, fresh containers, and live-reload tools—to speed up your inner development loop.]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><em>This article is based on a common Docker Compose + Go development question originally discussed on Stack Overflow.</em></p>



<h2 class="wp-block-heading">The Problem: Slow Rebuilds in Docker Compose</h2>



<p class="wp-block-paragraph">If you are new to Docker Compose and working on a Go project, you may have noticed that every time you change a source file, the feedback loop feels painfully slow. The naive workflow looks like this:</p>


<pre class="wp-block-code"><span><code class="hljs">docker-compose build
docker-compose up</code></span></pre>


<p class="wp-block-paragraph">The issue is that <code>docker-compose build</code> rebuilds the entire image from scratch—including re-downloading and re-compiling all Go dependencies—even when only one source file changed. On a project with many dependencies this can take minutes per iteration.</p>



<h2 class="wp-block-heading">Why the Volume Mount Approach Breaks</h2>



<p class="wp-block-paragraph">A natural instinct is to skip the full image rebuild by running a build command directly against a running container:</p>


<pre class="wp-block-code"><span><code class="hljs">docker-compose run web go build .
docker-compose run web ./app</code></span></pre>


<p class="wp-block-paragraph">or</p>


<pre class="wp-block-code"><span><code class="hljs">docker-compose run web go build .
docker-compose restart</code></span></pre>


<p class="wp-block-paragraph">This seems reasonable because a host-to-container volume mount means the container already has access to updated source files—there is no need to copy them in again. However, two problems occur:</p>



<ul class="wp-block-list">
<li><strong>The new binary is not picked up.</strong> <code>docker-compose restart</code> restarts the service using the <code>command</code> defined in <code>docker-compose.yml</code>, but the running process image is already in memory. The container does not re-exec the binary after restart in the way you might expect.</li>
<li><strong>Port forwarding breaks.</strong> <code>docker-compose run</code> starts a brand-new, one-off container. It does not reuse the port bindings of the <em>up</em>-managed container, so the published port is no longer mapped correctly.</li>
</ul>



<h2 class="wp-block-heading">Reference Configuration</h2>



<p class="wp-block-paragraph">Here is the Dockerfile and Compose file that illustrate the typical starting point for this problem:</p>



<h3 class="wp-block-heading">Dockerfile</h3>


<pre class="wp-block-code"><span><code class="hljs language-php">FROM golang:<span class="hljs-number">1.8</span>

COPY . /go/src/github.com/codeblooded/test1
WORKDIR /go/src/github.com/codeblooded/test1

RUN <span class="hljs-keyword">echo</span> $PATH
RUN go get -d -v ./...
RUN go install -v ./...

RUN go build -o test1 .
CMD &#91;<span class="hljs-string">"test1"</span>]
EXPOSE <span class="hljs-number">3470</span></code></span></pre>


<h3 class="wp-block-heading">docker-compose.yml</h3>


<pre class="wp-block-code"><span><code class="hljs language-php">version: <span class="hljs-string">'3'</span>
services:
  postgres:
    image: postgres
    volumes:
      - ./db/data/psql:/<span class="hljs-keyword">var</span>/lib/postgresql/data
      - ./db/schema:/db/schema
  redis:
    image: redis
    volumes:
      - ./db/data/redis:/data
  server:
    build: .
    command: test1
    volumes:
      - .:/go/src/github.com/codeblooded/test1
    ports:
      - <span class="hljs-string">"3470:3470"</span>
    depends_on:
      - postgres
      - redis</code></span></pre>


<h2 class="wp-block-heading">Root Cause: The Image Layer Cache Is Not Being Used Properly</h2>



<p class="wp-block-paragraph">The Dockerfile above copies the entire project directory before running <code>go get</code>. This means Docker cannot cache the dependency-download layer separately from the source code. Every time a source file changes, Docker invalidates the <code>COPY . .</code> layer, which forces every subsequent layer—including <code>go get</code>—to re-run.</p>



<h2 class="wp-block-heading">Solution 1: Fix the Layer Cache Order</h2>



<p class="wp-block-paragraph">If you are using Go modules (<code>go.mod</code> / <code>go.sum</code>), copy only those files first, run <code>go mod download</code>, and <em>then</em> copy the rest of the source. Docker caches each layer independently, so the dependency download layer is only invalidated when <code>go.mod</code> or <code>go.sum</code> changes—not on every source edit.</p>


<pre class="wp-block-code"><span><code class="hljs language-php">FROM golang:<span class="hljs-number">1.21</span>

WORKDIR /app

<span class="hljs-comment"># Cache dependencies separately from source code</span>
COPY go.mod go.sum ./
RUN go mod download

<span class="hljs-comment"># Now copy the rest of the source</span>
COPY . .

RUN go build -o server .
CMD &#91;<span class="hljs-string">"./server"</span>]
EXPOSE <span class="hljs-number">3470</span></code></span></pre>


<p class="wp-block-paragraph">With this structure, <code>docker-compose build</code> only re-downloads dependencies when the module files change. Rebuilding after a source-only edit becomes much faster.</p>



<h2 class="wp-block-heading">Solution 2: Use exec + Stop/Start Instead of restart</h2>



<p class="wp-block-paragraph">If you want to rebuild inside the running container without a full image rebuild, use <code>docker-compose exec</code> (not <code>run</code>) to compile inside the already-running service container, then stop and start the service:</p>


<pre class="wp-block-code"><span><code class="hljs language-php"><span class="hljs-comment"># Compile inside the existing container</span>
docker-compose exec server go build -o /app/server .

<span class="hljs-comment"># Stop and start (not restart) so CMD is re-executed</span>
docker-compose stop server
docker-compose start server</code></span></pre>


<p class="wp-block-paragraph"><code>docker-compose exec</code> runs the command inside the container that is already listening on the correct port, so port forwarding remains intact. <code>stop</code> + <code>start</code> (rather than <code>restart</code>) ensures the entry-point binary is re-executed from disk.</p>



<p class="wp-block-paragraph">Note: the container&#8217;s <code>CMD</code> must point to the binary at a predictable path that the new build overwrites.</p>



<h2 class="wp-block-heading">Solution 3: Use a Live-Reload Tool</h2>



<p class="wp-block-paragraph">For the fastest inner-loop experience during development, use a file-watching live-reload tool as the container&#8217;s entrypoint. The tool watches your source files via the shared volume and automatically recompiles and restarts the Go binary when files change—no manual rebuild step needed.</p>



<p class="wp-block-paragraph">Popular options for Go include:</p>



<ul class="wp-block-list">
<li><strong>Air</strong> (<code>github.com/air-verse/air</code>) — a widely used live-reload tool for Go applications.</li>
<li><strong>CompileDaemon</strong> (<code>github.com/githubnemo/CompileDaemon</code>) — watches Go files and triggers <code>go build</code> on change.</li>
<li><strong>Reflex</strong> (<code>github.com/cespare/reflex</code>) — a general-purpose file watcher that can run any command.</li>
</ul>



<p class="wp-block-paragraph">A Dockerfile using Air for development might look like this:</p>


<pre class="wp-block-code"><span><code class="hljs language-php">FROM golang:<span class="hljs-number">1.21</span>

WORKDIR /app

<span class="hljs-comment"># Install Air</span>
RUN go install github.com/air-verse/air@latest

COPY go.mod go.sum ./
RUN go mod download

COPY . .

EXPOSE <span class="hljs-number">3470</span>
CMD &#91;<span class="hljs-string">"air"</span>]</code></span></pre>


<p class="wp-block-paragraph">With the host source directory mounted as a volume (<code>.:/app</code>), Air detects file changes on the host, rebuilds the binary inside the container, and restarts it—all automatically. Port bindings remain stable because the container itself never stops.</p>



<h2 class="wp-block-heading">Choosing the Right Approach</h2>



<figure class="wp-block-table"><table><thead><tr><th>Approach</th><th>Build speed</th><th>Port stability</th><th>Complexity</th><th>Best for</th></tr></thead><tbody><tr><td>Fix layer cache order</td><td>Fast after first build</td><td>Stable (full rebuild)</td><td>Low</td><td>CI / production images</td></tr><tr><td>exec + stop/start</td><td>Fast (no image rebuild)</td><td>Stable</td><td>Medium</td><td>Occasional manual rebuilds</td></tr><tr><td>Live-reload tool (Air)</td><td>Fastest (automatic)</td><td>Stable</td><td>Low–Medium</td><td>Active development loops</td></tr></tbody></table></figure>



<h2 class="wp-block-heading">Key Takeaways</h2>



<ul class="wp-block-list">
<li>Never run <code>docker-compose build</code> on every source change if you can avoid it. Fix your Dockerfile layer order so that dependencies are cached separately from application code.</li>
<li>Use <code>docker-compose exec</code> (not <code>run</code>) when you need to run a command inside an already-running service container. <code>run</code> creates a new container with different port bindings.</li>
<li>For active Go development inside Docker Compose, a live-reload tool like Air gives you the fastest and most ergonomic feedback loop with minimal configuration.</li>
<li>Volume mounts alone do not cause the container to pick up a new binary—you still need to stop and restart the process, or use a watcher that does this automatically.</li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bestdevops.com/how-to-rebuild-go-project-efficiently-while-using-docker-compose/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
