How to Stop Deploying Manually and Stop Fearing Commits
\n\nHave you ever sat on a Friday evening, looked at production, and thought: "Well, it seems to work, but if I run the build now — will anything break?" Sound familiar? Manual deployment is like skydiving without an instructor: it gives you an adrenaline rush, but it too often ends painfully.
\n\nA CI/CD pipeline is your automatic safety rope. It will build the project, run tests, check the code, and if everything is OK — deploy the update to the server. No more "oops, I forgot to run the build" or "why did the tests fail, they worked locally?".
\n\nIn this article, we will set up a full CI/CD pipeline for a JavaScript project from scratch. No fluff, with real code examples and ready-made configs. Let's go!
\n\nWhat is a CI/CD pipeline and why does a JavaScript developer need it
\n\nLet's clarify the terms right away to avoid confusion.
\n\nContinuous Integration (CI) — continuous integration. This means every commit you make is automatically checked: code passes linters, tests, and builds. If something breaks — you find out in 2 minutes, not a week later.
\n\nContinuous Delivery (CD) — continuous delivery. Automatic deployment of ready code to the server after all CI checks have passed successfully.
\n\nFor JavaScript projects, CI/CD is especially important. Why? Because the JS ecosystem consists of thousands of dependencies that can update at any moment and break your code. Automation saves you from such surprises.
\n\nWhat we will set up
\n- \n
- GitHub Actions — a free CI/CD tool (sufficient for most projects) \n
- Linter — code style checking (ESLint) \n
- Tests — automatic Jest execution \n
- Build — project build (Webpack or Vite) \n
- Deployment — automatic upload to a server or hosting \n
Step 1: Prepare the project
\n\nLet's assume you already have a JavaScript project (React, Vue, Node.js — it doesn't matter). If not, create a simple test project:
\n\nmkdir my-ci-cd-project\ncd my-ci-cd-project\nnpm init -y\nnpm install --save-dev jest eslint\n\nAdd a basic script to package.json:
{\n "scripts": {\n "test": "jest",\n "lint": "eslint src/",\n "build": "webpack --mode production",\n "deploy": "rsync -avz dist/ user@server:/var/www"\n }\n}\n\nNow we have local commands that the CI/CD will execute automatically.
\n\nStep 2: Create a GitHub Actions workflow
\n\nGitHub Actions is the brain of our pipeline. Everything is managed by YAML files in the .github/workflows/ folder.
Create the file .github/workflows/ci-cd.yml:
name: CI/CD Pipeline\n\non:\n push:\n branches: [ main, develop ]\n pull_request:\n branches: [ main ]\n\njobs:\n build-and-test:\n runs-on: ubuntu-latest\n \n steps:\n - uses: actions/checkout@v3\n \n - name: Setup Node.js\n uses: actions/setup-node@v3\n with:\n node-version: '18'\n \n - name: Install dependencies\n run: npm ci\n \n - name: Run linter\n run: npm run lint\n \n - name: Run tests\n run: npm test\n \n - name: Build project\n run: npm run build\n\nWhat happens here? On every push to main or develop, GitHub launches a virtual machine with Ubuntu, installs Node.js 18, installs dependencies (a clean install via npm ci — faster and more reliable than npm install), checks the code with a linter, runs tests, and builds the project.
If any step fails — the pipeline stops, and you receive a notification.
\n\nStep 3: Add a linter and tests
\n\nESLint and Jest are the standard for JavaScript. Let's configure them