GitLab Pipeline for Node.js Project
Learn how to create a practical GitLab CI/CD pipeline for a Node.js project. This guide covers npm install, lint, test, build, cache, artifacts, Docker image build, deployment rules, environments, and best practices.
Table of contents
- Quick answer
- Sample Node.js project structure
- Basic Node.js pipeline
- npm cache and artifacts
- Lint, test, and build stages
- Docker image pipeline
- Branch rules and deployment jobs
- Variables and secrets
- Common mistakes
- Best practices
- Related Melochip guides
Quick answer
Use npm ci
Use npm ci in CI because it installs dependencies from package-lock.json in a predictable way.
Cache dependencies
Use cache for npm download speed, not for required build output.
Save build output
Use artifacts for dist/ , test reports, coverage reports, or packaged files.
Deploy safely
Use branch rules, environments, protected variables, and manual production deployment.
1. Sample Node.js project structure
A simple Node.js application may look like this:
my-node-app/ src/ tests/ package.json package-lock.json Dockerfile .gitlab-ci.yml
Your package.json should define scripts that GitLab can run:
{ "scripts": { "lint": "eslint .", "test": "jest --ci", "build": "npm run compile", "start": "node dist/server.js" } }
2. Basic GitLab pipeline for Node.js
image: node:20 stages: - install - test - build install_dependencies: stage: install script: - npm ci run_tests: stage: test script: - npm test build_app: stage: build script: - npm run build
This is a clean beginner pipeline. It installs dependencies, runs tests, and builds the application.
3. npm cache and artifacts
In GitLab CI/CD, cache and artifacts are different:
| Feature | Use for Node.js | Example |
|---|---|---|
| Cache | Speeding up npm downloads | .npm/ |
| Artifacts | Required build output | dist/ , coverage reports |
image: node:20 cache: key: files: - package-lock.json paths: - .npm/ install_dependencies: stage: install script: - npm ci --cache .npm --prefer-offline
4. Complete lint, test, and build pipeline
image: node:20 stages: - install - validate - test - build cache: key: files: - package-lock.json paths: - .npm/ install_dependencies: stage: install script: - npm ci --cache .npm --prefer-offline artifacts: paths: - node_modules/ expire_in: 1 hour lint_code: stage: validate script: - npm run lint run_tests: stage: test script: - npm test artifacts: when: always paths: - coverage/ expire_in: 1 week build_app: stage: build script: - npm run build artifacts: paths: - dist/ expire_in: 1 week
5. Build Docker image for Node.js app
After testing and building the app, many teams package Node.js applications as Docker images.
Sample Dockerfile
FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --omit=dev COPY . . EXPOSE 3000 CMD ["npm", "start"]
GitLab Docker build job
build_docker_image: stage: build image: docker:27 services: - docker:27-dind variables: DOCKER_TLS_CERTDIR: "/certs" IMAGE_TAG: "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" script: - echo "$CI_REGISTRY_PASSWORD" | docker login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" --password-stdin - docker build -t "$IMAGE_TAG" . - docker push "$IMAGE_TAG" rules: - if: '$CI_COMMIT_BRANCH == "main"'
6. Branch rules and deployment jobs
Use rules to control when jobs should run.
deploy_development: stage: deploy script: - echo "Deploying Node.js app to development" environment: name: development rules: - if: '$CI_COMMIT_BRANCH == "develop"' deploy_production: stage: deploy script: - echo "Deploying Node.js app to production" environment: name: production rules: - if: '$CI_COMMIT_BRANCH == "main"' when: manual - when: never
7. Variables and secrets
Node.js applications often need environment values such as API URLs, database URLs, JWT secrets, registry credentials, or deployment keys. Store these in GitLab CI/CD variables, not in source code.
| Variable | Example use | Recommended protection |
|---|---|---|
| NODE_ENV | Set runtime mode | Normal variable |
| API_BASE_URL | Frontend/backend API URL | Environment scoped if needed |
| DATABASE_URL | Backend database connection | Masked/protected |
| JWT_SECRET | Token signing secret | Masked/protected |
| KUBE_CONFIG | Kubernetes deployment access | File/protected variable |
Common mistakes
| Mistake | Problem | Better approach |
|---|---|---|
| Using npm install in CI | Can change dependency versions unexpectedly. | Use npm ci with lock file. |
| No package-lock.json | Builds may not be reproducible. | Commit lock file. |
| Using cache as build output | Deploy job may not receive files reliably. | Use artifacts for required output. |
| Printing secrets | Credentials can leak in logs. | Use masked/protected variables and avoid echoing secrets. |
| Deploying every branch | Unsafe and noisy deployments. | Use rules and environments. |
| Using only latest Docker tag | Hard to audit or rollback. | Use commit SHA/version tags. |
Best practices
- Use npm ci instead of npm install in CI.
- Commit package-lock.json .
- Keep package.json scripts clear and reusable.
- Run lint and tests before build/deploy.
- Use cache for npm download speed.
- Use artifacts for dist/ , reports, and build output.
- Use Docker image tags based on commit SHA.
- Use protected variables for production secrets.
- Use manual production deployment.
- Review pipeline logs and fix flaky tests early.
Screenshot checklist
- Pipeline graph showing install, validate, test, build, deploy.
- Job log showing npm ci .
- Artifacts page showing dist/ output.
- Cache configuration in pipeline.
- Docker image pushed to registry.
- Manual production deployment button.
- GitLab CI/CD Learning Path
- GitLab CI/CD YAML Syntax Explained
- GitLab Artifacts vs Cache Explained
- GitLab CI/CD Docker Build Pipeline
- GitLab CI/CD Best Practices for DevOps Teams
- Dockerfile Instructions Explained
Official references
- GitLab CI/CD YAML syntax reference
- GitLab CI/CD cache documentation
- GitLab job artifacts documentation
- npm ci documentation
Conclusion
A good GitLab pipeline for Node.js should be predictable, fast, and safe. Start with npm ci , lint, test, and build. Then add cache, artifacts, Docker image builds, deployment rules, environments, and protected variables as your project grows.
Keep the pipeline simple enough for the whole team to understand, but strict enough to protect production releases.
Join the discussion
0 CommentsAsk questions, add context, or share what worked.
More from Melochip Editorial
Learn what Playwright testing is, why modern QA teams use it, how testers can get started, and the major types...
7 min read · Sep 19, 2026
Learn how Kubernetes Deployments and ReplicaSets work with practical YAML, scaling, self-healing, rolling upda...
7 min read · Sep 17, 2026
Learn Kubernetes security best practices with RBAC, Secrets, ServiceAccounts, Pod securityContext, NetworkPoli...
6 min read · Sep 17, 2026Related articles
Learn Linux from the ground up with simple explanations of the kernel, distributions, filesystem, commands, pe...
4 min read · Updated Oct 1, 2026
Learn how Kubernetes Deployments and ReplicaSets work with practical YAML, scaling, self-healing, rolling upda...
7 min read · Sep 17, 2026
Learn Kubernetes security best practices with RBAC, Secrets, ServiceAccounts, Pod securityContext, NetworkPoli...
6 min read · Sep 17, 2026
Learn Kubernetes monitoring and logs with kubectl logs, events, metrics-server, top commands, Prometheus, Graf...
5 min read · Sep 17, 2026Stay in the loop. Get new Melochip articles
Receive Melochip article updates when new articles are available. Explicit opt-in only.
No comments yet. Start the discussion.