CI/CD
Apply migrations automatically in your deployment pipeline. Two main patterns: migrations at application startup, or as a separate step before deployment.
Migration File in Git
Store migration files alongside your code:
my-project/
├── revisium/
│ ├── migrations.json # schema migrations
│ └── data/ # seed data (optional)
│ ├── products/
│ │ ├── iphone-16.json
│ │ └── macbook-m4.json
│ └── categories/
│ └── electronics.json
├── src/
└── package.json
Add npm scripts for convenience (Node.js example):
{
"scripts": {
"revisium:save-migrations": "revisium migrate save --file ./revisium/migrations.json --url $REVISIUM_URL",
"revisium:apply-migrations": "revisium migrate apply --file ./revisium/migrations.json --commit --url $REVISIUM_URL"
}
}
Pattern 1: Migrations at Startup
Apply migrations when the application container starts — before the app itself. Common for backend services.
Dockerfile
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist/
COPY --from=builder /app/revisium/ ./revisium/
COPY --from=builder /app/package*.json ./
RUN npm ci --omit=dev
CMD ["npm", "run", "start:prod"]
Startup Command
{
"scripts": {
"start:prod": "npm run revisium:apply-migrations && node dist/main"
}
}
Migrations run before the app starts. If migrations fail, the container fails and Kubernetes restarts it.
Environment Variables
REVISIUM_URL=revisium://revisium.example.com/myorg/myproject/master
REVISIUM_USERNAME=service-account
REVISIUM_PASSWORD=secret
Pattern 2: Separate Migration Container
Build a dedicated migration image with the CLI + migration files. Run it as an init container or CI step before deploying the app.
Migration Dockerfile
FROM revisium/revisium-cli:latest
COPY revisium/migrations.json /app/migrations.json
COPY revisium/data/ /app/data/
Kubernetes Init Container
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
initContainers:
- name: revisium-migrate
image: my-registry/my-app-migrations:latest
command: ["revisium"]
args:
- migrate
- apply
- --file=/app/migrations.json
- --commit
env:
- name: REVISIUM_URL
value: "revisium://revisium.example.com/myorg/myproject/master"
- name: REVISIUM_USERNAME
valueFrom:
secretKeyRef:
name: revisium-credentials
key: username
- name: REVISIUM_PASSWORD
valueFrom:
secretKeyRef:
name: revisium-credentials
key: password
containers:
- name: app
image: my-registry/my-app:latest
CI: Build Two Images
# GitHub Actions — build app + migrations images
jobs:
build:
strategy:
matrix:
include:
- name: app
dockerfile: Dockerfile
context: "."
- name: migrations
dockerfile: revisium/Dockerfile
context: "."
steps:
- uses: actions/checkout@v4
- name: Build and push
uses: docker/build-push-action@v5
with:
context: ${{ matrix.context }}
file: ${{ matrix.dockerfile }}
push: true
tags: my-registry/my-app-${{ matrix.name }}:latest
Data Seeding
Upload seed data alongside migrations — useful for initial setup or test environments.
Kubernetes Seeding Job
apiVersion: batch/v1
kind: Job
metadata:
name: revisium-seed
spec:
template:
spec:
containers:
- name: revisium-cli
image: my-registry/my-app-migrations:latest
command: ["/bin/sh", "-c"]
args:
- |
revisium migrate apply --file /app/migrations.json --commit && \
revisium rows upload --folder /app/data --commit
env:
- name: REVISIUM_URL
value: "revisium://revisium.example.com/myorg/myproject/master"
- name: REVISIUM_USERNAME
valueFrom:
secretKeyRef:
name: revisium-credentials
key: username
- name: REVISIUM_PASSWORD
valueFrom:
secretKeyRef:
name: revisium-credentials
key: password
restartPolicy: OnFailure
GitHub Actions
Token Authentication (recommended)
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Apply Migrations
run: npx revisium migrate apply --file ./revisium/migrations.json --commit
env:
REVISIUM_URL: revisium://cloud.revisium.io/${{ vars.ORG }}/${{ vars.PROJECT }}/master
REVISIUM_TOKEN: ${{ secrets.REVISIUM_TOKEN }}
Username/Password Authentication
- name: Apply Migrations
run: npx revisium migrate apply --file ./revisium/migrations.json --commit
env:
REVISIUM_URL: revisium://cloud.revisium.io/${{ vars.ORG }}/${{ vars.PROJECT }}/master
REVISIUM_USERNAME: ${{ secrets.REVISIUM_USERNAME }}
REVISIUM_PASSWORD: ${{ secrets.REVISIUM_PASSWORD }}
Docker Image Approach
- name: Apply Migrations
run: |
docker run --rm \
-e REVISIUM_URL=revisium://cloud.revisium.io/${{ vars.ORG }}/${{ vars.PROJECT }}/master \
-e REVISIUM_TOKEN=${{ secrets.REVISIUM_TOKEN }} \
-v ${{ github.workspace }}/revisium/migrations.json:/app/migrations.json \
revisium/revisium-cli \
revisium migrate apply --file /app/migrations.json --commit
Full Pipeline with Migrations and Seed Data
name: Full Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Apply Schema Migrations
run: npx revisium migrate apply --file ./revisium/migrations.json --commit
env:
REVISIUM_URL: revisium://cloud.revisium.io/${{ vars.ORG }}/${{ vars.PROJECT }}/master
REVISIUM_TOKEN: ${{ secrets.REVISIUM_TOKEN }}
- name: Upload Seed Data
if: github.ref == 'refs/heads/main'
run: npx revisium rows upload --folder ./revisium/data --commit
env:
REVISIUM_URL: revisium://cloud.revisium.io/${{ vars.ORG }}/${{ vars.PROJECT }}/master
REVISIUM_TOKEN: ${{ secrets.REVISIUM_TOKEN }}
- name: Deploy Application
run: # your deployment step
GitLab CI
stages:
- migrate
- deploy
migrate:
stage: migrate
image: revisium/revisium-cli:latest
script:
- revisium migrate apply --file ./revisium/migrations.json --commit
variables:
REVISIUM_URL: revisium://revisium.example.com/$REVISIUM_ORG/$REVISIUM_PROJECT/master
REVISIUM_TOKEN: $REVISIUM_TOKEN
only:
- main
deploy:
stage: deploy
script: # your deployment step
only:
- main
Docker Run (Manual)
# Apply migrations
docker run --rm \
-e REVISIUM_URL=revisium://cloud.revisium.io/myorg/myproject/master \
-e REVISIUM_TOKEN=$TOKEN \
-v ./revisium/migrations.json:/app/migrations.json \
revisium/revisium-cli \
revisium migrate apply --file /app/migrations.json --commit
# Upload seed data
docker run --rm \
-e REVISIUM_URL=revisium://cloud.revisium.io/myorg/myproject/master \
-e REVISIUM_TOKEN=$TOKEN \
-v ./revisium/data:/app/data \
revisium/revisium-cli \
revisium rows upload --folder /app/data --commit
Best Practices
Dev (source of truth)
│
│ migrate save / sync schema
↓
Staging (test)
│
│ migrate apply / sync schema
↓
Production
- Migrations before app — apply migrations before the application starts or deploys
- One direction — schema changes originate from dev, flow to staging, then production. Never backwards
- Token auth for CI — use
REVISIUM_TOKENinstead of username/password in pipelines - Idempotent — safe to retry on failure, already-applied migrations are skipped
- Commit after apply — use
--committo create a revision after migrations - Test on staging — always apply to staging before production
- Version control — commit migration files to Git, review schema changes in PRs