{"id":936,"date":"2025-08-29T08:17:56","date_gmt":"2025-08-29T06:17:56","guid":{"rendered":"https:\/\/deepdocs.dev\/?p=936"},"modified":"2025-08-29T08:20:06","modified_gmt":"2025-08-29T06:20:06","slug":"set-up-gitlab-ci-cd","status":"publish","type":"post","link":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/","title":{"rendered":"How to Set Up a GitLab CI\/CD Pipeline\u00a0"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Once upon a time, deploying apps used to be slow, manual and repetitive process. However, modern software is built and shipped rapidly through automation. This is called&nbsp;<a href=\"https:\/\/deepdocs.dev\/cicd-in-devops-theory-to-practice\/\"><strong>CI\/CD (Continuous Integration \/ Continuous Deployment)<\/strong><\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Previously, I covered about how to set-up a&nbsp;<a href=\"https:\/\/deepdocs.dev\/set-up-a-ci-cd-pipeline-using-github-actions\/\">CI\/CD Pipeline on Github<\/a>. But if you\u2019re using GitLab, you have a powerful CI\/CD system built right into your repository. In-fact, one of the distinguishing features for GitLab is its native support for CI\/CD workflows.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this guide, I\u2019ll walk you through setting up your very first GitLab CI\/CD pipeline. We\u2019ll break down what it actually&nbsp;<em>is<\/em>, why you need it, and then create a working example with a simple Node\/React-style app. Along the way, I\u2019ll share some practical developer insights that I\u2019ve learned the hard way.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is GitLab CI\/CD (and Why Should You Care)?<\/h2>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-412.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">At its core,&nbsp;<strong>GitLab CI\/CD<\/strong>&nbsp;is GitLab\u2019s built-in automation system. You define instructions in a special YAML file (<code>.gitlab-ci.yml<\/code>), and GitLab takes care of running them every time you push code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Think of it like giving GitLab a recipe:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Step 1 \u2192 Build the app<\/li>\n\n\n\n<li>Step 2 \u2192 Run the tests<\/li>\n\n\n\n<li>Step 3 \u2192 Deploy somewhere<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Instead of doing these things manually, GitLab CI\/CD does them automatically, on every commit, merge request, or release tag.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Why is this useful?<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>You catch bugs early with automated tests.<\/li>\n\n\n\n<li>You ensure every commit is deployable.<\/li>\n\n\n\n<li>You remove the \u201cit works on my machine\u201d problem.<\/li>\n\n\n\n<li>You free yourself from repetitive manual tasks.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you\u2019re building anything beyond a hobby project, CI\/CD is the secret sauce to moving fast without breaking things.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Get Started with GitLab CI\/CD<\/h2>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-413.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>CI\/CD<\/strong>&nbsp;is a continuous method of software development, where you continuously build, test, deploy, and monitor iterative code changes. This iterative process helps reduce the chance that you develop new code based on buggy or failed previous versions. GitLab CI\/CD can catch bugs early in the development cycle and help ensure that the code deployed to production complies with your established standards.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This process is part of a larger workflow:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">GitLab DevSecOps lifecycle with stages for Plan, Create, Verify, Secure, Release, and Monitor.<\/p>\n<\/blockquote>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-409.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Create a&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;file<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To use GitLab CI\/CD, you start with a&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;file at the root of your project. This file specifies the stages, jobs, and scripts to be executed during your CI\/CD pipeline. In this file, you define variables, dependencies between jobs, and specify when and how each job should be executed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Find or create runners<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Runners are the agents that run your jobs. These can run on physical machines or virtual instances. In your&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;file, you can specify a container image. The runner loads the image, clones your project, and runs the job either locally or in the container.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>On\u00a0<a href=\"http:\/\/gitlab.com\/\">GitLab.com<\/a>, runners on Linux, Windows, and macOS are already available.<\/li>\n\n\n\n<li>On self-managed GitLab, you\u2019ll need to register your own runner.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Define your pipelines<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A pipeline is what you\u2019re defining in&nbsp;<code>.gitlab-ci.yml<\/code>. It\u2019s made up of jobs and stages:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Stages<\/strong>\u00a0define the order of execution (build, test, deploy).<\/li>\n\n\n\n<li><strong>Jobs<\/strong>\u00a0specify the tasks in each stage (compile, test, etc.).<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Pipelines can be triggered by commits, merges, or schedules.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Use CI\/CD variables<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">GitLab CI\/CD variables are key-value pairs used to store configuration settings or sensitive info (like API keys). Variables can be defined in the file, in project settings, or generated dynamically.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Types:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Custom variables<\/strong>\u00a0\u2192 user-defined.<\/li>\n\n\n\n<li><strong>Predefined variables<\/strong>\u00a0\u2192 set automatically by GitLab.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Variables can be protected or masked for security.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 5: Use CI\/CD components<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A CI\/CD component is a reusable pipeline configuration unit. They help reduce duplication, improve maintainability, and promote consistency across projects. GitLab even provides templates for common tasks.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create and Run Your First GitLab CI\/CD Pipeline<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Prerequisites<\/h3>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-414.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Before starting, make sure you have:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A project in GitLab. (If you don\u2019t, create a free public project at\u00a0<a href=\"https:\/\/gitlab.com\/\">gitlab.com<\/a>)<\/li>\n\n\n\n<li>Maintainer or Owner role for that project.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-415.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Steps<\/h3>\n\n\n\n<h3 class=\"wp-block-heading\">1. Ensure you have runners available<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>On\u00a0<a href=\"http:\/\/gitlab.com\/\">GitLab.com<\/a>, runners are provided by default.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-418.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>To check: go to\u00a0<strong>Settings > CI\/CD > Runners<\/strong>. At least one runner should show as active.<\/li>\n\n\n\n<li>If none are available, install GitLab Runner locally and register it with your project.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-417.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">2. Create a&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;file<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">At the root of your repository, add a&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;file to define your pipeline.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>stages:          # Pipeline stages\n  - build\n  - test\n  - deploy\n\nbuild-job:       # Job 1: Build\n  stage: build\n  image: node:18\n  script:\n    - npm install\n    - npm run build\n  artifacts:\n    paths:\n      - dist\/\n\ntest-job:        # Job 2: Test\n  stage: test\n  image: node:18\n  script:\n    - npm install\n    - npm test\n\nlint-job:        # Job 3: Lint (runs in parallel with test-job)\n  stage: test\n  image: node:18\n  script:\n    - npm run lint\n\ndeploy-job:      # Job 4: Deploy\n  stage: deploy\n  image: node:18\n  script:\n    - echo \"Deploying to production server...\"\n  only:\n    - main\n\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This defines&nbsp;<strong>four jobs across three stages<\/strong>:&nbsp;<em>build \u2192 test \u2192 deploy<\/em>.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>build-job<\/code><\/strong>\u00a0installs dependencies and builds your app.<\/li>\n\n\n\n<li><strong><code>test-job<\/code><\/strong>\u00a0runs your tests.<\/li>\n\n\n\n<li><strong><code>lint-job<\/code><\/strong>\u00a0checks your code quality (runs alongside tests).<\/li>\n\n\n\n<li><strong><code>deploy-job<\/code><\/strong>\u00a0deploys to production, but only when changes are pushed to the\u00a0<code>main<\/code>\u00a0branch.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">3. Commit and run<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Commit the&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;file to your repository. GitLab automatically starts the pipeline.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. View your pipeline and jobs<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Go to\u00a0<strong>Build > Pipelines<\/strong>\u00a0to see the pipeline progress.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-419.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Click on a pipeline ID to view a graph of jobs and dependencies.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-410.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Select a job name (e.g.,\u00a0<code>deploy-prod<\/code>) to inspect logs and job details.<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/assets.apidog.com\/blog-next\/2025\/08\/image-410.png?ssl=1\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Done! &nbsp;&#8211; you\u2019ve just created and run your first GitLab CI\/CD pipeline! From here, you can expand the&nbsp;<code>.gitlab-ci.yml<\/code>with more advanced jobs, variables, and integrations.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Building Blocks of GitLab CI\/CD<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before jumping into the setup, let\u2019s clarify the&nbsp;<strong>three key concepts<\/strong>&nbsp;you\u2019ll see in every&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;file:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. Pipelines<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<strong>pipeline<\/strong>&nbsp;is the full CI\/CD workflow. It\u2019s triggered by a commit or merge, and it runs through a series of stages\/jobs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. Stages<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<strong>stage<\/strong>&nbsp;is a phase in your pipeline (build, test, deploy). Stages run&nbsp;<strong>sequentially<\/strong>: the&nbsp;<code>test<\/code>&nbsp;stage won\u2019t run until&nbsp;<code>build<\/code>&nbsp;has succeeded.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Jobs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<strong>job<\/strong>&nbsp;is a single task inside a stage. It\u2019s just a set of shell commands. For example, a test job might run&nbsp;<code>npm test<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So the hierarchy looks like this:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Setting Up Your First GitLab CI\/CD Pipeline<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">We\u2019ll build a simple pipeline for a Node\/React app. Assume your project has this structure:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 1: Create a&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;File<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">At the root of your repo, create a file named&nbsp;<code>.gitlab-ci.yml<\/code>. This file tells GitLab what to do when you push code.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Step 2: Define Your Stages<\/h3>\n\n\n\n<h3 class=\"wp-block-heading\">Step 3: Add Your Jobs<\/h3>\n\n\n\n<h3 class=\"wp-block-heading\">Step 4: Push and Watch the Magic<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Head to&nbsp;<strong>Build \u2192 Pipelines<\/strong>&nbsp;in GitLab to see your pipeline running.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Developer Insights: Common Mistakes and Pro Tips<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Even experienced developers slip up when setting up GitLab CI\/CD. Here are a few common mistakes I\u2019ve seen (and made myself), plus how to avoid them:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">1. Forgetting to cache dependencies<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If every job re-installs dependencies from scratch, pipelines get painfully slow. For example, in a Node.js project,&nbsp;<code>npm install<\/code>&nbsp;can take minutes each time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Use GitLab\u2019s&nbsp;<code>cache<\/code>&nbsp;keyword to speed things up:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>cache:\n  paths:\n    - node_modules\/\n\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">2. Not pinning Docker images<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Using&nbsp;<code>image: node:latest<\/code>&nbsp;seems convenient, but it can break your build if a new Node release introduces changes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Pin to a specific version like&nbsp;<code>node:18<\/code>&nbsp;to ensure stability.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Misusing stages and jobs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Beginners sometimes put all commands in a single job. That works\u2026 until you need parallelization or conditional deployments.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Break pipelines into clear&nbsp;<strong>stages<\/strong>&nbsp;(<code>build<\/code>,&nbsp;<code>test<\/code>,&nbsp;<code>deploy<\/code>) with multiple jobs. This makes debugging and scaling way easier.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. Ignoring YAML anchors<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If you repeat the same&nbsp;<code>image<\/code>,&nbsp;<code>cache<\/code>, or&nbsp;<code>before_script<\/code>&nbsp;blocks in multiple jobs, your&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;gets messy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Use YAML anchors to DRY up your file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.default-job: &amp;default-job\n  image: node:18\n  cache:\n    paths:\n      - node_modules\/\n\nbuild-job:\n  &lt;&lt;: *default-job\n  script:\n    - npm run build\n\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">5. Not setting branch rules<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Without&nbsp;<code>only<\/code>&nbsp;or&nbsp;<code>except<\/code>, you might accidentally deploy from feature branches.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Protect your deploy job:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>only:\n  - main\n\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">That way, the section not only lists mistakes but also&nbsp;<strong>explains why they hurt and how to fix them with code snippets<\/strong>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Pro Tips (Quick Wins)<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Cache smartly<\/strong>\u00a0\u2192 Save time by caching\u00a0<code>node_modules\/<\/code>\u00a0or\u00a0<code>vendor\/<\/code>.<\/li>\n\n\n\n<li><strong>Pin versions<\/strong>\u00a0\u2192 Use\u00a0<code>node:18<\/code>\u00a0instead of\u00a0<code>node:latest<\/code>\u00a0for stability.<\/li>\n\n\n\n<li><strong>Use YAML anchors<\/strong>\u00a0\u2192 Keep your\u00a0<code>.gitlab-ci.yml<\/code>\u00a0clean and DRY.<\/li>\n\n\n\n<li><strong>Protect deploys<\/strong>\u00a0\u2192 Run deployment jobs only on\u00a0<code>main<\/code>\u00a0(or release branches).<\/li>\n\n\n\n<li><strong>Keep pipelines fast<\/strong>\u00a0\u2192 Fail fast with lint\/tests before hitting deploy.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">A Real-World Example: Node\/React App<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s make this practical. Imagine you\u2019ve got a simple React frontend with a Node\/Express backend in the same repo. You want your pipeline to:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Install dependencies<\/li>\n\n\n\n<li>Run tests<\/li>\n\n\n\n<li>Build the React app<\/li>\n\n\n\n<li>Deploy the backend + frontend<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s how your&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;might look:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>stages:\n  - install\n  - test\n  - build\n  - deploy\n\ndefault:\n  image: node:18\n\ncache:\n  paths:\n    - node_modules\/\n\ninstall:\n  stage: install\n  script:\n    - npm install\n  artifacts:\n    paths:\n      - node_modules\/\n\ntest:\n  stage: test\n  script:\n    - npm test\n\nbuild_frontend:\n  stage: build\n  script:\n    - cd frontend\n    - npm install\n    - npm run build\n  artifacts:\n    paths:\n      - frontend\/build\n\nbuild_backend:\n  stage: build\n  script:\n    - cd backend\n    - npm install\n    - npm run build\n  artifacts:\n    paths:\n      - backend\/dist\n\ndeploy:\n  stage: deploy\n  script:\n    - echo \"Deploying app...\"\n    - rsync -avz frontend\/build\/ user@server:\/var\/www\/frontend\n    - rsync -avz backend\/dist\/ user@server:\/var\/www\/backend\n  only:\n    - main\n\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">What\u2019s Happening Here<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Stages:<\/strong>\u00a0Install \u2192 Test \u2192 Build \u2192 Deploy (a standard flow for Node + React apps).<\/li>\n\n\n\n<li><strong>Cache:<\/strong>\u00a0Keeps\u00a0<code>node_modules\/<\/code>\u00a0between jobs so installs are faster.<\/li>\n\n\n\n<li><strong>Artifacts:<\/strong>\u00a0React build output (<code>frontend\/build<\/code>) and backend dist files (<code>backend\/dist<\/code>) are passed to the deploy job.<\/li>\n\n\n\n<li><strong>Deploy:<\/strong>\u00a0Uses\u00a0<code>rsync<\/code>\u00a0as a simple way to push files to a server \u2014 in real life, you\u2019d use SSH, Docker, or Kubernetes.<\/li>\n\n\n\n<li><strong>only: main:<\/strong>\u00a0Ensures deployment only runs from your main branch, avoiding those \u201coops, I deployed a feature branch\u201d moments.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">GitLab CI\/CD may seem intimidating at first, but once you understand&nbsp;<strong>pipelines, stages, and jobs<\/strong>, it clicks. With just a&nbsp;<code>.gitlab-ci.yml<\/code>&nbsp;file, you can:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Build your app automatically.<\/li>\n\n\n\n<li>Run tests on every commit.<\/li>\n\n\n\n<li>Deploy safely and consistently.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The real power comes when you start refining your pipelines: caching, artifacts, YAML anchors, and custom runners.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you\u2019re working with Node or React, the examples above should give you a solid starting point. From here, you can expand into more advanced flows (linting, end-to-end tests, staging\/production deployments, Docker builds, etc.).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Setting up CI\/CD in GitLab doesn\u2019t have to be complicated. In this guide, we\u2019ll walk through how to create a simple GitLab pipeline, explain common mistakes developers make (and how to avoid them), and even show you a real-world Node\/React example you can adapt for your own projects. Whether you\u2019re just getting started or looking to level up your DevOps workflow, this article will give you practical YAML snippets, pro tips, and a clear path to automation.<\/p>\n","protected":false},"author":259061980,"featured_media":938,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_wpcom_ai_launchpad_first_post":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"{title}\n\n{excerpt}\n\n{url}","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[1388],"tags":[],"class_list":["post-936","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.0 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>How to Set Up a GitLab CI\/CD Pipeline\u00a0 | DeepDocs<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Set Up a GitLab CI\/CD Pipeline\u00a0 | DeepDocs\" \/>\n<meta property=\"og:description\" content=\"Setting up CI\/CD in GitLab doesn\u2019t have to be complicated. In this guide, we\u2019ll walk through how to create a simple GitLab pipeline, explain common mistakes developers make (and how to avoid them), and even show you a real-world Node\/React example you can adapt for your own projects. Whether you\u2019re just getting started or looking to level up your DevOps workflow, this article will give you practical YAML snippets, pro tips, and a clear path to automation.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/\" \/>\n<meta property=\"og:site_name\" content=\"DeepDocs\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/profile.php?id=61560455754198\" \/>\n<meta property=\"article:published_time\" content=\"2025-08-29T06:17:56+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-08-29T06:20:06+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Emmanuel Mumba\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@Nilzkool\" \/>\n<meta name=\"twitter:site\" content=\"@Nilzkool\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Emmanuel Mumba\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/\"},\"author\":{\"name\":\"Emmanuel Mumba\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#\\\/schema\\\/person\\\/52d36f3b4e46de722c44fbe49fd41390\"},\"headline\":\"How to Set Up a GitLab CI\\\/CD Pipeline\u00a0\",\"datePublished\":\"2025-08-29T06:17:56+00:00\",\"dateModified\":\"2025-08-29T06:20:06+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/\"},\"wordCount\":1583,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/08\\\/Blue-Gradient-Modern-Sport-Presentation-.jpg?fit=1920%2C1080&ssl=1\",\"articleSection\":[\"Tutorials\"],\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/\",\"url\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/\",\"name\":\"How to Set Up a GitLab CI\\\/CD Pipeline\u00a0 | DeepDocs\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/08\\\/Blue-Gradient-Modern-Sport-Presentation-.jpg?fit=1920%2C1080&ssl=1\",\"datePublished\":\"2025-08-29T06:17:56+00:00\",\"dateModified\":\"2025-08-29T06:20:06+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/#primaryimage\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/08\\\/Blue-Gradient-Modern-Sport-Presentation-.jpg?fit=1920%2C1080&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/08\\\/Blue-Gradient-Modern-Sport-Presentation-.jpg?fit=1920%2C1080&ssl=1\",\"width\":1920,\"height\":1080},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/set-up-gitlab-ci-cd\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/deepdocs.dev\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Set Up a GitLab CI\\\/CD Pipeline\u00a0\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#website\",\"url\":\"https:\\\/\\\/deepdocs.dev\\\/\",\"name\":\"DeepDocs\",\"description\":\"Fix Your Outdated GitHub Docs on Autopilot\",\"publisher\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/deepdocs.dev\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#organization\",\"name\":\"DeepDocs\",\"url\":\"https:\\\/\\\/deepdocs.dev\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/6.jpg?fit=408%2C400&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/6.jpg?fit=408%2C400&ssl=1\",\"width\":408,\"height\":400,\"caption\":\"DeepDocs\"},\"image\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/profile.php?id=61560455754198\",\"https:\\\/\\\/x.com\\\/Nilzkool\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/deepdocs-dev\",\"https:\\\/\\\/www.youtube.com\\\/@DrNeelDas\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#\\\/schema\\\/person\\\/52d36f3b4e46de722c44fbe49fd41390\",\"name\":\"Emmanuel Mumba\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/90c244dc9060626f2083430694ba08d76466e572b1ffa6c89cd2e1becee977d3?s=96&d=identicon&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/90c244dc9060626f2083430694ba08d76466e572b1ffa6c89cd2e1becee977d3?s=96&d=identicon&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/90c244dc9060626f2083430694ba08d76466e572b1ffa6c89cd2e1becee977d3?s=96&d=identicon&r=g\",\"caption\":\"Emmanuel Mumba\"},\"url\":\"https:\\\/\\\/deepdocs.dev\\\/author\\\/sneakycom\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Set Up a GitLab CI\/CD Pipeline\u00a0 | DeepDocs","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/","og_locale":"en_GB","og_type":"article","og_title":"How to Set Up a GitLab CI\/CD Pipeline\u00a0 | DeepDocs","og_description":"Setting up CI\/CD in GitLab doesn\u2019t have to be complicated. In this guide, we\u2019ll walk through how to create a simple GitLab pipeline, explain common mistakes developers make (and how to avoid them), and even show you a real-world Node\/React example you can adapt for your own projects. Whether you\u2019re just getting started or looking to level up your DevOps workflow, this article will give you practical YAML snippets, pro tips, and a clear path to automation.","og_url":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/","og_site_name":"DeepDocs","article_publisher":"https:\/\/www.facebook.com\/profile.php?id=61560455754198","article_published_time":"2025-08-29T06:17:56+00:00","article_modified_time":"2025-08-29T06:20:06+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-.jpg","type":"image\/jpeg"}],"author":"Emmanuel Mumba","twitter_card":"summary_large_image","twitter_creator":"@Nilzkool","twitter_site":"@Nilzkool","twitter_misc":{"Written by":"Emmanuel Mumba","Estimated reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/#article","isPartOf":{"@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/"},"author":{"name":"Emmanuel Mumba","@id":"https:\/\/deepdocs.dev\/#\/schema\/person\/52d36f3b4e46de722c44fbe49fd41390"},"headline":"How to Set Up a GitLab CI\/CD Pipeline\u00a0","datePublished":"2025-08-29T06:17:56+00:00","dateModified":"2025-08-29T06:20:06+00:00","mainEntityOfPage":{"@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/"},"wordCount":1583,"commentCount":0,"publisher":{"@id":"https:\/\/deepdocs.dev\/#organization"},"image":{"@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-.jpg?fit=1920%2C1080&ssl=1","articleSection":["Tutorials"],"inLanguage":"en-GB","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/","url":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/","name":"How to Set Up a GitLab CI\/CD Pipeline\u00a0 | DeepDocs","isPartOf":{"@id":"https:\/\/deepdocs.dev\/#website"},"primaryImageOfPage":{"@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/#primaryimage"},"image":{"@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-.jpg?fit=1920%2C1080&ssl=1","datePublished":"2025-08-29T06:17:56+00:00","dateModified":"2025-08-29T06:20:06+00:00","breadcrumb":{"@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/"]}]},{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/#primaryimage","url":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-.jpg?fit=1920%2C1080&ssl=1","contentUrl":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-.jpg?fit=1920%2C1080&ssl=1","width":1920,"height":1080},{"@type":"BreadcrumbList","@id":"https:\/\/deepdocs.dev\/set-up-gitlab-ci-cd\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/deepdocs.dev\/"},{"@type":"ListItem","position":2,"name":"How to Set Up a GitLab CI\/CD Pipeline\u00a0"}]},{"@type":"WebSite","@id":"https:\/\/deepdocs.dev\/#website","url":"https:\/\/deepdocs.dev\/","name":"DeepDocs","description":"Fix Your Outdated GitHub Docs on Autopilot","publisher":{"@id":"https:\/\/deepdocs.dev\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/deepdocs.dev\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":"Organization","@id":"https:\/\/deepdocs.dev\/#organization","name":"DeepDocs","url":"https:\/\/deepdocs.dev\/","logo":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/deepdocs.dev\/#\/schema\/logo\/image\/","url":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/06\/6.jpg?fit=408%2C400&ssl=1","contentUrl":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/06\/6.jpg?fit=408%2C400&ssl=1","width":408,"height":400,"caption":"DeepDocs"},"image":{"@id":"https:\/\/deepdocs.dev\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/profile.php?id=61560455754198","https:\/\/x.com\/Nilzkool","https:\/\/www.linkedin.com\/company\/deepdocs-dev","https:\/\/www.youtube.com\/@DrNeelDas"]},{"@type":"Person","@id":"https:\/\/deepdocs.dev\/#\/schema\/person\/52d36f3b4e46de722c44fbe49fd41390","name":"Emmanuel Mumba","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/secure.gravatar.com\/avatar\/90c244dc9060626f2083430694ba08d76466e572b1ffa6c89cd2e1becee977d3?s=96&d=identicon&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/90c244dc9060626f2083430694ba08d76466e572b1ffa6c89cd2e1becee977d3?s=96&d=identicon&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/90c244dc9060626f2083430694ba08d76466e572b1ffa6c89cd2e1becee977d3?s=96&d=identicon&r=g","caption":"Emmanuel Mumba"},"url":"https:\/\/deepdocs.dev\/author\/sneakycom\/"}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-.jpg?fit=1920%2C1080&ssl=1","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pgAtwt-f6","jetpack-related-posts":[{"id":2466,"url":"https:\/\/deepdocs.dev\/gitlab-ci-yml\/","url_meta":{"origin":936,"position":0},"title":"A Developer&#8217;s Guide to GitLab CI YML","author":"Neel Das","date":"16 February 2026","format":false,"excerpt":"At the heart of every GitLab CI\/CD pipeline is a single, powerful file: .gitlab-ci.yml. This isn't just another config file; it's the blueprint for your entire automation workflow. Written in YAML and placed in the root of your repository, it tells GitLab exactly what to build, what to test, and\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/01\/gitlab-ci-yml-developers-guide-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/01\/gitlab-ci-yml-developers-guide-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/01\/gitlab-ci-yml-developers-guide-1.jpg?fit=1200%2C673&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/01\/gitlab-ci-yml-developers-guide-1.jpg?fit=1200%2C673&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/01\/gitlab-ci-yml-developers-guide-1.jpg?fit=1200%2C673&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":898,"url":"https:\/\/deepdocs.dev\/set-up-a-ci-cd-pipeline-using-github-actions\/","url_meta":{"origin":936,"position":1},"title":"How to Set Up a CI\/CD Pipeline Using GitHub Actions","author":"Emmanuel Mumba","date":"21 August 2025","format":false,"excerpt":"Learn how to set up a CI\/CD pipeline with GitHub Actions from scratch. Using a sample React app, we\u2019ll walk through creating workflows, automating builds, and deploying to GitHub Pages making deployments fast, reliable, and stress-free.","rel":"","context":"In &quot;Tutorials&quot;","block_context":{"text":"Tutorials","link":"https:\/\/deepdocs.dev\/category\/tutorials\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-1-1.jpg?fit=1200%2C675&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-1-1.jpg?fit=1200%2C675&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-1-1.jpg?fit=1200%2C675&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-1-1.jpg?fit=1200%2C675&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/Blue-Gradient-Modern-Sport-Presentation-1-1.jpg?fit=1200%2C675&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":998,"url":"https:\/\/deepdocs.dev\/how-to-set-up-a-jenkins\/","url_meta":{"origin":936,"position":2},"title":"How to Set Up a Jenkins CI\/CD Pipeline (Step-by-Step Guide)","author":"Emmanuel Mumba","date":"6 September 2025","format":false,"excerpt":"Setting up a CI\/CD pipeline can feel overwhelming at first, but Jenkins makes it possible to automate builds, tests, and deployments in a powerful, flexible way. In this guide, I\u2019ll walk you through the complete setup from installing Jenkins to writing a Jenkinsfile and share a real-world Node\/React example you\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-1.jpg?fit=1200%2C675&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-1.jpg?fit=1200%2C675&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-1.jpg?fit=1200%2C675&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-1.jpg?fit=1200%2C675&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-1.jpg?fit=1200%2C675&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":1011,"url":"https:\/\/deepdocs.dev\/ci-cd-pipeline-with-aws\/","url_meta":{"origin":936,"position":3},"title":"How to Build a CI\/CD Pipeline with AWS (Step-by-Step Guide)","author":"Emmanuel Mumba","date":"11 September 2025","format":false,"excerpt":"Manually deploying code is slow and error-prone. In this guide, I\u2019ll show you how to set up a CI\/CD pipeline on AWS from scratch using services like CodePipeline, CodeBuild, and CodeDeploy. You\u2019ll learn how the pieces fit together, see a practical example, and pick up best practices to keep your\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/IMG_2371.jpeg?fit=1200%2C675&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/IMG_2371.jpeg?fit=1200%2C675&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/IMG_2371.jpeg?fit=1200%2C675&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/IMG_2371.jpeg?fit=1200%2C675&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/IMG_2371.jpeg?fit=1200%2C675&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":714,"url":"https:\/\/deepdocs.dev\/cicd-in-devops-theory-to-practice\/","url_meta":{"origin":936,"position":4},"title":"What is CI\/CD in DevOps: From Theory to Practice","author":"Neel Das","date":"11 August 2025","format":false,"excerpt":"I still remember the \"deployment days\" from early in my career. The air in the office would be thick with a mixture of anticipation and dread. Our engineering team would huddle around a few computers, their faces illuminated by the glow of terminal windows. The process was a carefully choreographed\u2026","rel":"","context":"In \"CI\/CD\"","block_context":{"text":"CI\/CD","link":"https:\/\/deepdocs.dev\/tag\/ci-cd\/"},"img":{"alt_text":"CI\/CD in DevOps","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/IMG_2124-1.jpg?fit=1200%2C720&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/IMG_2124-1.jpg?fit=1200%2C720&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/IMG_2124-1.jpg?fit=1200%2C720&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/IMG_2124-1.jpg?fit=1200%2C720&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/08\/IMG_2124-1.jpg?fit=1200%2C720&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":1044,"url":"https:\/\/deepdocs.dev\/set-up-a-ci-cd-pipeline-on-azure-cloud\/","url_meta":{"origin":936,"position":5},"title":"How to Set Up a CI\/CD Pipeline on Azure Cloud","author":"Emmanuel Mumba","date":"22 September 2025","format":false,"excerpt":"Manual deployments slow you down and increase the risk of errors. With Azure DevOps, you can create a CI\/CD pipeline that automates builds, tests, and deployments helping your team release faster and with more confidence. This guide walks you through the process, explains key services, and highlights best practices for\u2026","rel":"","context":"In &quot;Tutorials&quot;","block_context":{"text":"Tutorials","link":"https:\/\/deepdocs.dev\/category\/tutorials\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-16.png?fit=1200%2C675&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-16.png?fit=1200%2C675&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-16.png?fit=1200%2C675&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-16.png?fit=1200%2C675&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/09\/Blue-Gradient-Modern-Sport-Presentation-16.png?fit=1200%2C675&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/posts\/936","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/users\/259061980"}],"replies":[{"embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/comments?post=936"}],"version-history":[{"count":3,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/posts\/936\/revisions"}],"predecessor-version":[{"id":940,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/posts\/936\/revisions\/940"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/media\/938"}],"wp:attachment":[{"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/media?parent=936"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/categories?post=936"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/tags?post=936"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}