Why CI/CD Matters
Continuous Integration (CI) and Continuous Deployment (CD) are core practices for any team shipping software. Projects of every size are prone to errors, but a solid CI/CD pipeline with well-written tests makes those errors significantly easier to locate and resolve.
This guide walks through building that pipeline with a specific toolset: CircleCI for automation, Coveralls for tracking test coverage, and Heroku for hosting a Vue application. The specific stack isn't the takeaway—the underlying principles apply regardless of which frameworks or platforms you use.
Before we begin, a few definitions:
- Continuous integration: The practice of committing code frequently and running test and build processes on it before merging or deploying.
- Continuous deployment: Keeping software in a state where it can be deployed to production at any time.
- Test coverage: A metric describing how much of a codebase is executed during testing. High coverage means most code paths are verified.
To follow along, you'll need accounts for CircleCI, GitHub, Heroku, and Coveralls, plus the NYC package for measuring coverage.
Preparing the Project
Start by installing NYC:
npm i nyc
Update the scripts section in package.json. If coverage should run alongside unit tests, modify the existing test script:
"scripts": {
"test:unit": "nyc vue-cli-service test:unit",
},
That command assumes a Vue setup, as it references cue-cli-service. Adjust it according to your framework.
To run coverage separately, add another script entry:
"scripts": {
"test:unit": "nyc vue-cli-service test:unit",
"coverage": "nyc npm run test:unit"
},
Coverage is then checked from the terminal:
npm run coverage
Install Coveralls to handle reporting:
npm i coveralls
Add Coveralls as another script—this one uploads the coverage report:
"scripts": {
"test:unit": "nyc vue-cli-service test:unit",
"coverage": "nyc npm run test:unit",
"coveralls": "nyc report --reporter=text-lcov | coveralls"
},
Register the app in your Heroku dashboard, then move to the CircleCI dashboard to connect your project.
Connecting CircleCI
From the Projects tab, find your repository under your GitHub organization and click "Set Up Project." When asked about configuration, choose "Use an existing config" since one will be provided.
You'll be taken to the project's pipeline, confirming the repository is connected. Next, configure environment variables in the project settings:

Open project settings and navigate to Environment Variables:

Three variables are needed:
HEROKU_APP_NAME: Your Heroku app nameHEROKU_API_KEY: Available in the account section of the Heroku dashboardCOVERALLS_REPO_TOKEN: Found after adding your repository to Coveralls
Add the repo on Coveralls by selecting it from the list of GitHub repositories:

After the repository is linked, open it to retrieve the token:

Writing the CircleCI Configuration
In the project root, create a .circleci directory containing a config.yml file:

The configuration looks like this:
version: 2.1
orbs:
node: circleci/[email protected] // node orb
heroku: circleci/[email protected] // heroku orb
coveralls: coveralls/[email protected] // coveralls orb
workflows:
heroku_deploy:
jobs:
- build
- heroku/deploy-via-git: # Use the pre-configured job
requires:
- build
filters:
branches:
only: master
jobs:
build:
docker:
- image: circleci/node:10.16.0
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ checksum "package.json" }}
- run:
name: install-npm-dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- ./node_modules
- run: # run tests
name: test
command: npm run test:unit
- run: # run code coverage report
name: code-coverage
command: npm run coveralls
- run: # run build
name: Build
command: npm run build
# - coveralls/upload
Here's what each major piece does.
Orbs
orbs:
node: circleci/[email protected] // node orb
heroku: circleci/[email protected] // heroku orb
coveralls: coveralls/[email protected] // coveralls orb
Orbs are reusable packages that simplify integrating third-party tools. The config declares the node orb for JavaScript, heroku for deployment, and coveralls for uploading coverage results.
The Heroku and Coveralls orbs are external, so CircleCI will error until uncertified orbs are allowed. Find Organization Settings, then the Security tab, and enable that option:

Workflows
workflows:
heroku_deploy:
jobs:
- build
- heroku/deploy-via-git: # Use the pre-configured job
requires:
- build
filters:
branches:
only: master
A workflow defines a set of jobs and their execution order. This config builds the project first, then deploys. The requires key ensures the heroku/deploy-via-git job runs only after the build succeeds.
Jobs
jobs:
build:
docker:
- image: circleci/node:10.16.0
steps:
- checkout
- restore_cache:
key: dependency-cache-{{ checksum "package.json" }}
- run:
name: install-npm-dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package.json" }}
paths:
- ./node_modules
Jobs are step collections. The restore_cache step brings back dependencies from earlier builds. Un-cached dependencies get installed, then saved so subsequent builds skip that step. Caching speeds up later runs considerably.
After dependency setup, CircleCI executes the project's tests.
Sending Coverage to Coveralls
- run: # run tests
name: test
command: npm run test:unit
- run: # run code coverage report
name: code-coverage
command: npm run coveralls
# - coveralls/upload
The unit tests run here, but because NYC was added to the test:unit script, coverage data is collected at the same time. The output includes coverage from unit tests, and the final step runs the Coveralls script that uploads that report.
The coveralls/upload line is commented out—it was intended to finish the process but behaved unpredictably, so it's left disabled as a potential alternative for developers who need it.
The Complete Setup
The resulting app is hosted on Heroku with automated testing and deployment wired through CircleCI, with coverage tracked by Coveralls:

The value of this pipeline becomes clear during active development or testing cycles, where frequent small commits require rapid iteration. Automating test runs and deployments removes repetitive manual work—worth the initial setup effort for teams that want to catch regressions early and keep production releasable.



