<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://feeds.feedblitz.com/feedblitz_rss.xslt"?>
<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/"
	xmlns:webfeeds="http://webfeeds.org/rss/1.0"  xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
<channel>
	<title>Baeldung - Ops</title>
	<atom:link href="https://www.baeldung.com/ops/feed" rel="self" type="application/rss+xml" />
	<link>https://www.baeldung.com/ops</link>
	<description>Baeldung - Ops</description>
	<lastBuildDate>Fri, 03 Apr 2026 12:36:55 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
<meta xmlns="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
<item>
<feedburner:origLink>https://www.baeldung.com/ops/jenkins-series</feedburner:origLink>
		<title>Jenkins Series</title>
		<link>https://feeds.feedblitz.com/~/953170670/0/baeldung/ops~Jenkins-Series</link>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Fri, 03 Apr 2026 12:36:55 +0000</pubDate>
				<category><![CDATA[Jenkins]]></category>
		<category><![CDATA[Series]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/?p=94241</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Jenkins-Featured-Image-05-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" fetchpriority="high" />This tutorial provides an overview of Jenkins pipelines, job management, and administration.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953170670/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/953170670/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fJenkins-Featured-Image-05-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/953170670/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/953170670/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/953170670/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/git-series">Git Series</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-jenkins-connection-issues">Troubleshoot Docker Daemon Connection Issues in Jenkins</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/jenkins-valid-crumb-request-error">Troubleshooting Jenkins 403 No Valid Crumb in Request Error</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Jenkins-Featured-Image-05-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Jenkins-Featured-Image-05-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Jenkins-Featured-Image-05-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Jenkins-Featured-Image-05-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Jenkins-Featured-Image-05-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Jenkins-Featured-Image-05-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Jenkins-Featured-Image-05.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><p>Jenkins is a widely used open-source automation server that enables teams to build, test, and deploy software continuously. With its declarative and scripted pipeline syntax, extensive plugin ecosystem, and flexible job scheduling, <em>Jenkins</em> covers the full CI/CD lifecycle â€” from simple builds to complex multi-stage delivery pipelines.</p>
<p>This curated series provides <strong>a comprehensive overview of Jenkins pipelines, job management, and administration</strong>. It covers core pipeline mechanics, Groovy scripting, parameterized and parallel builds, and server maintenance essentials.</p>
<h2 id="bd-getting-started" data-id="getting-started"><img decoding="async" class=" wp-image-93726 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-09.png" alt="ops icons 09" width="52" height="52" data-wp-editing="1" /> Getting Started</h2>
<div class="bd-anchor" id="getting-started"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipelines">Intro to Jenkins 2 and the Power of Pipelines</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-scripted-vs-declarative-pipelines">Scripted vs Declarative Pipelines in Jenkins</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-agent-vs-node">Difference Between Agent and Node in Jenkins Pipeline</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkinsfile-comments">Comments in a Jenkinsfile</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-best-practices">Jenkins Best Practices</a></li>
</ul>
<h2 id="bd-pipeline-mechanics" data-id="pipeline-mechanics"><img decoding="async" class=" wp-image-93727 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-10.png" alt="ops icons 10" width="52" height="52" data-wp-editing="1" /> Pipeline Mechanics</h2>
<div class="bd-anchor" id="pipeline-mechanics"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-set-stage-status">Set Stage Status in Jenkins Pipelines</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-conditional-constructs">How to Use Conditional Constructs in Jenkins Pipeline</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-output-shell-command-variable">Get the Output of a Shell Command in a Jenkins Pipeline</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-skip-stage">Skip a Stage in a Jenkins Pipeline</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-check-file-existence">Check if a File Exists in a Jenkins Pipeline</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-change-to-another-folder">Jenkins Pipeline &#8211; Change to Another Folder</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-git-checkout-credentials">Jenkins Pipeline &#8211; Git Checkout With Credentials</a></li>
</ul>
<h2 id="bd-groovy-and-scripting" data-id="groovy-and-scripting"><img loading="lazy" decoding="async" class=" wp-image-93728 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-11.png" alt="ops icons 11" width="52" height="52" data-wp-editing="1" /> Groovy and Scripting</h2>
<div class="bd-anchor" id="groovy-and-scripting"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-global-variables-pipeline">Utilizing Global Variables in Jenkins Pipeline</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-groovy-read-workspace-file">Reading a File From Workspace in Jenkins Using Groovy</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-sh-script-return-status">Return Stdout, Stderr, and Status From Jenkins sh Script</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-json-object-parameter">Getting a JSON Object as a Parameter in a Jenkins Pipeline</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-no-such-dsl-method-error">Fixing the &#8220;No Such DSL method&#8221; Error in Jenkins Pipeline</a></li>
</ul>
<h2 id="bd-job-management" data-id="job-management"><img loading="lazy" decoding="async" class=" wp-image-93729 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-12.png" alt="ops icons 12" width="52" height="52" data-wp-editing="1" /> Job Management</h2>
<div class="bd-anchor" id="job-management"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-parameterized-builds">Guide to Jenkins Parameterized Builds</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-check-empty-parameter">How to Check if a Pipeline Parameter Is Empty in Jenkins</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-trigger-new-job">Trigger Another Job from a Jenkins Pipeline</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/running-stages-in-parallel-jenkins-workflow-pipeline">Running Stages in Parallel With Jenkins Workflow / Pipeline</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-run-job-parallel">Run the Same Jenkins Job Multiple Times in Parallel</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-multiple-git-repos">Using a Jenkins Pipeline to Checkout Multiple Git Repos Into Same Job</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-dynamic-stages">How to Create Dynamic Stages in a Jenkins Pipeline</a></li>
</ul>
<h2 id="bd-administration" data-id="administration"><img loading="lazy" decoding="async" class=" wp-image-93731 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-14.png" alt="ops icons 14" width="52" height="52" data-wp-editing="1" /> Administration</h2>
<div class="bd-anchor" id="administration"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-export-import-jobs">Export/Import Jobs in Jenkins</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-slave-node-setup">Setting Up a Jenkins Slave Node</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-show-existing-plugins">Listing Installed Jenkins Plugins</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-update-plugins-cli">Updating Jenkins Plugins From the Command Line</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-safe-restart">How to Restart Jenkins Safely</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-api-token">How to Get the API Token for Jenkins</a></li>
</ul><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/953170670/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953170670/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/953170670/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fJenkins-Featured-Image-05-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/953170670/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/953170670/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/953170670/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/git-series">Git Series</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-jenkins-connection-issues">Troubleshoot Docker Daemon Connection Issues in Jenkins</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/jenkins-valid-crumb-request-error">Troubleshooting Jenkins 403 No Valid Crumb in Request Error</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Jenkins-Featured-Image-05-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/ops/git-series</feedburner:origLink>
		<title>Git Series</title>
		<link>https://feeds.feedblitz.com/~/953170673/0/baeldung/ops~Git-Series</link>
		
		<dc:creator><![CDATA[baeldung]]></dc:creator>
		<pubDate>Fri, 03 Apr 2026 12:35:13 +0000</pubDate>
				<category><![CDATA[Git]]></category>
		<category><![CDATA[Series]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/?p=94237</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/Git-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" />This tutorial provides a practical overview of essential Git workflows and techniques.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953170673/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/953170673/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f02%2fGit-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/953170673/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/953170673/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/953170673/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/jenkins-series">Jenkins Series</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-pr-files-modified">Get Files Modified in a PR in GitHub Actions</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/Git-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/Git-Featured-Image-02-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/Git-Featured-Image-02-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/Git-Featured-Image-02-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/Git-Featured-Image-02-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/Git-Featured-Image-02.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><p>Git is the industry-standard distributed version control system used to track changes, coordinate work across teams, and maintain the full history of a codebase. From committing and branching to merging and rebasing, mastering <em>git</em> is foundational for every developer and operations professional.</p>
<p>This curated series provides <strong>a practical overview of essential Git workflows and techniques</strong>, from setting up credentials and managing branches to rewriting history and resolving merge conflicts.</p>
<h2 id="bd-git-essentials" data-id="git-essentials"><img loading="lazy" decoding="async" class=" wp-image-93718 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-01.png" alt="Git Essentials" width="52" height="52" data-wp-editing="1" /> Git Essentials</h2>
<div class="bd-anchor" id="git-essentials"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-guide">Git for Beginners: The Definitive Practical Guide</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-vs-github">Git vs. GitHub</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-commit-messages">Best Practices for Git Commit Message</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-configure-credentials">Configuring git Credentials</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/visual-studio-code-git-credentials">Adding Git Credentials in VS Code</a></li>
</ul>
<h2 id="bd-branches-and-synchronization" data-id="branches-and-synchronization"><img loading="lazy" decoding="async" class=" wp-image-93724 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-07.png" alt="Branches and Synchronization" width="52" height="52" data-wp-editing="1" /> Branches and Synchronization</h2>
<div class="bd-anchor" id="branches-and-synchronization"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-branches-differences">Find the Differences Between Two Git Branches</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-clone-remote-branches">Clone All Remote Branches in Git</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-synchronize-local-remote-branches">Synchronizing Local and Remote Branches in Git</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-branch-creation-date">Determine When a Git Branch Was Created</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-move-uncommitted-work-to-new-branch">Move Existing, Uncommitted Work to a New Branch in Git</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-remove-merged-branches">Delete All Git Branches Which Have Been Merged</a></li>
</ul>
<h2 id="bd-commits-and-history" data-id="commits-and-history"><img loading="lazy" decoding="async" class=" wp-image-93721 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-04.png" alt="Commits and History" width="52" height="52" data-wp-editing="1" /> Commits and History</h2>
<div class="bd-anchor" id="commits-and-history"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-squash-commits">Squash the Last X Commits Using Git</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-remove-file-commit-history">Remove a Large File from Commit History in Git</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-revert-commit">Undo and Revert Commits in Git</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-commit-message-changes">How to Modify Git Commit Messages</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-control-ignore-whitespace">How to Control and Ignore Whitespace Changes in Git Commands</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-commit-search-string">Searching for a String in Git Commits</a></li>
</ul>
<h2 id="bd-merging-and-rebasing" data-id="merging-and-rebasing"><img loading="lazy" decoding="async" class=" wp-image-93725 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-08.png" alt="Merging and Rebasing" width="52" height="52" data-wp-editing="1" /> Merging and Rebasing</h2>
<div class="bd-anchor" id="merging-and-rebasing"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-merge-strategies">Merge Strategies in Git</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-merge-vs-rebase">Difference Between git merge and rebase</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-merge-conflicts-undo">Git Merging: Conflict Resolution and Undoing a merge</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-undo-rebase">Guide to Undo a git rebase</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-merge-unrelated-histories-error">How to Fix Git &#8220;Refusing to Merge Unrelated Histories&#8221;</a></li>
</ul>
<h2 id="bd-staging-and-stash" data-id="staging-and-stash"><img loading="lazy" decoding="async" class=" wp-image-93719 alignnone" src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/10/ops-icons-02.png" alt="Staging and Stash" width="52" height="52" data-wp-editing="1" /> Staging and Stash</h2>
<div class="bd-anchor" id="staging-and-stash"></div>
<hr style="margin-top: -50px" />
<ul>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-staging-stashing">Guide to Git Staging and the Stash</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-stash-pop-vs-stash-apply">Difference Between Git Stash Pop and Git Stash Apply</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-recover-dropped-stash">How to Recover a Dropped Stash in Git</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-remove-file-without-deleting-it">Remove File From Git Repository Without Deleting It Locally</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-discard-unstaged-changes">How to Discard Unstaged Changes in Git</a></li>
<li style="margin-bottom: 5px"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/git-remove-tracked-files-gitignore">Removing Tracked Files With .gitignore</a></li>
</ul><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/953170673/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/953170673/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/953170673/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f02%2fGit-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/953170673/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/953170673/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/953170673/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/jenkins-series">Jenkins Series</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-pr-files-modified">Get Files Modified in a PR in GitHub Actions</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/Git-Featured-Image-02-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/ops/ansible-configuring-environment-variables</feedburner:origLink>
		<title>Configuring Environment Variables in Ansible</title>
		<link>https://feeds.feedblitz.com/~/925102127/0/baeldung/ops~Configuring-Environment-Variables-in-Ansible</link>
		
		<dc:creator><![CDATA[Burak Gökmen]]></dc:creator>
		<pubDate>Sat, 20 Sep 2025 03:03:21 +0000</pubDate>
				<category><![CDATA[Deployment Tools]]></category>
		<category><![CDATA[Ansible]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/?p=94157</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" />Learn how to set both temporary and permanent environment variables using Ansible.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/925102127/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/925102127/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f02%2fOPS-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/925102127/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/925102127/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/925102127/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/ansible-docker-commands-execute">Run Docker Commands With Ansible</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/gocd-introduction">Introduction to GoCD</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p><span lang="EN-GB">The use of <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/environment-variables">environment variables</a> is common in Ansible to make deployments flexible and secure.</span></p>
<p>In this tutorial, we’ll discuss how to set both temporary and permanent environment variables using Ansible. The version of Ansible we use in the examples is 2.12.0.</p>
<h2 id="bd-setting-temporary-environment-variables" data-id="setting-temporary-environment-variables">2. Setting Temporary Environment Variables</h2>
<div class="bd-anchor" id="setting-temporary-environment-variables"></div>
<p>In this section, we’ll see how to set a temporary environment variable to be used within a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/ansible-task-role-play-playbook#ansible-playbook">playbook</a>.</p>
<h3 id="bd-1-example-playbook" data-id="1-example-playbook">2.1. Example Playbook</h3>
<div class="bd-anchor" id="1-example-playbook"></div>
<p>We’ll use the following playbook, <em>playbook_env.yml</em>:</p>
<pre><code class="language-bash">$ vi +"set number" playbook_env.yml
 1 ---
 2   - name: Play1
 3     hosts: localhost
 4     environment:
 5       ENV_VARIABLE: PLAY_LEVEL
 6
 7     tasks:
 8     - name: Task1
 9       command: "echo Environment variable: $ENV_VARIABLE"
10       environment:
11         ENV_VARIABLE: TASK_LEVEL
12       register: print_environment_variable
13
14     - debug:
15         var: print_environment_variable.stdout_lines
16
17     - name: Task2
18       command: "echo Environment variable: $ENV_VARIABLE"
19       register: print_environment_variable
20
21     - debug:
22         var: print_environment_variable.stdout_lines
</code></pre>
<p>The <em>+&#8221;set number&#8221;</em> option of <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/vi-editor"><em>vi</em></a> displays line numbers.</p>
<p>In addition to the playbook, we’ll use the following <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/ansible-list-variables-host-group#1-inventory-file">inventory</a> file:</p>
<pre><code class="language-bash">$ cat inventory
localhost ansible_connection=local
</code></pre>
<p>Let’s discuss the playbook shortly in the following subsection.</p>
<h3 id="bd-2-dissection-of-the-playbook" data-id="2-dissection-of-the-playbook">2.2. Dissection of the Playbook</h3>
<div class="bd-anchor" id="2-dissection-of-the-playbook"></div>
<p>The playbook has a single <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/ansible-task-role-play-playbook#ansible-play">play</a>, <em>Play1</em>, which is shown on lines 2-5. <strong>The play uses the <em>environment</em> keyword, which defines an environment variable for an action to be taken</strong>. Its name is <em>ENV_VARIABLE</em>, and its value is <em>PLAY_LEVEL</em>. <strong>This environment variable is accessible from all <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/ansible-task-role-play-playbook#ansible-task">tasks</a> within the play, as it’s defined at the play level</strong>.</p>
<p>The first task, namely <em>Task1</em> (Lines 8-12), also uses the <em>environment</em> keyword to define an environment variable having the name <em>ENV_VARIABLE</em> and value <em>TASK_LEVEL. </em>We define this environment variable at the task level. <strong>Since its name is the same as the name of the one at the play level, the value at the task level overrides the value at the play level</strong>.</p>
<p>When we execute this task, we run the <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/echo-command">echo</a> Environment variable: $ENV_VARIABLE</em> command to display the environment variable’s value. We create a variable, <em>print_environment_variable</em>, to save the output of the <em>echo</em> command (Line 12). We save the variable using the keyword <em>register</em>. Then, we print this variable using the built-in <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://docs.ansible.com/ansible/latest/collections/ansible/builtin/debug_module.html"><em>debug</em></a> module and its <em>var</em> parameter (Lines 14-15).</p>
<p>The other task, <em>Task2</em> (Lines 17-19), runs the same <em>echo</em> command to display the environment variable’s value. However, it prints the environment variable defined at the play level, as we’ll see shortly. We capture the output of the <em>echo</em> command and print it in the same manner as in <em>Task1</em> (Lines 21-22).</p>
<h3 id="bd-3-running-the-playbook" data-id="3-running-the-playbook">2.3. Running the Playbook</h3>
<div class="bd-anchor" id="3-running-the-playbook"></div>
<p>Having discussed the playbook shortly, let’s now run the playbook using the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/kubernetes-deployment-pass-environment-variable#using-ansible-playbook"><em>ansible-playbook</em></a> command:</p>
<pre><code class="language-bash">$ ansible-playbook playbook_env.yml -i inventory
PLAY [Play1] *******************************************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Task1] *******************************************************************
changed: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] =&gt; {
    "print_environment_variable.stdout_lines": [
        "Environment variable: TASK_LEVEL"
    ]
}
TASK [Task2] *******************************************************************
changed: [localhost]
TASK [debug] *******************************************************************
ok: [localhost] =&gt; {
    "print_environment_variable.stdout_lines": [
        "Environment variable: PLAY_LEVEL"
    ]
}
PLAY RECAP *********************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
</code></pre>
<p>The <em>-i</em> option specifies the inventory file to be used. As is apparent from the output, the value of the environment variable in <em>Task1</em> is <em>TASK_LEVEL</em> as expected. Similarly, the value of the environment variable in <em>Task2</em> is <em>PLAY_LEVEL</em>.</p>
<p>However, there isn’t any environment variable, <em>ENV_VARIABLE</em>, in the system:</p>
<pre><code class="language-bash">$ env | grep ENV_VARIABLE</code></pre>
<p>We used the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/list-env-variables#using-the-env-command"><em>env</em></a> command to display the environment variables defined and filtered the output using the <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/common-text-search">grep</a> ENV_VARIABLE</em> command. Therefore, <strong>the temporary environment variables defined within the playbook are only valid within the playbook</strong>. They don’t have an effect on the system.</p>
<h2 id="bd-setting-permanent-environment-variables" data-id="setting-permanent-environment-variables">3. Setting Permanent Environment Variables</h2>
<div class="bd-anchor" id="setting-permanent-environment-variables"></div>
<p>In this section, we’ll see how to set a permanent environment variable for a user. For this purpose, <strong>we’ll use the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/bashrc-vs-bash-profile-vs-profile#2-significance-of-bashrc"><em>.bashrc</em></a> file, a Bash shell script that sets variables, functions, and aliases</strong>. It runs on every interactive shell launch. It’s in the home directory of a user.</p>
<p>It’s also possible to set an environment variable for all users. For example, we can use <em>/etc/default</em> for this purpose.</p>
<h3 id="bd-1-example-playbook-1" data-id="1-example-playbook-1">3.1. Example Playbook</h3>
<div class="bd-anchor" id="1-example-playbook-1"></div>
<p>We’ll use the following playbook, <em>playbook_env_persistent.yml</em>:</p>
<pre><code class="language-bash">$ vi +"set number" playbook_env_persistent.yml
1 ---
2   - name: Ansible define a persistent environment variable
3     hosts: localhost
4
5     tasks:
6     - name: Set environment variable in config file
7       lineinfile:
8         path: /home/baeldung/.bashrc
9         line: 'export ENV_VARIABLE=SYSTEM_LEVEL'</code></pre>
<p>We’ll use the same inventory file.</p>
<p>Let’s discuss the playbook briefly in the following subsection.</p>
<h3 id="bd-2-dissection-of-the-playbook-1" data-id="2-dissection-of-the-playbook-1">3.2. Dissection of the Playbook</h3>
<div class="bd-anchor" id="2-dissection-of-the-playbook-1"></div>
<p>We define an environment variable, <em>ENV_VARIABLE</em>, in <em>/home/baeldung/.bashrc</em> by using the built-in <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://docs.ansible.com/ansible/latest/collections/ansible/builtin/lineinfile_module.html"><em>lineinfile</em></a> module (Lines 7-9).</p>
<p><strong>The built-in <em>lineinfile</em> module is useful for changing a single line in a file or adding a single line to a file</strong>. The <em>path</em> parameter specifies the file to edit, which is <em>/home/baeldung/.bashrc</em> in our case. The <em>line</em> parameter, on the other hand, specifies the line to insert into the file. It’s the <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/bash-variables-export#the-export-command">export</a> ENV_VARIABLE=SYSTEM_LEVEL</em> command. By default, it’s appended to the end of the file using only these two parameters.</p>
<h3 id="bd-3-running-the-playbook-1" data-id="3-running-the-playbook-1">3.3. Running the Playbook</h3>
<div class="bd-anchor" id="3-running-the-playbook-1"></div>
<p>Now, let’s run the playbook:</p>
<pre><code class="language-bash">$ ansible-playbook playbook_env_persistent.yml -i inventory
PLAY [Ansible define a persistent environment variable] ***********************************************************************
TASK [Gathering Facts] ********************************************************************************************************
ok: [localhost]
TASK [Set environment variable in config file] ********************************************************************************
changed: [localhost]
PLAY RECAP ********************************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
</code></pre>
<p>According to the output, the tasks ran successfully. Let’s check the last line of <em>/home/baeldung/.bashrc</em> using the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/head-tail-commands#tail"><em>tail</em></a> command:</p>
<pre><code class="language-bash">$ tail -1 /home/baeldung/.bashrc
export ENV_VARIABLE=SYSTEM_LEVEL
</code></pre>
<p>The last line of the file contains the <em>export</em> command we appended, as expected. Let’s also verify that the environment variable, <em>ENV_VARIABLE</em>, is defined using the <em>echo</em> command in a new terminal:</p>
<pre><code class="language-bash">$ echo $ENV_VARIABLE
SYSTEM_LEVEL
</code></pre>
<p>The environment variable is defined and has the expected value.</p>
<h2 id="bd-conclusion" data-id="conclusion">4. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we discussed how to set both temporary and permanent environment variables using Ansible. Firstly, we learned that we can use the <em>environment</em> keyword to define temporary environment variables within an Ansible playbook, both at play and task levels. We saw that if we use the same name for an environment variable at the play and task levels simultaneously, the one at the task level overrides the other one.</p>
<p>Then, we learned that we must export an environment variable in one of the configuration scripts to have a permanent effect. We used <em>.bashrc</em> in the example. We saw that we can use the built-in <em>lineinfile</em> module for appending the <em>export</em> statement to the end of the file.</p>
<p><span lang="EN-GB">Although we didn’t use a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_blocks.html">block</a> in the example playbooks, in addition to play and task levels, it’s also possible to define environment variables at a block level.</span></p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/925102127/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/925102127/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/925102127/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f02%2fOPS-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/925102127/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/925102127/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/925102127/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/ansible-docker-commands-execute">Run Docker Commands With Ansible</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/gocd-introduction">Introduction to GoCD</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/ops/gocd-introduction</feedburner:origLink>
		<title>Introduction to GoCD</title>
		<link>https://feeds.feedblitz.com/~/925047929/0/baeldung/ops~Introduction-to-GoCD</link>
		
		<dc:creator><![CDATA[Albert Stec]]></dc:creator>
		<pubDate>Fri, 19 Sep 2025 02:29:00 +0000</pubDate>
				<category><![CDATA[Deployment Tools]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[CI/CD]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/gocd-introduction</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" />Learn how GoCD can help with development through CICD pipeline creation, maintenance, and visualization.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/925047929/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/925047929/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f02%2fOPS-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/925047929/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/925047929/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/925047929/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/ansible-configuring-environment-variables">Configuring Environment Variables in Ansible</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/dotnet-publish-work">How Does Dotnet Publish Work</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction">1. Introduction</h2>
<div class="bd-anchor" id="introduction"></div>
<p><strong>Continuous integration and continuous development (<a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/ci-cd-best-practices">CICD</a>)</strong> is a standard practice in modern software development. Many different tools supporting CICD are available on the market &#8211; free, open-source, proprietary, subscription-based, and others. Choosing one can mean the difference between an easy-to-use and long-supported, stable product, in contrast to a tedious integration process.</p>
<p>In this tutorial, we&#8217;ll discuss the fundamentals, architecture, and ways of modeling pipelines of the GoCD open-source CICD server.</p>
<h2 id="bd-fundamentals" data-id="fundamentals">2. Fundamentals</h2>
<div class="bd-anchor" id="fundamentals"></div>
<p><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.gocd.org/">GoCD</a> is an open-source tool by ThoughtWorks. Its task is to support programming teams in automating processes related to building, testing, and implementing applications.</p>
<h3 id="bd-1-pipelines" data-id="1-pipelines">2.1. Pipelines</h3>
<div class="bd-anchor" id="1-pipelines"></div>
<p>As already mentioned, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/gitlab-multiple-pipelines-same-repository">pipelines</a> are the central concept of GoCD. <strong>Pipelines are defined as chains of steps that open the way to streamlined development</strong>. For instance, each pipeline may include subsequent stages:</p>
<ul>
<li>downloading the source code</li>
<li>compilation process</li>
<li>running tests</li>
<li>deployment on the server</li>
</ul>
<p>Thanks to this, the whole process is more organized and easier to recreate.</p>
<h3 id="bd-2-visualization" data-id="2-visualization">2.2. Visualization</h3>
<div class="bd-anchor" id="2-visualization"></div>
<p>Another important aspect is the <strong>emphasis on the visualization of the flow of work</strong>. The graphical interface clearly shows how each pipeline is connected to the others and which tasks have already been completed, as well as which tasks are still pending. This approach makes the tool work well in complex projects.</p>
<h3 id="bd-3-pipeline-as-code" data-id="3-pipeline-as-code">2.3. Pipeline as Code</h3>
<div class="bd-anchor" id="3-pipeline-as-code"></div>
<p><strong>The next important feature of GoCD is the support for the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-scripted-vs-declarative-pipelines">pipeline-as-code</a> approach</strong>. The definition of pipelines can be written in JSON files and stored in the repository next to the source code. Thanks to this, CICD processes can have versions like the application, which makes it easier to maintain and transfer between environments.</p>
<p>In effect, GoCD is a tool that works well wherever the process of providing programming is deployed and requires clear modeling and full transparency.</p>
<h2 id="bd-architecture" data-id="architecture">3. Architecture</h2>
<div class="bd-anchor" id="architecture"></div>
<p><strong>GoCD is based on a client-server architecture, where GoCD serves as the central component</strong>. It&#8217;s responsible for storing configurations, managing pipelines, and visualizing the entire delivery process. The users interact with the server using a web panel, where they can define stages, monitor progress, and diagnose possible problems.</p>
<h3 id="bd-1-agents" data-id="1-agents">3.1. Agents</h3>
<div class="bd-anchor" id="1-agents"></div>
<p>Further, GoCD <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/gitlab-runner-guide">agents</a> are responsible for performing specific tasks. These are light processes that run on many machines, both local and in the cloud. <strong>The agent collects orders from the server and executes them</strong>.</p>
<p>Thus, users can scale the environment simply and perform tests or the process of building an application simultaneously.</p>
<h3 id="bd-2-pipeline-composition" data-id="2-pipeline-composition">3.2. Pipeline Composition</h3>
<div class="bd-anchor" id="2-pipeline-composition"></div>
<p>As already mentioned, the central element of the GoCD work is pipelines. They are divided into stages, which, in turn, consist of jobs, the smallest units of work. Thus, such a hierarchy enables users to model even complex processes transparently.</p>
<p><strong> Pipelines rely on so-called materials, i.e., sources from which input data is collected</strong>. Most often, this is a Git repository, but it&#8217;s also possible to use other version control systems, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/gitlab-pass-artifacts-stage-job">artifact</a> archives, or even external resources.</p>
<p>Thanks to this, GoCD can respond to changes in many sources at the same time:</p>
<img loading="lazy" decoding="async" class="aligncenter wp-image-139056" src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/09/pipeline-build.png" alt="Pipeline in GoCD" width="1356" height="618" />
<p>Notably, all these elements are closely related. <strong>The server manages the flow of data and dependencies, agents perform tasks, and pipelines organize logical stages</strong>.</p>
<p>Thanks to this, the GoCD architecture remains fairly simple to understand and at the same time provides a lot of flexibility even when modeling very extensive flows.</p>
<h2 id="bd-pipeline-creation" data-id="pipeline-creation">4. Pipeline Creation</h2>
<div class="bd-anchor" id="pipeline-creation"></div>
<p>Pipeline in GoCD is the fundamental element of working with the tool. Using pipelines, we can define the full process of building, testing, and deploying the application.</p>
<h3 id="bd-1-stages" data-id="1-stages">4.1. Stages</h3>
<div class="bd-anchor" id="1-stages"></div>
<p><strong>The basic organizational unit is the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/jenkins-pipeline-dynamic-stages">stage</a></strong>. It&#8217;s a group of tasks that run sequentially. <strong>The stage contains one or more jobs, and each job consists of specific tasks</strong>, such as running compilations, performing tests, or building a container image.</p>
<p>This division enables precise control of the process and clearly separates individual steps. The definition of a pipeline can be created directly in the GoCD web panel. This approach is convenient at the beginning of the work because it enables users to quickly understand the structure and mechanisms of the tool.</p>
<h3 id="bd-2-pipeline-as-json-and-yaml" data-id="2-pipeline-as-json-and-yaml">4.2. Pipeline as JSON and YAML</h3>
<div class="bd-anchor" id="2-pipeline-as-json-and-yaml"></div>
<p><strong>In practice, however, the pipeline-as-code approach is increasingly used, in which the configuration is saved in a YAML or JSON file and stored in the repository along with the source code</strong>. Thanks to this, it&#8217;s easier to version it and also transfer it between different environments.</p>
<p>Let&#8217;s see an example fragment of the pipeline definition in YAML format:</p>
<pre><code class="language-yaml">pipelines:
  sample-app:
    group: ExampleGroup
    materials:
      git:
        url: https://github.com/example/app.git
    stages:
      - build:
          jobs:
            compile:
              tasks:
                - exec:
                    command: ./gradlew build</code></pre>
<p>In this example, a simple pipeline called <em>sample-app</em> was defined. It uses a Git repository as input material. Through that, it runs a single-stage build, in which the task is to execute the commands compiling the project. Although it&#8217;s a minimal configuration, it shows the basic rules for defining processes in GoCD well.</p>
<p><strong>Expanded pipelines can take many stages and use various sources of materials</strong>. It&#8217;s also possible to create dependencies between pipelines, which enables building entire supply chains, including unit tests, integration tests, and production deployment.</p>
<h2 id="bd-benefits-and-limitations" data-id="benefits-and-limitations">5. Benefits and Limitations</h2>
<div class="bd-anchor" id="benefits-and-limitations"></div>
<p>GoCD has many features that distinguish it from other CICD tools.</p>
<h3 id="bd-1-benefits" data-id="1-benefits">5.1. Benefits</h3>
<div class="bd-anchor" id="1-benefits"></div>
<p>The most often weighted advantage is the transparent visualization of pipelines, thanks to which even complex delivery processes are often easier to understand and monitor.</p>
<p>Next, <strong>support for dependency between pipelines makes the tool useful in large projects</strong>, where it is necessary to strictly control subsequent actions. Further, the pipeline as a code approach enables versioning the configuration and maintaining its consistency in all environments.</p>
<p><strong>Scalability is achieved through the GoCD agents and the ability to integrate with numerous external systems, also playing a pivotal role</strong>.</p>
<h3 id="bd-2-limitations" data-id="2-limitations">5.2. Limitations</h3>
<div class="bd-anchor" id="2-limitations"></div>
<p>On the other hand, GoCD isn&#8217;t without limitations. Compared to tools such as <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/gitlab-ci-jenkins-differences-comparison">Jenkins or GitLab CI</a>, it has a less active community and a poorer plugin system. The result may mean that unusual scenarios can make it difficult to find a ready-made solution or documentation support.</p>
<p>Another barrier is the learning curve, i.e., the entry threshold. Especially for teams coming from simpler CICD systems, <strong>the implementation and understanding of GoCD architecture may be time-consuming</strong>. Some functions may also seem less intuitive.</p>
<p>In summary, GoCD is a tool with great possibilities and unique advantages, but at the same time requires a larger team to invest in learning and maintenance. It does best in environments where transparency and control over the deployment process are more important than the availability of ready-made plugins or a quick start.</p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we discussed GoCD. <strong>GoCD is a well-developed and transparent tool supporting CICD processes</strong>. Thanks to its model based on pipelines, it naturally visualizes the next stages of application development, from building and testing to production deployment. Its flexibility makes it work well in both small projects and large organizations, where the ability to control and visualize the entire process is important.</p>
<p>Although GoCD requires some initial configuration and learning of specific terminology, in return, it offers a lot of transparency, integration with other tools, and stability. It&#8217;s worth considering GoCD as an alternative to other CICD systems, especially when the key is a readable and graphical representation of flows and easy management of expanded pipelines.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/925047929/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/925047929/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/925047929/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f02%2fOPS-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/925047929/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/925047929/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/925047929/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/ansible-configuring-environment-variables">Configuring Environment Variables in Ansible</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/dotnet-publish-work">How Does Dotnet Publish Work</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/ops/docker-container-perf-cost</feedburner:origLink>
		<title>What Is the Runtime Performance Cost of a Docker Container?</title>
		<link>https://feeds.feedblitz.com/~/924828113/0/baeldung/ops~What-Is-the-Runtime-Performance-Cost-of-a-Docker-Container</link>
		
		<dc:creator><![CDATA[Johnson Fabowale]]></dc:creator>
		<pubDate>Mon, 15 Sep 2025 03:54:40 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker Container]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/docker-container-perf-cost</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" />Explore factors that contribute to Docker's runtime performance cost and learn practical steps to optimize performance.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/924828113/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/924828113/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fOPS-Featured-Image-05-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/924828113/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/924828113/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/924828113/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-google-chrome-headless">Run Google Chrome headless in Docker</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-build-run-format-error">Docker Build and Run Platforms and Resolving exec /usr/bin/sh: exec format error</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/docker-guide">Docker</a> containers are now an essential part of modern development and operations (DevOps) workflows, providing isolated environments for applications that are portable and lightweight. As these containers move into production, it becomes important to understand their runtime performance costs. While they deliver flexibility and efficiency, they also <strong>introduce some overhead compared to running directly on the host system.</strong></p>
<p>In this tutorial, we&#8217;ll explore these performance costs, focusing on CPU, memory, storage, and networking. We&#8217;ll also look at how Docker manages resources and practical steps to optimize performance in containerized environments.</p>
<h2 id="bd-understanding-docker-containers" data-id="understanding-docker-containers">2. Understanding Docker Containers</h2>
<div class="bd-anchor" id="understanding-docker-containers"></div>
<p>To begin with, let&#8217;s understand how Docker <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/docker-images-vs-containers">containers</a> work at a high level. They&#8217;re lightweight, portable, and provide process isolation using Linux namespaces and cgroups. These features allow multiple containers to run on the same host without interfering with each other.</p>
<p>Containers share the host OS kernel, which makes them more efficient than traditional virtual machines (VMs) that run their own OS instances. However, this shared environment also means that containers rely on the host system&#8217;s resources, which can impact performance under certain conditions.</p>
<h2 id="bd-factors-behind-dockers-runtime-performance-cost" data-id="factors-behind-dockers-runtime-performance-cost">3. Factors Behind Docker’s Runtime Performance Cost</h2>
<div class="bd-anchor" id="factors-behind-dockers-runtime-performance-cost"></div>
<p>Although Docker containers are designed to be lightweight, they still introduce performance trade-offs. Several factors drive this runtime cost, such as CPU overhead, memory usage, I/O performance, and network latency.</p>
<p>Let&#8217;s break down how each of these comes into play.</p>
<h3 id="bd-1-cpu-overhead" data-id="1-cpu-overhead">3.1. CPU Overhead</h3>
<div class="bd-anchor" id="1-cpu-overhead"></div>
<p>Docker containers rely on the host machine&#8217;s CPU to execute processes. In theory, containers should have little to no CPU overhead compared to traditional processes, as they run directly on the host kernel. However, in practice, the CPU overhead can occur due to several reasons:</p>
<ul>
<li><strong>Context Switching</strong>: When <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/docker-share-volume-multiple-containers">multiple containers</a> share CPU resources, the host operating system may have to frequently switch between them, causing context switching overhead.</li>
<li><strong>Cgroup Resource Limiting</strong>: Docker uses cgroups (control groups) to manage and limit the CPU usage of containers. This introduces some overhead, especially when strict limits are set. If a container is constrained to a limited CPU resource, like limiting the container to one <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/cs/core-vs-cpu">CPU core</a>, Docker may introduce some performance degradation due to CPU throttling.</li>
<li><strong>CPU Pinning</strong>: In some high-performance use cases, CPU pinning (binding a container to specific CPU cores) may be used to ensure predictable performance. While this can mitigate the impact of context switching, improper CPU pinning can also lead to inefficient resource usage.</li>
</ul>
<h3 id="bd-2-memory-usage" data-id="2-memory-usage">3.2. Memory Usage</h3>
<div class="bd-anchor" id="2-memory-usage"></div>
<p>Memory management in Docker containers can add overhead, especially when compared to traditional bare-metal processes. Let&#8217;s see how this is possible:</p>
<ul>
<li><strong>Shared Memory (Kernel vs. User Space)</strong>: Docker containers share the host kernel&#8217;s memory but run in their own user space. This can lead to some inefficiencies in memory management, particularly when the containers are handling large amounts of data.</li>
<li><strong>Memory Overcommitment</strong>: By default, Docker doesn&#8217;t strictly enforce memory limits unless we set them. When multiple containers run at the same time and some consume more memory than expected, Docker can end up overcommitting memory. This not only hurts performance but, in extreme cases, can cause containers to be terminated with out-of-memory errors.</li>
<li><strong>Swap Usage</strong>: When we set memory limits and containers go beyond their allocation, Docker falls back to swap space if it&#8217;s available. Since swap is much slower than physical RAM, this can quickly drag down performance.</li>
</ul>
<h3 id="bd-3-io-performance" data-id="3-io-performance">3.3. I/O Performance</h3>
<div class="bd-anchor" id="3-io-performance"></div>
<p>Disk I/O performance plays a critical role in the runtime cost of Docker containers. Since containers handle I/O through volumes or bind mounts, some extra overhead comes into play. Let&#8217;s break down what this means:</p>
<ul>
<li><strong>Storage Drivers</strong>: Docker uses different storage drivers to manage how container data is stored on disk, such as OverlayFS, aufs, etc. Each storage driver has its own performance characteristics, and some drivers, like OverlayFS, can offer better performance than others.</li>
<li><strong>Bind Mounts vs. Volumes</strong>: Containers can access files via bind mounts or Docker volumes. Bind mounts can incur additional overhead if the underlying filesystem on the host isn&#8217;t optimized for the operations that the container is performing. Volumes are managed by Docker, and their performance is generally better since Docker optimizes them for containerized workloads.</li>
<li><strong>File System Overhead</strong>: Containers using their own file system layers, such as OverlayFS can face performance penalties, especially for read/write-heavy operations. Copy-on-write (COW) operations, which are typical in Docker&#8217;s <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://docs.docker.com/engine/storage/">storage</a> model, can result in extra overhead when data is modified within containers.</li>
</ul>
<h3 id="bd-4-network-latency-and-overhead" data-id="4-network-latency-and-overhead">3.4. Network Latency and Overhead</h3>
<div class="bd-anchor" id="4-network-latency-and-overhead"></div>
<p>Networking in Docker containers introduces its own overhead because of how Docker isolates containers within virtual networks:</p>
<ul>
<li style="font-weight: 400"><strong>Network Bridges</strong>: By default, Docker containers are connected to a bridge network, which introduces network routing overhead. The performance cost is usually minimal, but for high-performance applications that require low-latency networking, this can be a factor.</li>
<li style="font-weight: 400"><strong>NAT and IP Tables</strong>: Docker containers rely on Network Address Translation (NAT) and IP tables for network isolation. The additional layer of NAT can introduce slight delays, especially when containers communicate with external resources.</li>
<li style="font-weight: 400"><strong>Container Networking Mode</strong>: We can choose between host, bridge, or overlay networking. For example, host networking reduces overhead since the container shares the host&#8217;s network stack directly. The trade-off, however, is weaker isolation.</li>
</ul>
<h2 id="bd-best-practices-to-reduce-dockers-runtime-cost" data-id="best-practices-to-reduce-dockers-runtime-cost">4. Best Practices to Reduce Docker’s Runtime Cost</h2>
<div class="bd-anchor" id="best-practices-to-reduce-dockers-runtime-cost"></div>
<p>Docker containers bring a lot of flexibility, but they also introduce a level of runtime overhead. The good news is that with the right practices, we can reduce this cost and keep performance close to native. Let&#8217;s walk through some proven strategies that make a meaningful difference.</p>
<h3 id="bd-1-resource-limiting-and-allocation" data-id="1-resource-limiting-and-allocation">4.1. Resource Limiting and Allocation</h3>
<div class="bd-anchor" id="1-resource-limiting-and-allocation"></div>
<p>One of the first steps to improving performance is making sure containers use resources efficiently. Without limits, a single container can hog CPU or memory and starve others running on the same host.</p>
<ul>
<li><strong>Setting CPU Limits Wisely: </strong>Applying CPU limits helps prevent noisy neighbors. Techniques like CPU pinning can also improve consistency in latency-sensitive workloads.</li>
<li><strong>Controlling Memory Usage</strong>: Defining memory limits ensures containers don’t take more than their fair share. Swap space should be configured carefully, since it&#8217;s slower than RAM and can degrade performance if overused. Monitoring usage over time helps fine-tune these limits as workloads evolve.</li>
</ul>
<h3 id="bd-2-storage-optimization" data-id="2-storage-optimization">4.2. Storage Optimization</h3>
<div class="bd-anchor" id="2-storage-optimization"></div>
<p>Storage I/O can make or break containerized applications, especially those handling large datasets or transaction-heavy operations.</p>
<ul>
<li style="font-weight: 400"><strong>Choosing the Right Storage Driver</strong>: We get better results when the storage driver matches the workload. OverlayFS works well for general use, while specialized workloads (like databases) benefit from testing and benchmarking before committing.</li>
<li style="font-weight: 400"><strong>Using Volumes Over Bind Mounts</strong>: Docker volumes are designed for performance and management efficiency, making them preferable to bind mounts, which often add unnecessary overhead.</li>
<li style="font-weight: 400"><strong>Reducing I/O Overhead</strong>: We can improve efficiency by minimizing frequent disk reads and writes. Frequently accessed data is best handled in memory or cache layers.</li>
</ul>
<h3 id="bd-3-network-optimization" data-id="3-network-optimization">4.3. Network Optimization</h3>
<div class="bd-anchor" id="3-network-optimization"></div>
<p>Networking is another area where containers can introduce latency. The way containers are connected to networks has a direct impact on performance.</p>
<ul>
<li style="font-weight: 400"><strong>Leveraging Host Networking</strong>: When low latency is critical, host networking reduces overhead by removing virtual bridge layers. The trade-off is weaker isolation, so it works best in selective cases.</li>
<li style="font-weight: 400"><strong>Optimizing Container-to-Container Traffic</strong>: Performance improves when services that communicate heavily run on the same Docker network. At the infrastructure level, robust NICs and switches help handle expected traffic loads effectively.</li>
</ul>
<h3 id="bd-4-monitoring-and-performance-tuning" data-id="4-monitoring-and-performance-tuning">4.4. Monitoring and Performance Tuning</h3>
<div class="bd-anchor" id="4-monitoring-and-performance-tuning"></div>
<p>Optimization doesn&#8217;t end with initial setup. Continuous monitoring allows us to detect bottlenecks early and tune workloads before they escalate into production issues.</p>
<ul>
<li><b>Monitoring with <em>docker stat</em></b><span style="font-weight: 400">: The <em>docker stats</em> command provides real-time visibility into CPU, memory, and I/O usage, helping us spot bottlenecks early.</span></li>
<li><strong>Adopting Monitoring Stacks: </strong>Tools like <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/spring-boot-prometheus">Prometheus</a>, Grafana, and cAdvisor give deeper insights with long-term metrics and dashboards, moving us from reactive troubleshooting to proactive optimization.</li>
</ul>
<h2 id="bd-conclusion" data-id="conclusion">5. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we explored how CPU, memory, storage, and networking contribute to Docker&#8217;s runtime performance cost. Containers provide portability and isolation, but they also introduce some overhead compared to running applications directly on the host.</p>
<p>By setting smart resource limits, optimizing storage and networking, and monitoring performance closely, we can reduce these costs and keep containers running efficiently in production. With the right practices, Docker delivers both flexibility and strong performance.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/924828113/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/924828113/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/924828113/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fOPS-Featured-Image-05-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/924828113/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/924828113/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/924828113/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-google-chrome-headless">Run Google Chrome headless in Docker</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-build-run-format-error">Docker Build and Run Platforms and Resolving exec /usr/bin/sh: exec format error</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/ops/docker-build-run-format-error</feedburner:origLink>
		<title>Docker Build and Run Platforms and Resolving exec /usr/bin/sh: exec format error</title>
		<link>https://feeds.feedblitz.com/~/924429560/0/baeldung/ops~Docker-Build-and-Run-Platforms-and-Resolving-exec-usrbinsh-exec-format-error</link>
		
		<dc:creator><![CDATA[Hiks Gerganov]]></dc:creator>
		<pubDate>Sat, 06 Sep 2025 06:29:25 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Errors]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/docker-build-run-format-error</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/01/Docker-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" />Explore Docker build and run platforms, along with errors that they might lead to. Further, learn about alternative reasons for exec format error issues.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/924429560/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/924429560/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f01%2fDocker-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/924429560/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/924429560/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/924429560/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-compose-no-config-file">Troubleshooting the no configuration file provided: not found Error in Docker Compose</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-container-perf-cost">What Is the Runtime Performance Cost of a Docker Container?</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/01/Docker-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2024/01/Docker-Featured-Image-02-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/01/Docker-Featured-Image-02-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/01/Docker-Featured-Image-02-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/01/Docker-Featured-Image-02-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/01/Docker-Featured-Image-02.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction">1. Introduction</h2>
<div class="bd-anchor" id="introduction"></div>
<p>As a breakthrough containerization tool based on Linux features, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/docker-guide">Docker</a> supports different architectures for both its core and containers. These are sometimes interchangeable, but could depend on certain conditions like executable file formats, layer abstractions, configuration, and others.</p>
<p>In this tutorial, <strong>we address platform management when building or running a Docker container, as well as the execution format error that may occur in certain scenarios</strong>. First, we build and run a sample Docker image via a Dockerfile to see each step. After that, we understand how and when the target or execution platform can be specified during this process. Next, we go through the consequences of mismatched build and run platforms. Finally, we delve into other reasons for getting an <em>exec format error</em>.</p>
<p>We tested the code in this tutorial on Debian 12 (Bookworm) with GNU Bash 5.2.15. Unless otherwise specified, it should work in most POSIX-compliant environments.</p>
<h2 id="bd-docker-image-build-and-run" data-id="docker-image-build-and-run">2. Docker Image Build and Run</h2>
<div class="bd-anchor" id="docker-image-build-and-run"></div>
<p>To create a Docker container, one usually first fetches or builds a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/dive-container-diff#docker-container-image">Docker image</a>. For that, a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/docker-dockerfile-docker-compose#dockerfile">Dockerfile</a> is commonly the way to go.</p>
<h3 id="bd-1-sample-dockerfile" data-id="1-sample-dockerfile">2.1. Sample Dockerfile</h3>
<div class="bd-anchor" id="1-sample-dockerfile"></div>
<p>Let&#8217;s create a simple Dockerfile for demonstration purposes:</p>
<pre><code class="language-shell">$ cat Dockerfile
FROM debian:bookworm-slim
RUN apt-get update
RUN apt-get install -y curl
RUN curl https://gerganov.com/ &gt; response
CMD ["sh"]</code></pre>
<p>This image blueprint is based on the <em>slim</em> version of the current latest Debian distribution. It downloads the most recent <em>curl</em> package and dumps an HTTP response to a file.</p>
<p>Notably, <strong><em>CMD</em> sets <em>sh</em> as the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/shells-count-command-run#shells">shell</a> to use, i.e., runs that process if no other process is specified</strong>.</p>
<h3 id="bd-2-image-build" data-id="2-image-build">2.2. Image Build</h3>
<div class="bd-anchor" id="2-image-build"></div>
<p>After creating a Dockerfile, we can initiate a build.</p>
<p>To do so, <strong>let&#8217;s issue the <em>docker</em> command with the <em>build</em> or <em>buildx build</em> subcommand</strong>:</p>
<pre><code class="language-shell">$ docker buildx build -t samplex-app .</code></pre>
<p>In this case, we name (or [<em>-t</em>]ag) the image as <em>samplex-app</em>. The <em>.</em> period indicates that the Dockerfile is in the current directory.</p>
<p>At this point, we should have an image available in the local registry.</p>
<h3 id="bd-3-run-container" data-id="3-run-container">2.3. Run Container</h3>
<div class="bd-anchor" id="3-run-container"></div>
<p>Once we have an image, let&#8217;s run it via the <em>run</em> subcommand of the <em>docker</em> command:</p>
<pre><code class="language-shell">$ docker run -it samplex-app</code></pre>
<p>Here, we create an [<em>-i</em>]nteractive [<em>-t</em>]erminal session for communication with the container after it initiates. Thus, we usually see a prompt:</p>
<pre><code class="language-shell">#</code></pre>
<p>Of course, this series of steps occurs during a successful workflow. Sometimes, the resulting image can be incompatible with the run environment.</p>
<h2 id="bd-container-architecture-platform-specification" data-id="container-architecture-platform-specification">3. Container Architecture Platform Specification</h2>
<div class="bd-anchor" id="container-architecture-platform-specification"></div>
<p>Since Linux exists on many architectures, containers can be built for and run on any of them.</p>
<p>In fact, <strong>we can both build and use containers meant for one architecture on others</strong>. For that, we need to configure the <em>binfmt_misc</em> kernel feature. It enables the recognition and execution of binaries for different architectures via emulators such as <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/qemu-from-terminal">QEMU</a>. This way, we might be able to run a PowerPC or ARM container within an x86 environment.</p>
<h3 id="bd-1-the---platform-parameter" data-id="1-the---platform-parameter">3.1. The <em>&#8211;platform</em> Parameter</h3>
<div class="bd-anchor" id="1-the---platform-parameter"></div>
<p>Although it works in different settings, the <em>&#8211;platform</em> parameter always has the same syntax for its options:</p>
<pre><code class="language-shell">--platform &lt;OS&gt;/&lt;ARCHITECTURE&gt;[/&lt;VARIANT&gt;]</code></pre>
<p>Let&#8217;s see a breakdown of each part:</p>
<ul>
<li><em>OS</em>: <em>linux</em>, <em>windows</em>, <em>darwin</em></li>
<li><em>ARCHITECTURE</em>: <em>amd64</em>, <em>arm64</em>, <em>arm</em>, <em>386</em>, and others</li>
<li><em>VARIANT</em> (optional): <em>v3</em>, <em>v5</em>, and similar</li>
</ul>
<p>For instance, <strong><em>linux/amd64</em> is perhaps one of the most common desktop or server platforms</strong>. Something like <em>linux/arm64</em> indicates a 64-bit ARM architecture such as that of the Raspberry PI v4 (also known as <em>aarch64</em>). Older ARM platforms are <em>linux/arm/v6</em> and <em>linux/arm/v7</em>.</p>
<h3 id="bd-2-build-time-platform" data-id="2-build-time-platform">3.2. Build-Time Platform</h3>
<div class="bd-anchor" id="2-build-time-platform"></div>
<p><strong>The default target platform for builds is usually the native one of the host</strong>.</p>
<p>To ensure we can specify a given platform during the build process, we must use <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/docker-buildx"><em>buildx</em></a>, because the regular <em>build</em> subcommand doesn&#8217;t have that option:</p>
<pre><code class="language-shell">$ docker buildx build --platform [...]</code></pre>
<p>In addition, <strong>the <em>buildx build</em> subcommand respects the <em>DOCKER_DEFAULT_PLATFORM</em> environment variable</strong> for targeted builds when the <em>&#8211;platform</em> parameter is omitted:</p>
<pre><code class="language-shell">$ DOCKER_DEFAULT_PLATFORM='linux/arm' docker buildx build -t samplex-app .</code></pre>
<p>Either way, we ensure that the <em>platform</em> for the resulting image is set accordingly. Notably, with the proper setup, <strong>we can build for platforms different from that of the host via emulators like QEMU</strong>.</p>
<h3 id="bd-3-runtime-platform" data-id="3-runtime-platform">3.3. Runtime Platform</h3>
<div class="bd-anchor" id="3-runtime-platform"></div>
<p>When using the <em>run</em> subcommand of <em>docker</em>, we can indicate the platform we want the image to be fetched for, in case there are several:</p>
<pre><code class="language-shell">$ docker run --platform [...]</code></pre>
<p>Similar to <em>buildx build</em>, <strong>the <em>run</em> subcommand considers <em>DOCKER_DEFAULT_PLATFORM</em></strong> if <em>&#8211;platform</em> isn&#8217;t explicitly defined:</p>
<pre><code class="language-shell">$ DOCKER_DEFAULT_PLATFORM='linux/arm' docker run -it samplex-app</code></pre>
<p>While the parameter may look obsolete if there&#8217;s only one version or platform, it forces the <em>docker run</em> command to error out:</p>
<pre><code class="language-shell">no matching manifest for linux/arm64 in the manifest list entries</code></pre>
<p>This can be critical to ensure we don&#8217;t attempt to run an unsupported image. Of course, again, we can run container images for different platforms as long as the proper configuration (e.g., QEMU) is in place.</p>
<h3 id="bd-4-dockerfile-and-from" data-id="4-dockerfile-and-from">3.4. Dockerfile and <em>FROM</em></h3>
<div class="bd-anchor" id="4-dockerfile-and-from"></div>
<p>Furthermore, we can indicate a target platform via the <em>&#8211;platform</em> option in <em>FROM</em> when writing a Dockerfile:</p>
<pre><code class="language-shell">$ cat Dockerfile
FROM --platform= debian:bookworm-slim
[...]</code></pre>
<p>However, <strong>this method doesn&#8217;t specify the build target platform</strong>, only the platform of the fetched image. This is similar to the <em>run</em> subcommand parameter.</p>
<p>Still, <strong>we can access the current value of the <em>buildx</em> flag <em>&#8211;platform</em> inside the Dockerfile via the <em>TARGETPLATFORM</em> variable</strong>.</p>
<h3 id="bd-5-platform-support" data-id="5-platform-support">3.5. Platform Support</h3>
<div class="bd-anchor" id="5-platform-support"></div>
<p>What platforms are supported by a given Docker setup is determined by the specific installation. For instance, Docker Desktop already has support for <em>arm64</em> and <em>arm</em> out of the box.</p>
<p><strong>To get the support list for a given environment, we can use the <em>buildx</em> subcommand with <em>inspect</em></strong>:</p>
<pre><code class="language-shell">$ docker buildx inspect --bootstrap
[...]
Platforms: linux/amd64, linux/arm64, linux/arm/v7, linux/386, linux/ppc64le, linux/s390x, linux/riscv64</code></pre>
<p>Since we see a number of supported platforms on top of the native one, there seems to be a QEMU configuration in place.</p>
<p>In addition, <strong>we can check a specific image via the <em>imagetools</em> subcommand</strong>:</p>
<pre><code class="language-shell">$ docker buildx imagetools inspect &lt;IMAGE_NAME&gt;</code></pre>
<p>Similar to the <em>&#8211;bootstrap</em> inspection, the output contains a <em>Platform:</em> field with a list. The <em>docker image inspect</em> command should produce a similar result, albeit in a different format.</p>
<h2 id="bd-platform-mismatches" data-id="platform-mismatches">4. Platform Mismatches</h2>
<div class="bd-anchor" id="platform-mismatches"></div>
<p>Perhaps one of the main reasons for an <em>exec format error</em> when running a container is that <strong>the build platform doesn&#8217;t match the run platform</strong>. Let&#8217;s see how and when this happens.</p>
<h3 id="bd-1-basic-case" data-id="1-basic-case">4.1. Basic Case</h3>
<div class="bd-anchor" id="1-basic-case"></div>
<p>Of course, <strong>we might just insert an unexpected platform as the value of <em>&#8211;platform</em></strong>:</p>
<pre><code class="language-shell">$ docker run --platform=linux/ppc64le ppc64le/debian sh
[...]
Status: Downloaded newer image for ppc64le/debian:latest
exec /usr/bin/sh: exec format error</code></pre>
<p>In this case, <em>ppc64le</em> isn&#8217;t compatible with the native platform, and there is no emulation set up to handle that architecture.</p>
<p>Yet, how do we know what platform Docker expects? As already mentioned, <strong>the native build and run platform is that of the host, but we can check the support via <em>docker buildx inspect &#8211;bootstrap</em></strong> to see what other platforms are configured.</p>
<h3 id="bd-2-pull-the-wrong-image" data-id="2-pull-the-wrong-image">4.2. Pull the Wrong Image</h3>
<div class="bd-anchor" id="2-pull-the-wrong-image"></div>
<p>When using <em>FROM</em> within a Dockerfile, <strong>we might also set the wrong platform, resulting in the same problem</strong>:</p>
<pre><code class="language-shell">$ cat Dockerfile
FROM --platform=linux/ppc64le debian:bookworm-slim
CMD ["sh"]
$ docker buildx build -t bad-platform .
[...]
$ docker run bad-platform
WARNING: The requested image's platform (linux/ppc64le) does not match the detected host platform (linux/amd64/v3) and no specific platform was requested
exec /usr/bin/sh: exec format error</code></pre>
<p>So, a Dockerfile can also be the source of the mismatch.</p>
<h3 id="bd-3-hidden-runners" data-id="3-hidden-runners">4.3. Hidden Runners</h3>
<div class="bd-anchor" id="3-hidden-runners"></div>
<p>To complicate matters, some cloud and other container runner environments like AWS and GitLab offer options to pick the execution platform.</p>
<p>In these cases, <strong>we should manually ensure that the configured and built containers run in the respective environment</strong>. While we can create a Dockerfile that adapts, doing so isn&#8217;t trivial.</p>
<h2 id="bd-non-platform-reasons-for-exec-format-error" data-id="non-platform-reasons-for-exec-format-error">5. Non-Platform Reasons for <em>exec format error</em></h2>
<div class="bd-anchor" id="non-platform-reasons-for-exec-format-error"></div>
<p>Critically, format errors can be caused by more than architecture mismatches. Let&#8217;s briefly take a look at other triggers for the same issue.</p>
<h3 id="bd-1-bad-script-header" data-id="1-bad-script-header">5.1. Bad Script Header</h3>
<div class="bd-anchor" id="1-bad-script-header"></div>
<p>When dealing with containers, we often create scripts that should run within them.</p>
<p>In Linux, <strong>the first line of scripts can be a special header called a <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/shebang">shebang</a></strong>:</p>
<pre><code class="language-shell">$ cat script.sh
#!/bin/bash
[...]</code></pre>
<p>The shebang contains the path to the correct interpreter of the respective script. It has very strict formatting rules:</p>
<ul>
<li>starts at the first character of the file</li>
<li>is allocated the whole first line</li>
<li>uses absolute paths</li>
<li>contains no unescaped space characters in the path</li>
<li>the comparison with <em>!#</em> is only for the first two (2) bytes</li>
</ul>
<p>Any deviation from the above, such as <strong>a missing shebang, space after <em>!#</em>, other characters on the first line, unexpected whitespace, or even an incorrect encoding, can cause an <em>exec format error</em></strong>:</p>
<pre><code class="language-shell">$ cat Dockerfile
FROM debian:bookworm-slim
RUN echo '#! /bin/sh\necho "bad"' &gt; /bad.sh
RUN chmod +x /bad.sh
CMD ["/bad.sh"]
$ docker buildx build -t badbang
[...]
$ docker run badbang
exec /bad.sh: exec format error</code></pre>
<p>Yet, confusingly, depending on the setup, terminal, and configuration, <strong>there might not be a problem when running the script directly on the host</strong>.</p>
<h3 id="bd-2-bad-file-permissions" data-id="2-bad-file-permissions">5.2. Bad File Permissions</h3>
<div class="bd-anchor" id="2-bad-file-permissions"></div>
<p>As usual on Linux and UNIX in general, file permissions dictate whether a file can run in a given context. Specifically, <strong>if a script isn&#8217;t marked as executable, attempting to run it directly results in an error</strong>:</p>
<pre><code class="language-shell">$ cat Dockerfile
FROM debian:bookworm-slim
RUN echo '#! /bin/sh\necho "norun"' &gt; /norun.sh
CMD ["/norun.sh"]
$ docker buildx build -t badbang
[...]
$ docker run badbang
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "/norun.sh": permission denied: unknown
Run 'docker run --help' for more information</code></pre>
<p>While this output doesn&#8217;t usually include the <em>exec format error</em> string, user reports state that it does so in some environments.</p>
<h2 id="bd-summary" data-id="summary">6. Summary</h2>
<div class="bd-anchor" id="summary"></div>
<p>In this article, we talked about Docker build and run platforms, along with errors that they might lead to. Further, we discussed alternative reasons for <em>exec format error</em> issues.</p>
<p>In conclusion, mismatches between the build and run platforms for a Docker container often lead to format errors, but that isn&#8217;t always the only reason to get them.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/924429560/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/924429560/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/924429560/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f01%2fDocker-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/924429560/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/924429560/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/924429560/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-compose-no-config-file">Troubleshooting the no configuration file provided: not found Error in Docker Compose</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-container-perf-cost">What Is the Runtime Performance Cost of a Docker Container?</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2024/01/Docker-Featured-Image-02-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/ops/github-actions-package-manager</feedburner:origLink>
		<title>Using a Package Manager in GitHub Actions</title>
		<link>https://feeds.feedblitz.com/~/924134489/0/baeldung/ops~Using-a-Package-Manager-in-GitHub-Actions</link>
		
		<dc:creator><![CDATA[Sidrah Abdullah]]></dc:creator>
		<pubDate>Sun, 31 Aug 2025 19:08:15 +0000</pubDate>
				<category><![CDATA[Deployment Tools]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Docker Container]]></category>
		<category><![CDATA[GitHub Actions]]></category>
		<category><![CDATA[Package Management]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/github-actions-package-manager</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" />Learn how to safely and wisely use a package manager within GitHub Actions.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/924134489/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/924134489/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fOPS-Featured-Image-05-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/924134489/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/924134489/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/924134489/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-pr-files-modified">Get Files Modified in a PR in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-private-docker-image">Use Private Docker Image in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-create-env-file">Using GitHub Actions to Create .env File in the Workflow</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction">1. Introduction</h2>
<div class="bd-anchor" id="introduction"></div>
<p><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/ci-cd-best-practices" target="_blank" rel="noopener">Continuous Integration</a> workflows often require external tools that aren&#8217;t available by default on the execution environment. <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/github-actions-workflow-locally" target="_blank" rel="noopener">GitHub Actions</a>, which provide hosted runners for building, testing, and deploying code, also require the same. To access these tools, we frequently use the Ubuntu <em>apt-get</em> package manager.</p>
<p>In this tutorial, <strong>we&#8217;ll discuss using a package manager in GitHub Actions</strong>. First, we&#8217;ll start by explaining its importance in workflows, and then examine practical usage within GitHub Actions. Lastly, we&#8217;ll discuss common errors that can occur when using <em><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/apt-vs-apt-get" target="_blank" rel="noopener">apt-get</a></em>.</p>
<h2 id="bd-package-installation-in-workflows" data-id="package-installation-in-workflows">2. Package Installation in Workflows</h2>
<div class="bd-anchor" id="package-installation-in-workflows"></div>
<p>When we run jobs on GitHub-hosted Ubuntu runners, <strong>each job begins in a clean virtual environment</strong>. To elaborate, the packages required for the task aren&#8217;t installed and need to be set up during the workflow. Installing packages ensures that the build environment meets the project requirements.</p>
<p>For example, a Python project may require <em>graphviz</em> to render documentation, a C++ project may need <em>lcov</em> for coverage analysis, and a Java project might require system-level libraries to compile native extensions. Without these, jobs would fail. Therefore, package installation becomes a critical step in CI.</p>
<p>While scripting, the question arises whether to use <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/debian-installing-packages-url#1-apt-advanced-packaging-tool"><em>apt</em></a> or <em>apt-get</em>. <em>apt-get</em> is generally preferred for scripting. <em>apt</em> is intended as a user-facing command with nicer output, while <em>apt-get</em> provides more stable, script-friendly behavior. For workflows where reproducibility matters, <em>apt-get</em> is the safer choice.</p>
<h2 id="bd-basic-example-setup" data-id="basic-example-setup">3. Basic Example Setup</h2>
<div class="bd-anchor" id="basic-example-setup"></div>
<p>To begin with, let&#8217;s consider a simple GitHub action where we install the <em>lcov</em> package, which is a tool for generating code coverage reports.</p>
<p>Let&#8217;s look at the <em>install.yaml</em>:</p>
<pre><code class="language-yaml">$ cat install.yaml
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install lcov
        run: |
          sudo apt-get update
          sudo apt-get install -y lcov
      - name: Run tests with coverage
        run: |
          ./scripts/run-tests.sh
          lcov --capture --directory . --output-file coverage.info
</code></pre>
<p>The above code checks out the repository, so the runner has the project code. After that, it installs <em>Icov</em> using <em>sudo apt-get</em> <em>update</em> followed by <em>sudo apt-get install -y lcov</em>. The <em>sudo</em> command is important because <em>apt-get</em> requires administrative privileges. The <em>-y</em> flag ensures the installation proceeds without waiting for confirmation. Lastly, <em>install.yaml</em> runs the tests and collects coverage data with the newly installed <em>Icov</em>.</p>
<p>In this basic example, the workflow runs smoothly. The tool is installed and is available immediately. In addition, later steps can use the installed package.</p>
<h2 id="bd-permission-error-in-github-actions" data-id="permission-error-in-github-actions">4. Permission Error in GitHub Actions</h2>
<div class="bd-anchor" id="permission-error-in-github-actions"></div>
<p>At first glance, installing packages in GitHub Actions seems straightforward. However, the first attempt to run <em>apt-get install</em> often fails, and leads to a specific error:</p>
<pre><code class="language-shell">E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?</code></pre>
<p>The issue arises because <strong>GitHub Actions jobs run as a non-<em>root</em> user by default</strong>. System package management with <em>apt-get</em> requires elevated privileges to modify <em>/var/lib/dpkg</em>. Since we aren&#8217;t <em>root</em>, the process cannot obtain the necessary lock.</p>
<p>To fix the above error, we can use the <em>sudo</em> command. Fortunately, GitHub&#8217;s Ubuntu runners enable passwordless <em>sudo</em>. To elaborate, we can run administrative commands without being prompted for a password. Therefore, <strong>the fix is often as simple as adding <em>sudo</em> to the install step</strong>.</p>
<h2 id="bd-performance-considerations" data-id="performance-considerations">5. Performance Considerations</h2>
<div class="bd-anchor" id="performance-considerations"></div>
<p>While the above method works, it can slow down workflows. Each run installs packages from scratch, which adds overhead, especially if the list of dependencies is long. To improve performance, we can apply several strategies discussed in this section.</p>
<h3 id="bd-1-grouping-packages" data-id="1-grouping-packages">5.1. Grouping Packages</h3>
<div class="bd-anchor" id="1-grouping-packages"></div>
<p>It&#8217;s faster to install multiple packages in one command rather than invoking <em>apt-get</em> multiple times.</p>
<p>For example, we can install <em>Icov</em>, <em>graphviz</em>, and <em>doxygen</em> together:</p>
<pre><code class="language-yaml">$ cat install.yaml
name: CI
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Install lcov
        run: |
          sudo apt-get update
          sudo apt-get install -y lcov graphviz doxygen
      - name: Run tests with coverage
        run: |
          ./scripts/run-tests.sh
          lcov --capture --directory . --output-file coverage.info</code></pre>
<p>Thus, we avoid repeating dependency resolution and reduce overhead.</p>
<h3 id="bd-2-caching-packages" data-id="2-caching-packages">5.2. Caching Packages</h3>
<div class="bd-anchor" id="2-caching-packages"></div>
<p>Another option is to use caching actions. The <em>cache-apt-pkgs-action</em> makes package installation faster by caching downloaded <em>.deb</em> files between runs.</p>
<p>Thus, <strong>we can include the caching option in the <em>uses</em> field within the <em>.yaml</em> file</strong>:</p>
<pre><code class="language-yaml">$ cat install.yaml
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          packages: dia doxygen doxygen-doc doxygen-gui doxygen-latex graphviz mscgen
          version: 1.0
      - name: Install lcov
        run: |
          sudo apt-get update
          sudo apt-get install -y lcov
...</code></pre>
<p>Here, the packages field lists the desired packages, and the version field serves as a manual cache key. Incrementing the version refreshes the cache when the package list changes. This reduces build times significantly for projects with heavy dependencies.</p>
<h3 id="bd-3-custom-containers" data-id="3-custom-containers">5.3. Custom Containers</h3>
<div class="bd-anchor" id="3-custom-containers"></div>
<p>​For projects requiring extensive system dependencies, we can use prebuilt containers, which are more efficient. By defining a container with all tools preinstalled, we avoid repeated installs in workflows.</p>
<p>The workflow then specifies those containers under the <em>build</em> section in the <em>.yaml</em> file:</p>
<pre><code class="language-yaml">$ cat install.yaml
name: CI
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    container: ghcr.io/my-org/custom-image:1.0
    steps:
      - uses: actions/checkout@v4
...</code></pre>
<p>This shifts installation overhead from every run to a one-time container build, improving both speed and reproducibility. The sacrifice is that the configuration is now in two separate places, and rebuilding <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/dive-container-diff#docker-container-image">container images</a> can be tedious if they change often.</p>
<h2 id="bd-best-practices" data-id="best-practices">6. Best Practices</h2>
<div class="bd-anchor" id="best-practices"></div>
<p>Across the different approaches to install packages in GitHub Actions, there are several best practices:</p>
<ul>
<li><strong>It&#8217;s always better to install only what&#8217;s necessary</strong>, since every extra package adds to build time and increases the risk of conflicts.</li>
<li><strong>We should keep the installations non-interactive</strong>, and that&#8217;s why flags like <em>-y</em> and the <em>DEBIAN_FRONTEND=noninteractive</em> setting are so valuable, since they prevent the workflow from hanging at unexpected prompts.</li>
<li>When stability is critical, <strong>it&#8217;s wise to pin package versions rather than relying on the latest available option</strong>, because reproducibility matters more than novelty in CI pipelines.</li>
<li><strong>It&#8217;s important to stay mindful of the runner image updates,</strong> since <em>ubuntu-latest</em> shifts over time, for example, from 20.04 to 22.04, and pinning a specific version can offer more predictable results.</li>
</ul>
<p>At the same time, we shouldn&#8217;t overlook the fact that dedicated setup actions for languages such as Python, Node, or Java, <em>actions/setup-python, actions/setup-node</em>, are often faster and more reliable than using system-level installs.</p>
<h2 id="bd-conclusion" data-id="conclusion">7. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, <strong>we covered how to use a package manager in GitHub Actions and pitfalls around such cases</strong>. First, we discussed why we use a package manager in GitHub Actions. After that, we covered an example of doing so. Lastly, we elaborated on the common errors and performance issues that arise when using <em>apt-get</em> in GitHub Actions and ways to fix or avoid them.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/924134489/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/924134489/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/924134489/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fOPS-Featured-Image-05-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/924134489/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/924134489/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/924134489/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-pr-files-modified">Get Files Modified in a PR in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-private-docker-image">Use Private Docker Image in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-create-env-file">Using GitHub Actions to Create .env File in the Workflow</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-05-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/ops/docker-desktop-error-while-executing-wsl-commandn</feedburner:origLink>
		<title>Troubleshooting ‘An Unexpected Error While Executing WSL Command’ in Docker Desktop</title>
		<link>https://feeds.feedblitz.com/~/923932157/0/baeldung/ops~Troubleshooting-%e2%80%98An-Unexpected-Error-While-Executing-WSL-Command%e2%80%99-in-Docker-Desktop</link>
		
		<dc:creator><![CDATA[Youssef Salem]]></dc:creator>
		<pubDate>Wed, 27 Aug 2025 21:53:50 +0000</pubDate>
				<category><![CDATA[Docker]]></category>
		<category><![CDATA[Docker Image]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/?p=94118</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Docker-Featured-Image-04-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" />Discover how Docker and WSL interact in order to troubleshoort this error: "An Unexpected Error While Executing WSL Command"<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/923932157/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/923932157/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fDocker-Featured-Image-04-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/923932157/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/923932157/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/923932157/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-container-perf-cost">What Is the Runtime Performance Cost of a Docker Container?</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-build-run-format-error">Docker Build and Run Platforms and Resolving exec /usr/bin/sh: exec format error</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Docker-Featured-Image-04-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Docker-Featured-Image-04-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Docker-Featured-Image-04-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Docker-Featured-Image-04-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Docker-Featured-Image-04-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Docker-Featured-Image-04-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Docker-Featured-Image-04.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p data-pm-slice="0 0 []">When working with <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/docker-guide">Docker</a> Desktop on Windows using the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/linux/windows-subsystem-explanation">WSL2</a> backend, Windows Subsystem for Linux, we may sometimes encounter a frustrating message, &#8220;An Unexpected Error Was Encountered While Executing a WSL Command&#8221;.</p>
<p data-pm-slice="0 0 []">This error can occur at almost any point. For example, it might occur when starting Docker Desktop, running <em>docker build</em>, pulling an image, or simply launching a container. <strong>Specifically, it stops our workflow abruptly and often leaves us wondering where to start.</strong></p>
<p>Fortunately, this error is often solvable.<strong> By understanding how Docker and WSL interact, and by following a methodical troubleshooting process, we can diagnose and fix the issue.</strong> In this tutorial, we will tackle this by explaining both the theory behind each step and the practical commands we can use to resolve it.</p>
<h2 id="bd-understanding-the-error" data-id="understanding-the-error">2. Understanding the Error</h2>
<div class="bd-anchor" id="understanding-the-error"></div>
<p data-pm-slice="0 0 []">There are multiple factors that lead to this issue. Before diving into fixes, <strong>let’s explore why WSL on our desktop is important</strong>:</p>
<ul>
<li data-pm-slice="0 0 []">WSL enables us to run Linux distributions natively on Windows without heavy virtual machines</li>
<li>WSL2 introduced a real Linux kernel running inside a lightweight virtual machine, improving performance and compatibility</li>
<li>Docker Desktop can use WSL2 as its backend instead of Hyper-V, which makes Linux containers run more efficiently and reduces overhead</li>
</ul>
<p data-pm-slice="0 0 []">However, Docker relies heavily on a stable WSL environment. In essence, if the WSL backend encounters issues, whether from corruption, outdated versions, or resource limits, we get this error.</p>
<p data-pm-slice="0 0 []">Next, <strong>there are a lot of common situations that trigger such an error</strong>:</p>
<ul>
<li data-pm-slice="0 0 []">Trying to run Docker when the WSL service is stopped</li>
<li>Running outdated WSL or Docker Desktop versions that no longer work well together</li>
<li>The <em>docker-desktop</em> or <em>docker-desktop-data</em> WSL distributions are being corrupted</li>
<li>Insufficient permissions for Docker to execute commands inside WSL</li>
<li>WSL is running out of allocated memory or CPU</li>
</ul>
<h2 id="bd-step-by-step-troubleshooting" data-id="step-by-step-troubleshooting">3. Step-by-Step Troubleshooting</h2>
<div class="bd-anchor" id="step-by-step-troubleshooting"></div>
<p data-pm-slice="0 0 []">In this section, we’ll follow a logical sequence starting from simple checks and moving toward more advanced fixes.</p>
<h3 data-pm-slice="0 0 []" id="bd-1-check-if-wsl-is-working" data-id="1-check-if-wsl-is-working">3.1. Check if WSL Is Working</h3>
<div class="bd-anchor" id="1-check-if-wsl-is-working"></div>
<p data-pm-slice="0 0 []">First, we&#8217;d better ensure that WSL itself is functional. For instance, if WSL is broken, Docker can&#8217;t work.</p>
<p data-pm-slice="0 0 []">The <em>wsl </em>PowerShell command validates WSL functionality:</p>
<pre><code class="language-powershell">$ wsl --list --verbose
  NAME                   STATE           VERSION
* Ubuntu                 Running         2
  docker-desktop         Running         2
  docker-desktop-data    Running         2
</code></pre>
<p><strong>Let&#8217;s understand what this command does and what benefit it brings</strong>:</p>
<ul>
<li data-pm-slice="0 0 []">lists all installed WSL distributions</li>
<li>shows their current state (<em>Running</em>/<em>Stopped</em>)</li>
<li>shows the WSL version (<em>1</em> or <em>2</em>)</li>
</ul>
<p>Looking at the output of this code snippet, we can easily spot that services like <em>docker-desktop</em> and <em>docker-desktop-data</em> are <em>Running</em>. If any of these services were showing a <em>Stopped</em> state, Docker can&#8217;t function properly. In particular, if any of the above services was in a <em>Stopped</em> state, we would better restart them:</p>
<pre><code class="language-bash">$ wsl --shutdown</code></pre>
<p data-pm-slice="0 0 []">Then we reopen Docker Desktop, which will automatically restart the required WSL services.</p>
<h3 id="bd-2-restart-wsl-services" data-id="2-restart-wsl-services">3.2. Restart WSL Services</h3>
<div class="bd-anchor" id="2-restart-wsl-services"></div>
<p>If WSL is indeed running, and we still get the error,<strong> we can try restarting WSL services:</strong></p>
<pre><code class="language-powershell">$ wsl --shutdown
</code></pre>
<p data-pm-slice="0 0 []">Essentially, this stops all WSL instances and frees up resources. In addition, when we start Docker Desktop again, it will restart the required WSL distributions automatically.</p>
<p data-pm-slice="0 0 []">Alternatively, restart the <em>LxssManager</em> service, which manages WSL:</p>
<ul>
<li>Press <em>Win + R</em>, then type <em>services.msc</em>, and press Enter</li>
<li>Find <em>LxssManager</em></li>
<li>Right-click, then choose <em>Restart</em></li>
</ul>
<p>This often clears temporary issues without touching configurations.</p>
<h3 id="bd-3-update-wsl-and-docker-desktop" data-id="3-update-wsl-and-docker-desktop">3.3. Update WSL and Docker Desktop</h3>
<div class="bd-anchor" id="3-update-wsl-and-docker-desktop"></div>
<p data-pm-slice="0 0 []">Consequently, if the above did not help, the suggestion would be to check for updates, as outdated software is one of the most common causes of this error.</p>
<p data-pm-slice="0 0 []">To avoid this, <strong>we always make sure our WSL version is up to date</strong>:</p>
<pre><code class="language-bash">$ wsl --update</code></pre>
<p data-pm-slice="0 0 []">This installs the latest Linux kernel and backend improvements. In addition, <strong>we update Docker Desktop by following a set of simple steps</strong>:</p>
<ul>
<li data-pm-slice="0 0 []">Open Docker Desktop</li>
<li>Go to Settings → General → Check for Updates</li>
<li>Install the latest version</li>
</ul>
<p>This matters because Docker and WSL updates often contain bug fixes and performance improvements. Particularly, <strong>if we’re running mismatched versions</strong>, <strong>commands can fail unexpectedly</strong>.</p>
<h3 id="bd-4-check-docker-windows-integration" data-id="4-check-docker-windows-integration">3.4. Check Docker-Windows Integration</h3>
<div class="bd-anchor" id="4-check-docker-windows-integration"></div>
<p>Essentially, Docker Desktop needs to know which WSL distributions it should work with. We can check whether it is configured correctly:</p>
<ul>
<li data-pm-slice="0 0 []">Open Docker Desktop</li>
<li>Navigate to Settings → Resources → WSL Integration</li>
<li>Make sure the Linux distribution we use (for example, Ubuntu) is enabled</li>
</ul>
<p data-pm-slice="0 0 []">If this is disabled, <strong>Docker won’t execute commands inside that distribution</strong>, <strong>leading to errors</strong>.</p>
<h3 id="bd-5-check-docker-logs" data-id="5-check-docker-logs">3.5. Check Docker Logs</h3>
<div class="bd-anchor" id="5-check-docker-logs"></div>
<p data-pm-slice="0 0 []">If the above steps don’t help, <strong>checking logs can give us clues:</strong></p>
<pre><code class="language-bash">$ wsl -d docker-desktop cat /var/log/docker.log
</code></pre>
<p data-pm-slice="0 0 []">This opens the Docker daemon log inside the WSL backend. Then, we look for any repeated error messages or permission issues.</p>
<h3 id="bd-6-adjust-wsl-resource-limits" data-id="6-adjust-wsl-resource-limits">3.6. Adjust WSL Resource Limits</h3>
<div class="bd-anchor" id="6-adjust-wsl-resource-limits"></div>
<p data-pm-slice="0 0 []">Sometimes, commands fail because WSL runs out of memory or CPU. Alternatively, we can configure resource limits by creating a <em>.wslconfig</em> file in our user profile directory:</p>
<pre><code class="language-ini">[wsl2]
memory=4GB
processors=2</code></pre>
<p data-pm-slice="0 0 []">Afterwards, we save the file as user <em>\.wslconfig</em> and we shut down WSL:</p>
<pre><code class="language-bash">$ wsl --shutdown
</code></pre>
<p data-pm-slice="0 0 []">Finally, we restart Docker Desktop to ensure Docker has enough resources to complete tasks.</p>
<h3 id="bd-7-inspect-dockerwsl-backend" data-id="7-inspect-dockerwsl-backend">3.7. Inspect Docker/WSL Backend</h3>
<div class="bd-anchor" id="7-inspect-dockerwsl-backend"></div>
<p data-pm-slice="0 0 []"><strong>If we suspect corruption, we can reset the Docker WSL distributions.</strong> Note that this will delete all our data, so if we want to do this, we first perform a backup:</p>
<p data-pm-slice="0 0 []"><code class="language-bash">$ docker save -o backup.tar image1</code></p>
<p data-pm-slice="0 0 []">This command saves a specified Docker image, including all its layers, metadata, and history, into a single tar archive file named <em>backup.tar</em>. Hence, we can use this archive for tasks like transferring images to systems without direct Docker registry access or creating backups of our Docker images. Finally, we can later load these images onto another Docker host using the <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/share-image-without-docker-hub#load-tararchive-into-the-docker-image"><em>docker load</em></a> command.</p>
<p data-pm-slice="0 0 []">Next, we can recreate the container:</p>
<pre><code class="language-bash">$ wsl --unregister docker-desktop
$ wsl --unregister docker-desktop-data
</code></pre>
<p data-pm-slice="0 0 []">When we restart Docker Desktop, it recreates these distributions.</p>
<h3 id="bd-8-reinstall-wsl-if-necessary" data-id="8-reinstall-wsl-if-necessary">3.8. Reinstall WSL if Necessary</h3>
<div class="bd-anchor" id="8-reinstall-wsl-if-necessary"></div>
<p data-pm-slice="0 0 []">As a last resort, if WSL itself is broken beyond repair, we can reinstall it:</p>
<pre><code class="language-bash">$ wsl --unregister &lt;distro-name&gt;
$ wsl --install
</code></pre>
<p data-pm-slice="0 0 []">We then reinstall Docker Desktop and reconfigure integration. This is extreme, but it guarantees a fresh environment.</p>
<h2 id="bd-preventive-measures" data-id="preventive-measures">4. Preventive Measures</h2>
<div class="bd-anchor" id="preventive-measures"></div>
<p>There are a lot of preventive measures we could take to avoid running into this issue:</p>
<ul>
<li data-pm-slice="0 0 []"><strong>Keep everything updated</strong> — run <em>wsl &#8211;update</em> monthly, and update Docker Desktop regularly</li>
<li><strong>Allocate enough resources</strong> — ensure <em>.wslconfig</em> values match the workloads we run</li>
<li><strong>Shut down cleanly</strong> — avoid force-closing Docker Desktop or turning off the PC abruptly</li>
<li><strong>Backup Docker images</strong> — periodically use <em>docker save</em> to preserve important images</li>
</ul>
<p>We could even run an automatic script to do the health check for us:</p>
<pre><code class="language-bash">Write-Host "Checking WSL status..."
wsl --list --verbose
Write-Host "`nRestarting WSL..."
wsl --shutdown
Write-Host "`nUpdating WSL..."
wsl --update
Write-Host "`nChecking Docker Desktop..."
&amp; "$Env:ProgramFiles\Docker\Docker\Docker Desktop.exe"
</code></pre>
<p>Next, let&#8217;s break down what it does:</p>
<ul>
<li data-pm-slice="0 0 []">Lists WSL distros and their states</li>
<li>Restarts WSL</li>
<li>Updates WSL to the latest version</li>
<li>Launches Docker Desktop</li>
</ul>
<p data-pm-slice="0 0 []">Running this before starting work can catch issues early.</p>
<h2 id="bd-conclusion" data-id="conclusion">5. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p data-pm-slice="0 0 []">In this article, we identified why Docker Desktop may show the &#8220;An unexpected error was encountered while executing a WSL command&#8221; message and outlined practical ways to fix it.</p>
<p>With simple checks, updates, and proper configuration, we can quickly restore Docker’s WSL integration and keep our environment stable.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/923932157/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/923932157/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/923932157/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fDocker-Featured-Image-04-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/923932157/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/923932157/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/923932157/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-container-perf-cost">What Is the Runtime Performance Cost of a Docker Container?</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/docker-build-run-format-error">Docker Build and Run Platforms and Resolving exec /usr/bin/sh: exec format error</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/Docker-Featured-Image-04-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/ops/dotnet-publish-work</feedburner:origLink>
		<title>How Does Dotnet Publish Work</title>
		<link>https://feeds.feedblitz.com/~/923705738/0/baeldung/ops~How-Does-Dotnet-Publish-Work</link>
		
		<dc:creator><![CDATA[John Caleb]]></dc:creator>
		<pubDate>Sun, 24 Aug 2025 00:00:00 +0000</pubDate>
				<category><![CDATA[Deployment Tools]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/dotnet-publish-work</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" />Explore what dotnet publish does, how it works behind the scenes, and how to use it efficiently in various deployment circumstances.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/923705738/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/923705738/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f02%2fOPS-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/923705738/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/923705738/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/923705738/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/ansible-configuring-environment-variables">Configuring Environment Variables in Ansible</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/gocd-introduction">Introduction to GoCD</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-overview" data-id="overview">1. Overview</h2>
<div class="bd-anchor" id="overview"></div>
<p>In <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://dotnet.microsoft.com/en-us/download">.NET</a> development, the <em>dotnet publish</em> command is essential for preparing applications for distribution. It builds the application, processes its dependencies, and stores the finished distributable assets in a specific location. This tool supports a variety of deployment targets, such as folders, <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/docker-images-vs-containers#docker-containers">containers</a>, and cloud environments.</p>
<p>In this tutorial, we&#8217;ll look at what <em>dotnet publish</em> does, how it works behind the scenes, and how to use it efficiently in various deployment circumstances.</p>
<h2 id="bd-what-happens-during-dotnet-publish" data-id="what-happens-during-dotnet-publish">2. What Happens During Dotnet Publish</h2>
<div class="bd-anchor" id="what-happens-during-dotnet-publish"></div>
<p>When we run <em>dotnet publish</em>, the CLI executes several processes that change our source code into a production-ready package:</p>
<pre><code class="language-bash">$ dotnet publish</code></pre>
<p>In this example, when we run the command, the dotnet CLI starts converting the project to <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/cs/how-compilers-work#4-intermediate-code-generation">Intermediate Language (IL) assemblies</a>. It then resolves all NuGet and project dependencies, ensuring that they work with the target framework. <strong>Following that, it moves the compiled binaries, configuration files, and static resources such as images or CSS to the publish folder.</strong></p>
<p>In addition, when a runtime identifier is supplied, it contains the corresponding .NET runtime. Finally, it optimizes the files if trimming or single-file publication is selected.</p>
<h2 id="bd-common-options-and-flags" data-id="common-options-and-flags">3. Common Options and Flags</h2>
<div class="bd-anchor" id="common-options-and-flags"></div>
<p>The <em>dotnet publish</em> command provides numerous arguments and <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://en.wikipedia.org/wiki/MSBuild">MSBuild</a> attributes for customising the output.</p>
<p>These options allow us to specify the build configuration, target runtime, deployment model, and even <strong>how the files are packed. We can adapt a single codebase to many contexts by mixing different flags</strong>:</p>
<pre><code class="language-bash">$ dotnet publish -c Release -o ./deploy</code></pre>
<pre><code class="language-bash">Determining projects to restore...
Restored /home/user/HelloApp/HelloApp.csproj (in 110 ms).
HelloApp -&gt; /home/user/HelloApp/bin/Release/net8.0/HelloApp.dll
HelloApp -&gt; /home/user/HelloApp/deploy/</code></pre>
<p>In this example, the <em>-c</em> <em>Release</em> flag builds with optimisations, and the <em>-o ./deploy</em> flag directs the published files to a <em>deploy</em> folder rather than the typical publish location:</p>
<table class="table-styled" style="width: 100%;height: 480px">
<tbody>
<tr style="height: 24px">
<td style="width: 50%;height: 24px"><strong>Option</strong></td>
<td style="width: 50%;height: 24px"><strong>Description</strong></td>
</tr>
<tr style="height: 48px">
<td style="height: 48px">-c &lt;CONFIGURATION&gt;</td>
<td style="height: 48px">Specifies the build configuration, usually <code>Debug</code> or <code>Release</code>. Default is <code>Debug</code>.</td>
</tr>
<tr style="height: 48px">
<td style="height: 48px">-r &lt;RUNTIME_IDENTIFIER&gt;</td>
<td style="height: 48px">Targets a specific OS and architecture, e.g., <code>win-x64</code>, <code>linux-arm</code>.</td>
</tr>
<tr style="height: 48px">
<td style="height: 48px">&#8211;self-contained true|false</td>
<td style="height: 48px">Includes the .NET runtime in the output (<code>true</code>) or relies on the system runtime (<code>false</code>).</td>
</tr>
<tr style="height: 48px">
<td style="height: 48px">/p:PublishSingleFile=true</td>
<td style="height: 48px">Bundles the app and dependencies into a single executable file.</td>
</tr>
<tr style="height: 48px">
<td style="height: 48px">/p:PublishTrimmed=true</td>
<td style="height: 48px">Removes unused code from assemblies to reduce the size of the published output.</td>
</tr>
<tr style="height: 48px">
<td style="height: 48px">/p:PublishReadyToRun=true</td>
<td style="height: 48px">Precompiles assemblies to improve application startup performance.</td>
</tr>
<tr style="height: 48px">
<td style="height: 48px">/p:PublishAot=true</td>
<td style="height: 48px">Enables ahead-of-time (AOT) compilation where supported.</td>
</tr>
<tr style="height: 24px">
<td style="height: 24px">&#8211;no-restore</td>
<td style="height: 24px">Skips restoring NuGet packages before publishing.</td>
</tr>
<tr style="height: 48px">
<td style="height: 48px">&#8211;no-build</td>
<td style="height: 48px">Skips the build step and only performs publish actions (useful if the project is already built).</td>
</tr>
<tr style="height: 48px">
<td style="height: 48px">-o &lt;OUTPUT_PATH&gt;</td>
<td style="height: 48px">Specifies the folder where the published files should be placed.</td>
</tr>
</tbody>
</table>
<p><strong>These options allow us to fine-tune the publishing process for speed, portability, and size.</strong></p>
<h2 id="bd-framework-dependent-vs-self-contained" data-id="framework-dependent-vs-self-contained">4. Framework-Dependent vs. Self-Contained</h2>
<div class="bd-anchor" id="framework-dependent-vs-self-contained"></div>
<p>A framework-dependent deployment expects that the destination machine already has the .NET runtime installed. This keeps the published output small:</p>
<pre><code class="language-bash">$ dotnet publish -c Release --self-contained false</code></pre>
<pre><code class="language-bash">HelloApp -&gt; /home/user/HelloApp/bin/Release/net8.0/HelloApp.dll
HelloApp -&gt; /home/user/HelloApp/bin/Release/net8.0/publish/
</code></pre>
<p>In this example, the publish folder contains mostly the <strong>application&#8217;s <em>.dll</em> file and any required libraries, but not the .NET runtime.</strong></p>
<p>However, a self-contained deployment bundles the .NET runtime with the program, allowing it to execute on systems that don&#8217;t have .NET installed:</p>
<pre><code class="language-bash">$ dotnet publish -c Release -r linux-x64 --self-contained true
</code></pre>
<pre><code class="language-bash">HelloApp -&gt; /home/user/HelloApp/bin/Release/net8.0/linux-x64/HelloApp.dll
HelloApp -&gt; /home/user/HelloApp/bin/Release/net8.0/linux-x64/publish/</code></pre>
<p>In this example, inspecting the publish folder displays an <strong>executable file as well as all runtime files required by that operating system and architecture.</strong></p>
<h2 id="bd-single-file-publishing" data-id="single-file-publishing">5. Single File Publishing</h2>
<div class="bd-anchor" id="single-file-publishing"></div>
<p>Single-file publishing enables us to distribute an application, its dependencies, and, optionally, the .NET runtime as a single executable. <strong>This approach simplifies deployment by eliminating the need to handle numerous assemblies and runtime files:</strong></p>
<pre><code class="language-bash">$ dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true</code></pre>
<pre><code class="language-bash">HelloApp -&gt; C:\Projects\HelloApp\bin\Release\net8.0\win-x64\HelloApp.dll
HelloApp -&gt; C:\Projects\HelloApp\bin\Release\net8.0\win-x64\publish\</code></pre>
<p>In this example, we publish a single-file executable for Windows; once published, we inspect the publish folder and find only one <em>.exe</em> file along with a few runtime-dependent files, depending on the parameters.</p>
<p>We can then proceed to launch the executable:</p>
<pre><code class="language-bash">$ C:\Projects\HelloApp\bin\Release\net8.0\win-x64\publish\HelloApp.exe</code></pre>
<pre><code class="language-bash">Hello World from Single File Deployment</code></pre>
<p>This indicates that the application runs correctly from a single file. Single-file publishing considerably simplifies deployment by lowering the number of files to distribute. Instead of handling multiple assemblies and runtime libraries, we can provide a single executable that can be launched immediately.</p>
<p>Furthermore, this method is useful in situations when simplicity and portability are important, such as <strong>distributing desktop utilities or packaging applications into containers.</strong></p>
<h2 id="bd-conclusion" data-id="conclusion">6. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In conclusion, the <em>dotnet publish</em> command is a crucial step in transitioning an application from development to production. It compiles the source code, handles dependencies, and generates a deployment-ready package specific to the specified environment.</p>
<p>In this article, we discuss what happens when we publish and how using options like <em>&#8211;self-contained</em>, runtime identifiers, or single-file publishing provides us fine-grained control over how programs are generated and delivered.</p>
<p>Finally, framework-dependent deployments reduce the footprint but rely on the presence of the .NET runtime, whereas self-contained deployments ensure portability. Single-file publishing simplifies distribution by combining everything into a single executable.</p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/923705738/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/923705738/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/923705738/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2024%2f02%2fOPS-Featured-Image-02-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/923705738/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/923705738/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/923705738/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/ansible-configuring-environment-variables">Configuring Environment Variables in Ansible</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/gocd-introduction">Introduction to GoCD</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2024/02/OPS-Featured-Image-02-150x150.jpg</webfeeds:featuredImage></item>
<item>
<feedburner:origLink>https://www.baeldung.com/ops/github-actions-pr-files-modified</feedburner:origLink>
		<title>Get Files Modified in a PR in GitHub Actions</title>
		<link>https://feeds.feedblitz.com/~/923543417/0/baeldung/ops~Get-Files-Modified-in-a-PR-in-GitHub-Actions</link>
		
		<dc:creator><![CDATA[Christian Jaimes]]></dc:creator>
		<pubDate>Wed, 20 Aug 2025 15:03:13 +0000</pubDate>
				<category><![CDATA[Git]]></category>
		<category><![CDATA[GitHub Actions]]></category>
		<category><![CDATA[Pull Request]]></category>
		<guid isPermaLink="false">https://www.baeldung.com/ops/?p=94104</guid>
					<description><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-04-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="max-width:100% !important;height:auto !important;float: left; margin-right: 5px;" loading="lazy" />Learn how to detect changed files in a PR and on push using GitHub Actions.<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/923543417/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/923543417/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fOPS-Featured-Image-04-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/923543417/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/923543417/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/923543417/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-create-pr">Create Pull Request With GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-private-docker-image">Use Private Docker Image in GitHub Actions</a></li></ul>&#160;</div>]]>
</description>
										<content:encoded><![CDATA[<img src="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-04-1024x536.jpg" class="webfeedsFeaturedVisual wp-post-image" alt="" style="float: left; margin-right: 5px;" decoding="async" loading="lazy" srcset="https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-04-1024x536.jpg 1024w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-04-300x157.jpg 300w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-04-768x402.jpg 768w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-04-100x52.jpg 100w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-04-600x314.jpg 600w, https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-04.jpg 1200w" sizes="auto, (max-width: 580px) 100vw, 580px" /><h2 id="bd-introduction" data-id="introduction">1. Introduction</h2>
<div class="bd-anchor" id="introduction"></div>
<p data-start="212" data-end="688"><a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/github-actions-workflow-locally">GitHub Actions</a> provides a flexible and powerful platform for automating workflows within a GitHub repository. One common use case in <a href="https://feeds.feedblitz.com/~/t/0/0/baeldung/ops/~https://www.baeldung.com/ops/ci-cd-best-practices">continuous integration (CI) workflows</a> is the ability to detect which files have changed in a pull request (PR) or push event.</p>
<p data-start="690" data-end="941">In this article, we&#8217;ll explore how to detect changed files in a PR and on push using GitHub Actions. We&#8217;ll also demonstrate how to combine both scenarios into a single workflow, ensuring that file detection logic works reliably for both event types.</p>
<h2 id="bd-detecting-changed-files-in-a-pull-request" data-id="detecting-changed-files-in-a-pull-request">2. Detecting Changed Files in a Pull Request</h2>
<div class="bd-anchor" id="detecting-changed-files-in-a-pull-request"></div>
<p><strong>When a PR is opened or updated, GitHub trig</strong><strong>gers a <em>pull_request</em> event.</strong> This event provides access to two important pieces of information: The base branch and the head branch. By comparing these two branches, we can detect which files have changed. This is especially useful when we want to run a specific job, like tests or linters, only for the parts of the codebase that were modified in the PR.</p>
<p>Let’s begin with a <em>pull_request</em> workflow that checks out the code and uses <em>git diff</em> to detect modified files:</p>
<pre><code class="language-yaml">name: Detect PR Changes
on:
  pull_request:
    types: [opened, synchronize, reopened]
jobs:
  detect-changes:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Ensures we have the full history for diff
      - name: Get changed files
        id: changes
        run: |
          git fetch origin ${{ github.base_ref }}
          CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
          echo "changed=$CHANGED_FILES" &gt;&gt; $GITHUB_OUTPUT
      - name: Print changed files
        run: echo "Changed files: ${{ steps.changes.outputs.changed }}"
</code></pre>
<p>The workflow is configured to trigger on <em>pull_request</em> events, specifically for actions such as <em>opened</em>, <em>synchronize</em>, and<em> reopened</em>. Within the job, in the first step, we use the <em>actions/checkout@v4 </em>action with <em>fetch-depth: 0 </em>to ensure that we retrieve the full commit history before comparing the difference.</p>
<p>Next, we fetch the base branch of the PR using <em>github.base_ref</em> in the second step. Then, we compare it against the current <em>HEAD</em> using <em>git diff &#8211;name-only</em>. <strong>This triple-dot syntax allows us to see the complete set of files that have changed between the branches.</strong> Finally, we store the result in an output variable so that subsequent steps in the workflow can access the list of changed files.</p>
<p>Lastly, we use <em>echo</em> to print the result and verify the output during the workflow execution.</p>
<h2 id="bd-detecting-changed-files-on-push" data-id="detecting-changed-files-on-push">3. Detecting Changed Files on Push</h2>
<div class="bd-anchor" id="detecting-changed-files-on-push"></div>
<p data-start="2731" data-end="2981">While PRs are common for collaborative development, direct pushes to branches are still relevant in many workflows. As another option,<strong> we can detect changed files when pushing new code to our branches.</strong> When using the <em>push </em>event, GitHub Actions provides access to the commit SHA before and after the <em>push</em>.</p>
<p data-start="2731" data-end="2981">This approach is straightforward and effective for detecting changes in workflows triggered by direct branch updates. It&#8217;s especially useful for scenarios like production deployments, validations, or testing workflows that need to respond to updates.</p>
<p data-start="2983" data-end="3023">We can use these SHAs to detect changes:</p>
<pre><code class="language-yaml">name: Detect Push Changes
on:
  push:
    branches:
      - main
      - develop
jobs:
  detect-push-changes:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout the code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Get changed files on push
        id: push_changes
        run: |
          git fetch origin ${{ github.ref_name }}
          CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }})
          echo "changed=$CHANGED_FILES" &gt;&gt; $GITHUB_OUTPUT
      - name: Print changed files
        run: echo "Changed files: ${{ steps.push_changes.outputs.changed }}"</code></pre>
<p>As discussed, <strong>GitHub&#8217;s <em>push</em> event provides two important commit SHAs: <em>before</em> and <em>after</em></strong>, representing the state of the branch before and after the push. By using <em>git diff </em>with these two SHAs, we can determine exactly which files were modified.</p>
<p>Similar to the pull request approach, we retrieve the full commit history using the <em>actions/checkout@v4</em> action with <em>fetch-depth: 0.</em></p>
<p>In the second step of the workflow, we compare the <em>before</em> and <em>after</em> SHAs using <em>git diff</em> to get a list of changed files.</p>
<p>Finally, we print the result to verify our changes during the workflow execution.</p>
<h2 id="bd-combining-pull-requests-and-pushes-on-a-single-workflow" data-id="combining-pull-requests-and-pushes-on-a-single-workflow">4. Combining Pull Requests and Pushes on a Single Workflow</h2>
<div class="bd-anchor" id="combining-pull-requests-and-pushes-on-a-single-workflow"></div>
<p data-start="4108" data-end="4282">In practice, <strong>we may want a unified workflow that handles both PRs and pushes.</strong> Rather than duplicating logic across separate workflows, we can combine support for both event types into a single, unified GitHub workflow.</p>
<p data-start="4284" data-end="4371"><strong>We can achieve this by adding conditional logic based on the <em>event_name</em> value:</strong></p>
<pre><code class="language-yaml">name: Detect File Changes
on:
  push:
    branches:
      - main
      - develop
  pull_request:
    types: [opened, synchronize, reopened]
jobs:
  detect-changed-files:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Determine event type
        id: event_type
        run: echo "Event is ${{ github.event_name }}"
      - name: Get changed files (PR)
        if: github.event_name == 'pull_request'
        id: pr_changes
        run: |
          git fetch origin ${{ github.base_ref }}
          CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
          echo "changed=$CHANGED_FILES" &gt;&gt; $GITHUB_OUTPUT
      - name: Get changed files (Push)
        if: github.event_name == 'push'
        id: push_changes
        run: |
          git fetch origin ${{ github.ref_name }}
          CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }})
          echo "changed=$CHANGED_FILES" &gt;&gt; $GITHUB_OUTPUT
      - name: Print changed files
        run: |
          if [ "${{ github.event_name }}" = "pull_request" ]; then
            echo "Changed files: ${{ steps.pr_changes.outputs.changed }}"
          else
            echo "Changed files: ${{ steps.push_changes.outputs.changed }}"
          fi
</code></pre>
<p data-start="4284" data-end="4371"><strong>This workflow listens to both <em>push</em> and <em>pull_request</em> events,</strong> allowing it to handle file change detection in a unified way. It begins by checking out the code with full history using <em>actions/checkoutv4</em>, ensuring that all commits needed for diff comparisons are available.</p>
<p data-start="4284" data-end="4371">Depending on the event type, determined by <em>github.event_name, </em>the workflow executes the appropriate set of steps: <strong>for pull requests, it compares the base branch to the head using <em>git diff</em>, while for pushes, it compares the <em>before</em> and <em>after</em> commit SHAs.</strong> Then, we store each result in an output variable. A final step prints the list of changed files, using conditional logic to select the correct output.</p>
<p data-start="4284" data-end="4371">This approach reduces maintenance overhead while also providing consistent file change detection, no matter how updates are made to the repository.</p>
<h2 id="bd-conclusion" data-id="conclusion">5. Conclusion</h2>
<div class="bd-anchor" id="conclusion"></div>
<p>In this article, we explored how detecting file changes in GitHub Actions is a powerful technique that enables more intelligent and efficient CI/CD workflows.</p>
<p>Detecting file changes in GitHub Actions is a powerful technique that enables more intelligent and efficient CI/CD workflows. Whether we&#8217;re working with PRs, direct pushes, or both, <strong>we can tailor our workflow to respond only to relevant changes, either for specific events or a combination of them.</strong></p><Img align="left" border="0" height="1" width="1" alt="" style="border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;" hspace="0" src="https://feeds.feedblitz.com/~/i/923543417/0/baeldung/ops">
<div style="clear:both;padding-top:0.2em;"><a title="Like on Facebook" href="https://feeds.feedblitz.com/_/28/923543417/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/fblike20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Pin it!" href="https://feeds.feedblitz.com/_/29/923543417/baeldung/ops,https%3a%2f%2fwww.baeldung.com%2fwp-content%2fuploads%2fsites%2f6%2f2025%2f01%2fOPS-Featured-Image-04-1024x536.jpg"><img height="20" src="https://assets.feedblitz.com/i/pinterest20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Post to X.com" href="https://feeds.feedblitz.com/_/24/923543417/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/x.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by email" href="https://feeds.feedblitz.com/_/19/923543417/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/email20.png" style="border:0;margin:0;padding:0;"></a>&#160;<a title="Subscribe by RSS" href="https://feeds.feedblitz.com/_/20/923543417/baeldung/ops"><img height="20" src="https://assets.feedblitz.com/i/rss20.png" style="border:0;margin:0;padding:0;"></a>&nbsp;<h3 style="clear:left;padding-top:10px">Related Stories</h3><ul><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-create-pr">Create Pull Request With GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-package-manager">Using a Package Manager in GitHub Actions</a></li><li><a rel="NOFOLLOW" href="https://www.baeldung.com/ops/github-actions-private-docker-image">Use Private Docker Image in GitHub Actions</a></li></ul>&#160;</div>]]>
</content:encoded>
					
		
		
		<webfeeds:featuredImage>https://www.baeldung.com/wp-content/uploads/sites/6/2025/01/OPS-Featured-Image-04-150x150.jpg</webfeeds:featuredImage></item>
</channel></rss>

