• Updated: 26 Feb 2026 · 26 Feb 2026 · CI/CD · 5 min read

    How to Set Up a Basic CI/CD Pipeline for Your Application

    Contents

    Setting up a CI/CD pipeline for the first time can feel overwhelming. There are tools, configuration files, build stages, environments, and deployment strategies to think about. But at its core, a basic CI/CD pipeline is straightforward.

    It should do three things reliably:

    1. Install dependencies
    2. Run automated tests
    3. Build and optionally deploy the application

    This guide walks through how to set up a minimal, production-ready CI/CD pipeline for common application types, with links to relevant documentation and examples.

    Step 1: Define What “Basic” Actually Means

    A basic CI/CD pipeline is not a full DevOps platform. It’s a reproducible process that:

    • Runs on every pull request or commit
    • Fails if tests fail
    • Produces a build artifact
    • Optionally deploys when changes are merged

    For most teams, that’s enough to dramatically improve software reliability.

    If you’re new to CI/CD concepts, Semaphore has a helpful general overview in the documentation.

    Step 2: Make Your Local Build Reproducible

    Before writing any CI configuration, your project should build cleanly from scratch.

    If this fails locally, CI will fail too.

    From a clean clone of your repository, you should be able to run:

    Node.js

    npm ci
    npm test
    npm run build

    Python

    pip install -r requirements.txt
    pytest

    Java (Maven)

    mvn clean test package

    If this doesn’t work on a fresh machine or container, fix that first. This is foundational to reliable CI/CD workflows, as discussed in our post on automated testing principles.

    Step 3: Add Lock Files

    Lock files are essential for reproducible CI builds.

    Examples:

    • package-lock.json
    • yarn.lock
    • Pipfile.lock
    • poetry.lock
    • go.sum
    • Gemfile.lock

    Without lock files, CI may install newer dependency versions than you used locally. This leads to dependency drift and unpredictable test failures.

    Commit lock files to version control. In Node.js, prefer:

    npm ci

    instead of npm install in CI. npm ci enforces the lock file exactly, preventing drift.

    Step 4: Create a Minimal CI Pipeline

    A basic pipeline has three stages:

    1. Install dependencies
    2. Run tests
    3. Build artifacts

    In a CI platform like Semaphore, a minimal pipeline might look like:

    version: v1.0
    name: Basic Pipeline
    blocks:
     - name: Install & Test
       task:
         jobs:
    
           - name: Run tests
             commands:
               - checkout
               - npm ci
               - npm test
    
     - name: Build
       task:
         jobs:
           - name: Build app
    
             commands:
    
               - checkout
               - npm ci
               - npm run build

    This ensures that tests gate the build, and that everything runs in a clean environment.

    If you’re interested in optimizing this further (parallelism, caching, monorepos), Semaphore’s documentation has detailed guides.

    Step 5: Configure Environment Variables

    Applications often require configuration:

    • Database URLs
    • API keys
    • Feature flags

    Never hardcode these in your repository.

    Instead:

    • Define environment variables in your CI settings
    • Inject them into test and build jobs
    • Use separate values for staging vs production

    Semaphore allows secure environment variable configuration at the project or pipeline level.

    Step 6: Enable Test Reports

    CI shouldn’t just say “pass” or “fail.” It should give visibility into:

    • Which tests failed
    • Which tests are slow
    • Which tests are flaky

    Semaphore provides built-in test reporting that aggregates results across runs, which is useful for tracking trends and identifying flaky tests.

    As discussed in our Why Do Builds Pass Locally but Fail in CI post, flaky tests are often exposed first in CI due to clean environments and timing differences.

    Step 7: Add Deployment (Optional)

    For a basic CI/CD setup:

    • Run CI on every pull request
    • Deploy automatically on merge to main
    • Keep production deployments controlled

    Deployment might:

    • Push a Docker image
    • Upload a build artifact
    • Deploy to a cloud provider

    The key principle: deployments should only happen after tests pass.

    Semaphore’s docs include examples for popular deployment targets.

    Common Mistakes to Avoid

    No Lock Files

    Leads to dependency drift and unpredictable CI failures.

    Tests That Depend on Local State

    Tests must be isolated and idempotent.

    Different Tool Versions in CI and Local

    Use version managers or Docker to align environments.

    Semaphore documentation on using containers and machine types is useful here.

    Skipping Tests in CI “For Speed”

    Fast feedback is important, but skipping tests reduces reliability.

    For advice on balancing speed and coverage, see our article on optimizing CI workflows.

    What a “Good Enough” Pipeline Looks Like

    You don’t need:

    • Complex multi-stage deployments
    • Advanced parallelization
    • Over-engineered workflows

    A good pipeline:

    • Runs consistently
    • Fails loudly
    • Is reproducible
    • Is easy to understand

    That’s it.

    Summary

    A basic CI/CD pipeline installs dependencies, runs automated tests, and builds your application in a clean, reproducible environment. Commit lock files, align tool versions, configure environment variables properly, and ensure tests are deterministic.

    Start simple. Reliability matters more than complexity.

    FAQs

    What is the minimum CI/CD setup?

    Install dependencies, run tests, build artifacts. Deployment is optional but recommended after tests pass.

    Do I need Docker for CI?

    Not strictly, but containers help match local and CI environments.

    Should I run all tests in CI?

    Yes. CI should be the source of truth for test automation reliability.

    How often should CI run?

    On every pull request and on merges to the main branch.

    Want to discuss this article? Join our Discord.

    Pete Miloravac
    Writen by:
    Pete Miloravac is a software engineer and educator at Semaphore. He writes about CI/CD best practices, test automation, reproducible builds, and practical ways to help teams ship software faster and more reliably.
    Star us on GitHub