Deploying
A "deploy" is taking an artifact (a zipped dotnet publish output) and rolling it out to a slot. There are three ways to start one: the CLI, the dashboard upload, and the GitHub webhook.
Via the CLI
velixir deploy
This:
- Runs
dotnet publish -c Releasein the current directory. - Tars the output into
.velixir/publish.tar.gz. - Asks the platform for a presigned S3 upload URL and PUTs the tar straight to object storage.
- Finalises the release (so we record the artifact size + detect the entry-point DLL).
- Enqueues a deployment and polls until it lands or fails.
If the build fails locally, you'll see dotnet's error output and nothing is uploaded. If the deploy fails server-side, the failure reason streams back to your terminal.
Via the dashboard
From an app's Overview tab, click Upload artifact. Pick a .zip or .tar.gz of your dotnet publish output. We sign a one-time URL pointing at object storage; your browser uploads directly to that URL (no proxy hop, no Cloudflare body-size cap).
Via GitHub Actions (the push-to-deploy path)
Velixir doesn't build server-side. Your GitHub Actions runner does the dotnet publish, uploads the result as a workflow artifact, and Velixir pulls that artifact down when the workflow finishes. This means:
- You don't pay us for build compute. The runner is your CI's own infrastructure.
- The same artifact that passed CI is the one that gets deployed. No drift, no "works in CI but breaks in prod because of a different build environment".
- One-click install. A real GitHub App — no PATs, no webhook secrets to paste, no organisation-wide OAuth scopes. You authorise the Velixir App on a single repo, GitHub redirects back, you're done.
1. Add the deploy workflow to your repo
Drop this in .github/workflows/velixir.yml:
name: Build and publish for Velixir
on:
push:
branches: [main] # change to your deploy branch
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Publish
run: dotnet publish -c Release -o publish
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: velixir-publish # must match Velixir's artifact name setting
path: publish/
retention-days: 7
That's it for the workflow side — no Velixir CLI invocations, no API keys in your repo secrets, no actions/checkout token magic.
2. Connect GitHub from Velixir
On your app's Security tab in the dashboard, click Connect GitHub. We redirect you to GitHub's install page for the Velixir App; you pick which repo to grant access to (just the one this app deploys from — install per-repo, not "all repositories", to keep the blast radius tight).
GitHub redirects you back to Velixir with an installation ID. We persist that and verify the integration is reachable by listing what we can see — you'll get a success toast that names the repo.
The Velixir GitHub App asks for exactly two scopes:
- Actions: Read — list workflow runs, list and download artifacts. The whole point.
- Metadata: Read — implicit on every fine-grained installation; required by GitHub for the App to exist.
Nothing else. We can't see your code (no Contents permission), can't merge PRs, can't push, can't modify the repo.
3. Push and watch the deploy
Push to the configured branch. GitHub Actions runs your workflow. When it completes successfully, GitHub fires a workflow_run webhook to Velixir. We:
- Verify the HMAC against the App's shared webhook secret.
- Find the matching Velixir app by repo URL.
- Mint a short-lived installation token (signed JWT → 1-hour token).
- List the run's artifacts, find the one named
velixir-publish. - Download it via GitHub's API, stream it into our object storage.
- Analyse the artifact for the entry-point DLL + listen port.
- Create a release row, enqueue a deployment.
Watch the Overview tab — a new release appears within a minute, then a deployment, then the live badge moves to it.
Disconnecting
Two halves to disconnecting cleanly, depending on how clean you want to be:
- Soft disconnect (Velixir side only). On the Deploys tab, click Disconnect. We forget the installation ID; workflow_run events for the repo are now ignored. The Velixir App is still installed on GitHub but we won't call its API.
- Hard disconnect (full revoke). Go to GitHub → Settings → Integrations → Applications → Installed GitHub Apps → Velixir → Uninstall. GitHub revokes the installation immediately; even if we still had the ID we couldn't mint tokens against it.
Use the soft path if you're just pausing the integration; use the hard path if you want our access entirely gone from the repo.
Common gotchas
- No artifact uploaded. Your workflow ran but didn't call
actions/upload-artifact— or used a differentname:than the one Velixir expects (defaultvelixir-publish; configurable on the Deploys tab). - Workflow failed. Velixir only pulls on
conclusion: success. If the workflow concludedfailure/cancelled/timed_out, you'll see an audit-log entry but no deploy. Fix the CI run and re-push. - Branch mismatch. If you set a Deploy branch on the app, only workflow_runs triggered from that branch fire a deploy. Leave it blank to deploy from any branch.
- App uninstalled out-of-band. If you remove the Velixir App from your repo on github.com, the next workflow_run we receive will surface an "installation_missing" audit entry. Reconnect from the Deploys tab.
Slots
Every app has at least one slot (production). You can deploy to a different slot to stage a release without touching live traffic:
velixir deploy --slot staging
From the dashboard's Slots tab you can then Promote that slot to live — a near-instant swap, the staged pods become production and the previously-live pods stay warm so you can flip back if anything's wrong.
Rollback
Every previous deploy is available from the Releases table on the Overview tab. Hit Redeploy on any earlier release to bring it back; we rebuild the pod with that artifact and the edge cuts traffic over once it's healthy.
After a deploy
- Set environment variables on the Environment tab — they're injected on the next deploy.
- The Logs tab tails container output live.
- The Metrics strip on the Overview tab updates every 10 seconds with replica count, CPU, memory, and HTTP traffic.