Users of your software need to see which version they are running. Coroid gives each release a version and a build number, passes both to the pipeline that builds it, and then checks that the environment is running the release you deployed.
1. Coroid names it
Release
1.4.1
Build 12
From Coroid, a file in your repository, or your pipeline.
2. Your pipeline builds it
Your CI/CD
COROID_VERSION=1.4.1
COROID_BUILD_NUMBER=12
COROID_COMMIT_SHA=3da015d…
These values arrive as variables or workflow inputs.
3. People see it
About
Version 1.4.1 (12)
Displayed in the app and written to release.json.
4. Coroid confirms it
GET /version.json
Verified
The pipeline reported 1.4.1, build 12
After a deployment, Coroid reads the version URL.
All settings on this page are configured per project in Releases → Release settings → Versioning.
Where the version comes from
Choose one source per project:
- Coroid assigns it (the default): Coroid suggests the next version when you prepare a release. It increments the last number of the highest version the project has released, so
1.4.0is followed by1.4.1. The first release is0.1.0. Type a different version whenever you need one. - Read it from the repository: Coroid reads the version your code declares at the release commit. It looks in
VERSION,package.json,app.json(Expo),pubspec.yaml, the Android Gradle file,Cargo.toml,pyproject.tomland the Xcode project, or only in the file you specify. If the file still contains a version used by an earlier release, Coroid asks you to increment it first. - My pipeline assigns it: your CI/CD picks the version, for example via semantic-release or from a tag, and reports it during deployment.
Every release also gets a build number. Build numbers only increase and are never reused within a project, which is a requirement of iOS app stores.
CFBundleVersion and Android versionCode.
What the build receives
When Coroid starts a GitHub Actions workflow or a GitLab CI/CD pipeline for a release, it passes these values:
| GitLab variable | GitHub input | Value |
|---|---|---|
COROID_VERSION | coroid_version | The release version |
COROID_BUILD_NUMBER | coroid_build_number | The build number |
COROID_RELEASE_NAME | coroid_release_name | The release name |
COROID_COMMIT_SHA | coroid_commit_sha | The full commit SHA |
COROID_ENVIRONMENT | coroid_environment | The environment key |
COROID_RELEASE_ID | coroid_release_id | The Coroid release ID |
COROID_ATTEMPT_ID | coroid_attempt_id | The deployment attempt |
GitHub rejects inputs that a workflow does not declare. Therefore, Coroid sends
coroid_version, coroid_build_number and coroid_release_name only to a workflow that lists them. Declare them as optional:
on:
workflow_dispatch:
inputs:
coroid_release_id: { required: true }
coroid_attempt_id: { required: true }
coroid_commit_sha: { required: true }
coroid_environment: { required: true }
coroid_version: { required: false }
coroid_build_number: { required: false }
coroid_release_name: { required: false }
jobs:
deploy:
runs-on: ubuntu-latest
env:
APP_VERSION: ${{ inputs.coroid_version || '0.0.0-dev' }}
APP_BUILD_NUMBER: ${{ inputs.coroid_build_number || '0' }}
APP_COMMIT: ${{ inputs.coroid_commit_sha || github.sha }}GitLab passes the values as variables, so no declaration is required:
deploy:
script:
- export APP_VERSION="${COROID_VERSION:-0.0.0-dev}"
- export APP_BUILD_NUMBER="${COROID_BUILD_NUMBER:-0}"
- export APP_COMMIT="${COROID_COMMIT_SHA:-$CI_COMMIT_SHA}"A pipeline that runs independently can use its own values. Report the version you deployed, as described below, so the release displays it.
Write a release manifest
The simplest approach that works on every platform is to write a small file during the build and read it wherever the version is displayed:
cat > release.json <<EOF
{
"version": "$APP_VERSION",
"buildNumber": "$APP_BUILD_NUMBER",
"commitSha": "$APP_COMMIT",
"releaseName": "${COROID_RELEASE_NAME:-}",
"environment": "${COROID_ENVIRONMENT:-local}"
}
EOFFor a web app or a service, serve the file at /version.json. This also gives Coroid a URL to check (see below).
Recipes
Web apps (Next.js, Vite)
Values the browser needs must be set when the bundle is built:
NEXT_PUBLIC_APP_VERSION="$APP_VERSION" NEXT_PUBLIC_APP_COMMIT="$APP_COMMIT" npm run build
VITE_APP_VERSION="$APP_VERSION" npm run buildShow process.env.NEXT_PUBLIC_APP_VERSION or import.meta.env.VITE_APP_VERSION
in the footer or an About screen, and copy release.json into the public folder before the build.
Servers and APIs
Read the values at start-up and respond via a version endpoint:
app.get('/version.json', (_request, response) => {
response.json({
version: process.env.APP_VERSION,
buildNumber: process.env.APP_BUILD_NUMBER,
commitSha: process.env.APP_COMMIT,
});
});Docker images
Pass the values as build arguments and label the image, so the running container and the registry both know the version:
ARG APP_VERSION=0.0.0-dev
ARG APP_COMMIT=unknown
ENV APP_VERSION=$APP_VERSION APP_COMMIT=$APP_COMMIT
LABEL org.opencontainers.image.version=$APP_VERSION \
org.opencontainers.image.revision=$APP_COMMITdocker build --build-arg APP_VERSION="$APP_VERSION" --build-arg APP_COMMIT="$APP_COMMIT" .iOS
Xcode reads the version shown in the App Store from MARKETING_VERSION and the build number from CURRENT_PROJECT_VERSION:
xcodebuild -scheme App -configuration Release archive \
MARKETING_VERSION="$APP_VERSION" \
CURRENT_PROJECT_VERSION="$APP_BUILD_NUMBER"With fastlane, use increment_version_number(version_number: ENV["APP_VERSION"])
and increment_build_number(build_number: ENV["APP_BUILD_NUMBER"]).
Android
Read the values in app/build.gradle.kts:
android {
defaultConfig {
versionName = System.getenv("APP_VERSION") ?: "0.0.0-dev"
versionCode = (System.getenv("APP_BUILD_NUMBER") ?: "1").toInt()
}
}BuildConfig.VERSION_NAME then displays the version in the app.
Flutter
flutter build appbundle --build-name="$APP_VERSION" --build-number="$APP_BUILD_NUMBER"
flutter build ipa --build-name="$APP_VERSION" --build-number="$APP_BUILD_NUMBER"Expo and React Native
Read the values in app.config.js:
export default {
expo: {
version: process.env.APP_VERSION ?? '0.0.0-dev',
ios: { buildNumber: process.env.APP_BUILD_NUMBER ?? '1' },
android: { versionCode: Number(process.env.APP_BUILD_NUMBER ?? 1) },
},
};Report the version you deployed
A deployment event can indicate which version and build were deployed. Add version
and buildNumber to the event your pipeline already sends:
{
"schemaVersion": 1,
"eventId": "ci:run-812:production:succeeded",
"providerRunId": "run-812",
"projectId": "<project-uuid>",
"environmentKey": "production",
"repository": "owner/repository",
"commitSha": "0123456789abcdef0123456789abcdef01234567",
"status": "succeeded",
"occurredAt": "2026-09-28T12:00:00Z",
"version": "1.4.0",
"buildNumber": "42"
}If the project's pipeline assigns versions, the release uses the reported version. Otherwise, the release page displays the reported version and highlights any differences from the release. For a project hosted on Coroid, set
repository to the project ID. Deployment events and CI setup describes the rest of the event.
Check what's running
Assign a version URL to each environment, such as
https://app.example.com/version.json. Once a deployment succeeds, Coroid
opens the URL and looks for the commit SHA or the version. The reported commit
must match the release commit; if not, the version must align. Coroid keeps
checking for ten minutes while the rollout completes, then displays Verified,
Different version or Not reachable under What's running on the
release page.
The URL must use HTTPS and a public address. Coroid does not follow redirects and reads at most 64 KB.
Let Coroid set it up
Set up version stamping on the Versioning screen opens New Work with a
request drafted for the project's detected tech stack. An agent reads the above values at build time, displays the version in the app, writes release.json,
declares the workflow inputs and documents them in the README. Review the
request, then proceed just like with any other task.