TL;DR: This guide explains how to replace risky, manual FTP/SCP server deployments with automated CI/CD pipelines to eliminate the "it works on my machine" problem. You will learn how Continuous Integration automatically runs commands like
npm run teston new GitHub/GitLab commits, and understand the exact distinction between Continuous Delivery and Continuous Deployment.
⚡ Key Takeaways
- Replace manual, error-prone deployment commands like
scpfile transfers andpm2 restartwith automated pipelines. - Use Continuous Integration (CI) to automatically provision virtual environments and run
npm installandnpm run testthe exact second code is pushed to a shared repository. - Block broken features from merging into your main codebase by configuring your CI server to reject commits that fail automated test scripts.
- Implement Continuous Delivery to automatically build and stage code for production while requiring a human to manually click "Approve" before it goes live.
- Use Continuous Deployment for a zero-touch pipeline where code that passes all automated tests is pushed directly to the live server without manual intervention.
Imagine spending three weeks writing code for a brand-new feature on your company’s website. You test it thoroughly on your laptop, and it works flawlessly. You hand the code over to the operations team to deploy it to the live environment.
But the moment it goes live, the entire website crashes. Customers cannot log in, the database disconnects, and your boss is frantic.
Upon investigation, you discover the production server is running an older software version than your local machine. Worse, your new code accidentally overwrote a teammate’s work because you both modified the same file.
Software development teams faced this exact nightmare for decades. Moving code from a developer's laptop to a live public server was a terrifying, error-prone manual process. Developers used to literally drag and drop files over the internet, crossing their fingers that nothing would break.
Continuous Integration and Continuous Delivery (CI/CD) is the solution. It is a set of practices and automated tools designed to test and deploy code safely, predictably, and automatically.
In this beginner's guide, we will break down exactly what CI/CD means, why it is the backbone of modern software engineering, and how you can implement it in your projects.
The Problem: The "It Works On My Machine" Nightmare
To understand why CI/CD matters, we must first look at how software was deployed without it.
Before CI/CD pipelines became the standard, a developer updating a website would typically use a secure file transfer protocol (FTP or SCP) to manually copy files from their computer directly to the live server.
It usually looked something like this manual terminal command:
# The old, risky way of deploying software
# Manually copying a folder from a laptop to a live server
scp -r ./my-website-code root@192.168.1.50:/var/www/html/
# Manually logging into the server to restart the application
ssh root@192.168.1.50
pm2 restart my-website
This manual workflow creates massive bottlenecks and risks. What if the developer forgets to run their security tests before uploading? What if two developers upload conflicting files at the same time? What if the developer's laptop has specific software configurations that the live server lacks?
This discrepancy leads to the most infamous phrase in software engineering: "It works on my machine!"
Without automation, releasing new software takes hours or even days of manual testing and synchronization. This slows down the business, frustrates the engineering team, and inevitably allows bugs to reach end users.
What is Continuous Integration (CI)?
Continuous Integration (CI) is the first half of the solution.
Whenever developers write code, they save it using a version control system and push it to a shared remote repository (often hosted on platforms like GitHub or GitLab). Saving code to this repository is called making a Commit.
Continuous Integration is an automated system that watches this repository. The exact second a developer pushes new code, the CI system wakes up, provisions a temporary virtual environment, and automatically tests the new code to ensure it functions correctly and integrates smoothly with the rest of the codebase.
If you are writing a JavaScript application, you likely have automated test scripts to verify your application's logic. A CI system automates the execution of these checks.
# When a developer pushes code, the CI server automatically runs:
npm install # Downloads all necessary software dependencies
npm run test # Runs automated checks against the new code
# Example output from the CI server:
# ✓ Test passed: User login works
# ✓ Test passed: Password reset works
# ✗ Test failed: Shopping cart calculation is incorrect
If the tests pass, the CI system gives the code a green light. If a test fails, the CI system halts the process, rejects the code, and alerts the developer immediately.
Production Note: By catching bugs the exact minute code is pushed, CI prevents broken features from merging into the main project. This ensures the primary version of your software remains stable and functional at all times.
What is Continuous Delivery and Deployment (CD)?
Once the code passes the Continuous Integration tests, it must be delivered to the actual live server so customers can interact with it. This is where CD comes in.
Depending on the level of automation a team requires, CD stands for either Continuous Delivery or Continuous Deployment:
- Continuous Delivery: The code is automatically tested, built, and packaged for release. It sits in a staging area, 100% ready to go live. However, a human (like a QA engineer or product manager) must manually click an "Approve" button to push it to the public server.
- Continuous Deployment: There is zero manual intervention. If the code passes all automated tests, the pipeline immediately and automatically pushes it directly to the live server.
With CD, deploying a website transforms from a high-risk manual chore into an invisible, automated background task. When a team leverages proper DevOps and Cloud Deployment Services, pushing new features to thousands of users takes minutes, not months.
Here is an example of what an automated CD deployment command looks like under the hood when deploying a containerized application to a Kubernetes cluster:
# The CD system automatically authenticates with the cloud provider
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin
# The CD system updates the live cluster with the newly tested code image
kubectl set image deployment/my-website my-website=my-repo/my-website:latest
# Output:
# deployment.apps/my-website image updated. Users are now seeing the new code.
Real-World Analogy: The Restaurant Kitchen
Technical jargon can be overwhelming, so let's translate CI/CD into a real-world analogy: a high-end restaurant kitchen.
Imagine the developers are Chefs. The code they write are the Ingredients. The final dish served to the customer is your Live Software.
Without CI/CD: A chef prepares a dish in their own corner, places it on a plate, and a waiter immediately carries it to the customer. Nobody double-checks the work. If the chef accidentally swapped salt for sugar, the customer eats it, complains, and the restaurant loses credibility.
With CI/CD:
- Continuous Integration (The Sous-Chef): Every time a chef finishes a component of a dish, they place it on a middle counter. An expert Sous-Chef (the CI system) immediately tastes a tiny spoonful. If it tastes wrong (a failed test), the Sous-Chef throws it away and tells the chef to remake it. Bad food never leaves the kitchen.
- Continuous Delivery (The Automated Waiter): If the component is perfect, it is placed under a heat lamp, perfectly plated and ready (Delivery). The manager rings a bell, and a highly efficient waiter glides the food out to the customer's exact table without dropping it (Deployment).
Here is a simple JSON data structure that represents how a CI/CD pipeline evaluates our "recipe":
{
"commit_message": "Add new shopping cart feature",
"author": "Chef Developer",
"pipeline_status": "running",
"stages": [
{
"name": "Integration (Taste Test)",
"status": "passed",
"details": "No bugs found. Syntax is correct."
},
{
"name": "Delivery (Plating)",
"status": "passed",
"details": "Software compiled and packaged successfully."
},
{
"name": "Deployment (Serving)",
"status": "pending_approval",
"details": "Waiting for manager to click 'Go Live'."
}
]
}
How to Build Your First CI/CD Pipeline
To make this concept completely concrete, let's look at how to build a simple pipeline using GitHub Actions, one of the most popular CI/CD tools in the world.
A CI/CD pipeline is simply a set of instructions written in a file using YAML (a human-readable data serialization language). You place this file inside your code repository, and GitHub reads it to know exactly what steps to execute.
Let's assume we have a Node.js project. We want GitHub to automatically run our tests every time we push code to the main branch.
We create a file in our project folder at .github/workflows/ci.yml:
# 1. Name the pipeline
name: Automated Testing Pipeline
# 2. Define the trigger (WHEN the pipeline runs)
on:
push:
branches:
- main
# 3. Define the JOBS (WHAT the pipeline will do)
jobs:
test-our-code:
# Rent a temporary Ubuntu Linux environment
runs-on: ubuntu-latest
# 4. List the exact STEPS the environment needs to take
steps:
# Step A: Download the code from the GitHub repository
- name: Checkout Code
uses: actions/checkout@v4
# Step B: Install a specific version of Node.js
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
node-version: '20'
# Step C: Install the project's dependencies
- name: Install Dependencies
run: npm install
# Step D: Execute the automated tests
- name: Run Tests
run: npm run test
When you push code to GitHub with this file in your repository, GitHub automatically reads it. It spins up a temporary runner (ubuntu-latest), downloads your code, installs Node.js, and runs npm run test.
If your tests pass, a green checkmark appears next to your commit on GitHub. If they fail, a red "X" appears, and you receive an alert warning you that the new code is broken.
Production Note: Never hardcode sensitive passwords or API keys directly into your YAML files. Always use your CI provider's "Secrets Manager" to securely inject credentials during deployment.
Why CI/CD Matters for Real Projects
At this point, you understand the what and the how. But why is CI/CD considered a mandatory requirement for modern, professional software engineering?
1. It Eliminates the Fear of Releasing When deployments are a manual process, teams are terrified of breaking things. They hoard features and only release once every few months. Because CI/CD utilizes automated testing to catch bugs instantly, developers feel confident releasing small code changes multiple times a day.
2. It Frees Up Developer Time Computers are exponentially faster and more accurate at copying files and running routine checklists than humans are. By automating testing and server uploads, developers can spend their time doing what they are actually paid to do: building new features.
3. Faster Time to Market If your business needs to launch a new payment feature to beat a competitor, you don't want to wait three weeks for a manual deployment window. CI/CD allows businesses to ship features to users the exact minute the code is finished and verified.
Here is a code snippet showing how modern CI/CD pipelines securely handle the secrets required to push code fast, without ever exposing sensitive data in the repository:
# Inside our deployment pipeline, we securely inject secrets
# without ever typing them out in the configuration file.
steps:
- name: Deploy to Production Environment
run: npm run deploy
env:
# The CI system pulls these safely from an encrypted vault
DATABASE_PASSWORD: ${{ secrets.PROD_DB_PASSWORD }}
STRIPE_API_KEY: ${{ secrets.LIVE_STRIPE_KEY }}
CI/CD is not just a technical tool; it is a business strategy. It transforms software development from a slow, error-prone assembly line into a high-speed, automated factory.
Whether you are a solo developer building a portfolio project, or a Fortune 500 company handling billions of requests, setting up a CI/CD pipeline is one of the most valuable investments you can make in your codebase's reliability. If you need expert guidance setting up secure pipelines, you can always talk to our DevOps engineers to book a free architecture review.
Need help building this in production?
SoftwareCrafting is a full-stack dev agency — we ship fast, scalable React, Next.js, Node.js, React Native & Flutter apps for global clients.
Get a Free ConsultationFrequently Asked Questions
What is the exact difference between Continuous Delivery and Continuous Deployment?
In Continuous Delivery, code is automatically tested and staged, but a human must manually approve the final release to the live server. Continuous Deployment removes this manual step, automatically pushing any code that passes all tests directly to production. Both practices ensure your software is always in a reliable, deployable state.
Why is manually uploading code via FTP or SCP considered a bad practice?
Manual deployments create massive bottlenecks and risks, such as accidentally overwriting a teammate's work or forgetting to run critical tests. It also leads to the "it works on my machine" problem, where local configuration differences cause live server crashes. Automated CI/CD pipelines eliminate these human errors by standardizing and securing the deployment process.
How does Continuous Integration (CI) prevent broken code from going live?
Continuous Integration systems actively monitor your shared code repository for new commits. The moment a developer pushes code, the CI server automatically provisions a temporary environment and runs automated test scripts. If any test fails, the system halts the process and alerts the developer, ensuring buggy code never merges into the main project.
How can SoftwareCrafting services help my team implement CI/CD?
Transitioning from manual deployments to automated pipelines can be complex for growing engineering teams. SoftwareCrafting services can design and implement custom CI/CD workflows tailored to your specific tech stack and repository. We help automate your testing and deployment processes so your developers can focus entirely on writing feature code.
What happens if an automated test fails during the CI process?
If an automated test fails, the CI system immediately halts the pipeline and rejects the new code. It then alerts the developer about the specific failure, such as a broken login route or an incorrect shopping cart calculation. This strict gatekeeping ensures that only stable, fully functional code is allowed to proceed to the delivery phase.
Can SoftwareCrafting services assist with moving our legacy applications to Continuous Deployment?
Yes, SoftwareCrafting services specializes in modernizing legacy deployment workflows for older applications. We can help you replace outdated FTP transfers and manual server restarts with fully automated Continuous Deployment pipelines. This ensures your legacy systems benefit from the same safety, speed, and predictability as modern software projects.
📎 Full Code on GitHub Gist: The complete
commands-1.shfrom this post is available as a standalone GitHub Gist — copy, fork, or embed it directly.
