CI/CD Build and Release Process
Yew Search uses both GitHub Actions and GitLab CI for building and publishing Docker images. Both CI systems support versioned releases using CalVer (YYYY.MM.DD.patch) format.
Overview
On GitLab CI, VERSION_TAG is required, not optional - each manual
build job validates it against ^[0-9]{4}\.[0-9]{2}\.[0-9]{2}\.[0-9]+$
(the CalVer format) and fails immediately if it's missing or malformed.
This is a deliberate choice: there's no "just build without a version"
path anymore.
All GitLab builds produce these tags:
- Commit SHA - Unique identifier for this exact build (e.g.,
:9124435e) :latest- Always applied to every build- CalVer version - Required (e.g.,
:2026.11.05.0)
GitHub Actions' manual workflows are simpler: a single tag input
(default latest), no CalVer validation - you can type any string,
including a CalVer one if you want parity with the GitLab-built image.
GitLab CI - Triggering Versioned Builds
Available Jobs
GitLab CI provides six manual build jobs:
manual-build-backend- Builds the NestJS backend APImanual-build-frontend- Builds the Svelte frontend applicationmanual-build-docs- Builds the documentation sitemanual-build-website- Builds the marketing websitemanual-build-api-docs- Builds the generated API reference docsmanual-build-proxy- Builds the Tor proxy image (proxy/)
...plus a matching manual-deploy-* job for each of backend, frontend,
website, docs, and api-docs, and a separate manual-run-production-migration
job for running a database migration ahead of (or independent of) a
deploy. All of these are manual, triggered the same way as the build jobs
below.
There's also a workflow that runs automatically on every push to any
branch, not manually - .github/workflows/push->*->api-lint-e2e.yaml -
which lints the backend and runs the full unit + e2e test suite against
real Postgres/Redis service containers. This is the one that actually
gates whether a change is safe, independent of any manual build/deploy.
How to Trigger a Build
Step 1: Go to CI/CD Pipelines
Navigate to your GitLab project:
Your Project → CI/CD → Pipelines
Step 2: Run Pipeline
Click "Run pipeline" button in the top right
Step 3: Set the Version Variable (Required)
In the pipeline configuration:
- Leave "Run for branch name or tag" as
main(or select your desired branch) - In the Variables section, add:
- Key:
VERSION_TAG - Value: Your CalVer version, matching
YYYY.MM.DD.patchexactly (e.g.,2026.11.05.0)
- Key:
Note: The job fails immediately if VERSION_TAG is missing or doesn't match that format - this isn't optional. Builds are also always tagged :latest in addition to your version.
Step 4: Run the Build Job
- Click "Run pipeline"
- Wait for pipeline to appear
- Click on the pipeline
- Find the
manual-build-backend(or whichever service you want) job under the "utility" stage - Click the Play button (▶) to trigger the manual job
Example: Building Backend Version 2025.01.27.0
1. Click "Run pipeline"
2. Branch: main
3. Add variable:
- Key: VERSION_TAG
- Value: 2025.01.27.0
4. Click "Run pipeline"
5. In pipeline view, click Play (▶) on "manual-build-backend"
Result: Image will be tagged as:
registry.gitlab.com/your-namespace/yew-monorepo/backend:9124435e(commit SHA)registry.gitlab.com/your-namespace/yew-monorepo/backend:latest(always)registry.gitlab.com/your-namespace/yew-monorepo/backend:2025.01.27.0(your CalVer version)
Building Multiple Services
To build multiple services with the same version:
- Trigger pipeline once with
VERSION_TAG=2025.01.27.0 - Manually trigger all jobs you need:
- Click Play on
manual-build-backend - Click Play on
manual-build-frontend - Click Play on
manual-build-docs - Click Play on
manual-build-website
- Click Play on
All will use the same VERSION_TAG from the pipeline variables.
GitHub Actions - Triggering Versioned Builds
Available Workflows
GitHub Actions provides five manual workflows, named Manual -> Build <Service>:
- Manual -> Build Backend - pushes
ghcr.io/<owner>/yew-backend - Manual -> Build Frontend - pushes
ghcr.io/<owner>/yew-frontend - Manual -> Build Docs - pushes
ghcr.io/<owner>/yew-docs - Manual -> Build Website - pushes
ghcr.io/<owner>/yew-website - Manual -> Hello World - builds the
hello-worldintegration test image
Note the image names are yew-backend/yew-frontend/etc., not bare
backend/frontend - don't drop the yew- prefix when pulling.
How to Trigger a Build
Step 1: Go to Actions Tab
Navigate to your GitHub repository:
Your Repository → Actions tab
Step 2: Select Workflow
In the left sidebar, click on the workflow you want to run (e.g., "Manual -> Build Backend")
Step 3: Run Workflow
- Click the "Run workflow" button (top right of workflow runs list)
- A dropdown will appear with:
- Branch: Select branch to run from (typically
main) - tag: Image tag, defaults to
latest
- Branch: Select branch to run from (typically
Step 4: Specify Version
In the tag field:
For versioned release:
2025.01.27.0
For latest:
latest
(or leave blank to use default)
Step 5: Trigger Build
Click the green "Run workflow" button
Example: Building Frontend Version 2026.11.05.0
1. Go to Actions tab
2. Click "Manual -> Build Frontend" (left sidebar)
3. Click "Run workflow" button
4. Branch: main
5. tag: 2026.11.05.0
6. Click "Run workflow"
Result: Image will be tagged as:
ghcr.io/<owner>/yew-frontend:<commit-sha>(commit SHA)ghcr.io/<owner>/yew-frontend:2026.11.05.0(your tag)
Building Multiple Services
Repeat the process for each service you want to build:
- Run "Manual -> Build Backend" with tag
2026.11.05.0 - Run "Manual -> Build Frontend" with tag
2026.11.05.0 - Run "Manual -> Build Docs" with tag
2026.11.05.0 - Run "Manual -> Build Website" with tag
2026.11.05.0
CalVer Version Format
Yew Search uses Calendar Versioning (CalVer) with the format:
YYYY.MM.DD.patch
Examples
2025.01.27.0- First release on January 27, 20252025.01.27.1- Second release (hotfix) on the same day2025.02.15.0- Release on February 15, 20252026.03.01.0- Release on March 1, 2026
When to Increment
Increment date (YYYY.MM.DD):
- Every new deployment day
- Even if it's just one commit
- Example:
2025.01.27.0→ next day →2025.01.28.0
Increment patch (.patch):
- Multiple releases on the same day
- Usually for hotfixes or urgent deployments
- Example:
2025.01.27.0→ hotfix same day →2025.01.27.1
Generating Today's Version
To generate a version for today:
# Basic version (patch = 0)
date +%Y.%m.%d.0
# Output: 2025.01.27.0
For subsequent releases on the same day, manually increment the patch number.
Best Practices
1. Coordinate Frontend and Backend Releases
Always build frontend and backend with the same version tag:
Backend: registry.gitlab.com/your-namespace/yew-monorepo/backend:2025.01.27.0
Frontend: registry.gitlab.com/your-namespace/yew-monorepo/frontend:2025.01.27.0
This ensures compatibility and makes it clear which versions were released together.
2. Tag Git Commits
After building a release, tag the git commit:
git tag 2025.01.27.0
git push origin 2025.01.27.0
This creates a permanent reference to the code that produced this release.
3. Document Releases
Keep a record of what each release contains:
2025.01.27.0
- Added OAuth reauth functionality
- Fixed sidebar mobile navigation
- Updated polling system for integrations
2025.01.20.0
- Initial Gmail integration polling
- Migration system improvements
4. Test Before Promoting to Latest
If testing a new feature:
- Build with version tag:
2025.01.27.0-beta - Deploy to staging environment
- Test thoroughly
- Build production release:
2025.01.27.0(from main branch)
5. Use Commit SHA for Debugging
If you need to debug a specific build:
# In docker-compose.yml
image: registry.gitlab.com/your-namespace/yew-monorepo/backend:9124435e
This gives you exact reproducibility.
Image Registries
GitLab Container Registry
Location: registry.gitlab.com/your-namespace/yew-monorepo/
Images:
backend:TAGfrontend:TAGdocs:TAGwebsite:TAG
Authentication:
echo $GITLAB_TOKEN | docker login registry.gitlab.com -u your-username --password-stdin
GitHub Container Registry (ghcr.io)
Location: ghcr.io/your-username/
Images:
yew-backend:TAGyew-frontend:TAGyew-docs:TAGyew-website:TAG
Authentication:
echo $GITHUB_TOKEN | docker login ghcr.io -u your-username --password-stdin
Viewing Available Tags
GitLab
Navigate to:
Your Project → Packages & Registries → Container Registry
Click on any image to see all available tags.
GitHub
Navigate to:
Your Repository → Packages (right sidebar)
Click on any package to see all available tags.
Troubleshooting
Build Fails with "Set VERSION_TAG when starting the pipeline"
Cause: VERSION_TAG is required on every GitLab manual build job now - it wasn't set, or was left as the literal placeholder yyyy.mm.dd.version.
Solution: Set the VERSION_TAG CI/CD variable to a real CalVer value (YYYY.MM.DD.patch) before running the pipeline.
Image Tagged as "latest" When I Specified a Version
Expected behavior on default branch (main):
- Custom version builds are ALSO tagged as
:latest - This ensures
:latestalways points to the newest release
To prevent this: Build from a feature branch instead of main
GitHub Actions: "Tag to use for Docker image" Field Missing
Cause: Your workflow file may be outdated
Solution: Check that your workflow file (.github/workflows/manual->build-*.yaml) has the workflow_dispatch input defined:
on:
workflow_dispatch:
inputs:
tag:
description: 'Image tag (default: latest)'
required: false
default: 'latest'
Related Documentation
- Why CalVer? - Explanation of our versioning strategy
- Server Deployment - Using versioned images in docker-compose
- Architecture - System architecture overview