CI/CD example
Node.js and PostgreSQL CI pipeline on Runnable
A complete, copyable workflow with two test jobs, a disposable PostgreSQL service, an npm cache, and test-output artifacts. The public example project includes a lockfile and tests.
Complete workflow YAML
Put this file at .runnable/workflows/ci.yml on the repository default branch. Runnable reads workflows from that root-level directory.
name: Node.js and PostgreSQL CI
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
suite: [unit, db]
services:
postgres:
image: postgres:17
env:
POSTGRES_USER: example
POSTGRES_PASSWORD: example
POSTGRES_DB: example
ports:
- 5432/tcp
options: >-
--health-cmd "pg_isready -U example -d example"
--health-interval 5s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node24-${{ hashFiles('package-lock.json') }}
- name: Install dependencies
run: npm ci
- name: Test ${{ matrix.suite }}
env:
DATABASE_URL: postgresql://example:example@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/example
run: |
set -o pipefail
npm run test:${{ matrix.suite }} 2>&1 | tee test-output.txt
- uses: actions/upload-artifact@v4
if: always()
with:
name: node24-${{ matrix.suite }}-test-output
path: test-output.txt
if-no-files-found: warnView the complete example project for its package lock and test files. The project is a folder in the public Runnable repository; copy its contents to the root of your own repository before connecting it.
How the pipeline works
The two matrix values run the unit and database suites as separate jobs. Each job gets a clean Linux x64 machine and its own PostgreSQL service.
| Part | Purpose |
|---|---|
| PostgreSQL service | Starts postgres:17, waits for pg_isready, and exposes its assigned port to the test step. The demo credentials belong only to this disposable database. |
| Matrix | Expands suite: [unit, db] into two jobs. A failing suite does not cancel the other one because fail-fast is false. |
| npm cache | Restores ~/.npm using the lockfile hash; npm ci still installs exactly the locked dependency graph in each clean job. |
| Test artifact | The test command writes test-output.txt. The upload step runs even if the test fails, so the output remains available for debugging. |
The runner already includes Node.js 24
Run the example
Use an isolated repository so the sample workflow is discovered at the correct path.
- 1
Copy the project
Copy the contents of the example folder to a repository root, including its.runnable/workflows/ci.ymlandpackage-lock.json. - 2
Connect and scan
Connect the repository through the GitHub App and review its workflow compatibility report. - 3
Push and inspect
Push a commit or open a pull request. Confirm that the unit and db matrix jobs pass, then open each run's test-output artifact.
Adapt it to your own CI
Keep the useful structure, then replace the test commands and database credentials with your application’s needs.
Start with the GitHub Actions compatibility checker for an existing workflow. The workflow reference lists supported syntax and limits, including service containers, matrices, cache, and artifacts.
Do not reuse example credentials

