Skip to content

GitLab CI/CD customization

Customize the automated build and deployment pipeline for GitLab Pages.

Overview

When you publish a Silex website to GitLab Pages, Silex creates a .gitlab-ci.yml file in your repository. This file defines a CI/CD pipeline that:

  1. Installs dependencies
  2. Runs build awesome (powered by Eleventy) to build the static site
  3. Deploys to GitLab Pages

You can customize the pipeline to add build steps, caching, custom domains, or integration with external services.

Prerequisites

  • Website stored in GitLab (via GitLab storage connector)
  • Basic understanding of GitLab CI/CD
  • Knowledge of shell scripts and Node.js

Default pipeline

Silex generates a standard .gitlab-ci.yml:

image: node:18

stages:
  - build
  - deploy

variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"

cache:
  paths:
    - .npm
    - node_modules

before_script:
  - npm ci --prefer-offline --no-audit

build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - _site/
    expire_in: 1 week

pages:
  stage: deploy
  script:
    - echo "Deploying to GitLab Pages"
  artifacts:
    paths:
      - public/
  environment:
    name: production
    url: https://$CI_PROJECT_NAMESPACE.gitlab.io/$CI_PROJECT_NAME
  only:
    - main

Customizing the pipeline

Edit .gitlab-ci.yml directly in your GitLab repository.

Adding a build step

Run custom commands after the default build:

build:
  stage: build
  script:
    - npm run build
    - npm run lint          # Add linting
    - npm run test          # Add tests
  artifacts:
    paths:
      - _site/

Environment variables

Pass secrets or configuration to the pipeline:

variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"
  CUSTOM_ENV_VAR: "value"    # Custom variable

Or set in GitLab project settings:

  1. Go to SettingsCI/CDVariables
  2. Add variable: MY_SECRET = secret-value
  3. Use in pipeline: $MY_SECRET

Protected variables (only on protected branches):

variables:
  DEPLOY_KEY:
    value: "secret"
    protected: true

Artifact retention

Control how long build artifacts are kept:

artifacts:
  paths:
    - _site/
  expire_in: 30 days    # Keep for 30 days

Cache dependencies

Speed up builds by caching npm packages:

cache:
  paths:
    - .npm
    - node_modules/
  policy: pull-push      # Pull from cache, push new items

Or cache only on specific branches:

cache:
  key:
    files:
      - package-lock.json
  paths:
    - node_modules/
  policy: pull           # Only pull from cache (never update)

Using different Node versions

Build with a specific Node.js version:

image: node:18          # Use Node 18

Or use a matrix to test multiple versions:

build:
  parallel:
    matrix:
      - NODE_VERSION: [16, 18, 20]
  image: node:$NODE_VERSION
  script:
    - npm run build

Running scripts in parallel

Speed up the pipeline by running independent steps in parallel:

stages:
  - build
  - test
  - deploy

build:
  stage: build
  script:
    - npm ci
    - npm run build

lint:
  stage: test
  script:
    - npm run lint

test:
  stage: test
  script:
    - npm run test

pages:
  stage: deploy
  script:
    - echo "Deploy"

Conditional execution

Only run certain jobs on specific branches:

deploy_production:
  stage: deploy
  script:
    - npm run build:prod
  only:
    - main       # Only on main branch

deploy_staging:
  stage: deploy
  script:
    - npm run build:staging
  only:
    - develop    # Only on develop branch

deploy_manual:
  stage: deploy
  script:
    - npm run build
  when: manual   # Requires manual trigger

Using Docker images

Build with a custom Docker image:

image: mycompany/silex-builder:latest

# Or use multiple images for different jobs
build:
  image: node:18-alpine
  script:
    - npm run build

test:
  image: ruby:3.0
  script:
    - bundle install
    - bundle exec rspec

Including external files

Share CI/CD configuration across repositories:

include:
  - remote: 'https://example.com/ci-templates/silex.yml'
  - project: 'my-org/ci-templates'
    file: 'silex-base.yml'
  - local: '.gitlab/ci-base.yml'

Notifications and integrations

Send notifications after builds:

pages:
  stage: deploy
  script:
    - npm run build
  after_script:
    - 'curl -X POST https://hooks.slack.com/... -d "{"text":"Deployment complete"}"'

Or integrate with external services:

after_script:
  - 'curl -X POST https://api.example.com/deployments'

Advanced configuration

Custom build for Build awesome

If your build awesome setup needs special handling:

build:
  stage: build
  script:
    - npm ci
    - npm run eleventy    # Custom 11ty build command
    - npm run minify-css  # Post-processing
  artifacts:
    paths:
      - _site/

Preinstall step

Run setup before builds:

before_script:
  - npm ci --prefer-offline
  - npm run setup        # Custom setup

Using the silexOverwrite flag

Control whether to overwrite existing files on republish:

variables:
  SILEX_OVERWRITE: "true"    # Overwrite on publish

Set in Silex publishing settings or pass via CI/CD variable.

Custom deployment steps

Add cleanup or post-deploy tasks:

pages:
  stage: deploy
  script:
    - echo "Deploying"
  after_script:
    - echo "Cleaning up"
    - rm -rf ./temp/
  artifacts:
    paths:
      - public/

Custom domain configuration

Configure a custom domain for GitLab Pages:

pages:
  environment:
    name: production
    url: https://my-custom-domain.com    # Custom domain
  artifacts:
    paths:
      - public/

In GitLab project settings, also add the domain:

  1. DeploymentsPages
  2. DomainsNew domain
  3. Enter domain and follow DNS setup

URL redirections

GitLab Pages supports a _redirects file at the root of the published site, using the same syntax as Netlify redirects. This is useful for:

  • Preserving old URLs when you reorganize documentation or pages
  • Redirecting short URLs to full paths
  • Handling moved content without breaking bookmarks or search engine links

Create a _redirects file in your repository:

# _redirects
/old-page    /new-page    301
/blog/:slug  /articles/:slug  301

Each line has three fields separated by spaces: the old path, the new path, and the HTTP status code (301 for permanent redirect, 302 for temporary).

Make sure the file ends up in the public/ directory after the build. Add a copy step to your pipeline if needed:

pages:
  script:
    - npm ci
    - npx @11ty/eleventy --input=public --output=_site
    - cp _redirects _site/ 2>/dev/null || true
    - rm -rf public && mv _site public

See GitLab Pages redirects documentation for the full syntax (splat rules, query parameters, forced redirects).

Building and deploying to multiple environments

Deploy to production and staging:

stages:
  - build
  - deploy

build:
  stage: build
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - _site/

deploy_prod:
  stage: deploy
  script:
    - echo "Deploy to production"
  environment:
    name: production
    url: https://prod.example.com
  only:
    - main

deploy_staging:
  stage: deploy
  script:
    - echo "Deploy to staging"
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - develop

Complete example

A full .gitlab-ci.yml with testing, linting, and caching:

image: node:18-alpine

stages:
  - install
  - build
  - test
  - deploy

variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"
  NODE_ENV: "production"

cache:
  key:
    files:
      - package-lock.json
  paths:
    - .npm
    - node_modules/

install:
  stage: install
  script:
    - npm ci --prefer-offline --no-audit

build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - _site/
    expire_in: 1 week

lint:
  stage: test
  script:
    - npm run lint:css
    - npm run lint:js
  allow_failure: true

test:
  stage: test
  script:
    - npm run test
  coverage: '/Coverage: (\d+)%/'

pages:
  stage: deploy
  script:
    - mkdir -p public
    - cp -r _site/* public/
  artifacts:
    paths:
      - public/
  environment:
    name: production
    url: https://$CI_PROJECT_NAMESPACE.gitlab.io/$CI_PROJECT_NAME
  only:
    - main

Troubleshooting

Pipeline fails with "npm not found"

Ensure the Docker image includes Node.js:

image: node:18    # Correct
# NOT: image: ubuntu:latest

Artifacts not deployed

Check:

  1. Artifacts are in public/ directory
  2. Job is in the deploy stage
  3. Job is named pages
  4. only rule allows the branch

Pipeline is slow

Optimize:

  1. Add caching for node_modules/ and .npm
  2. Use smaller Docker images (alpine variants)
  3. Run jobs in parallel when possible
  4. Cache external dependencies

Environment URL not working

Ensure:

  1. Domain is correct: https://username.gitlab.io/project-name
  2. Custom domain DNS is configured
  3. GitLab Pages is enabled in project settings

See also

Edit this page on GitLab