---
title: "Deploy a Bot from GitHub Actions"
description: "Deploy your bot to Silly Development from a GitHub Actions workflow after your tests pass, using the Git deploy API and a repository secret."
url: "https://sillydev.co.uk/docs/panel/recipes/deploy-from-github-actions"
updated: "2026-10-10"
---

Recipe

# Deploy from GitHub Actions

Automatic deploys send every push straight to your server. When you would rather deploy only after your tests pass, have your workflow ask for the deploy instead.

[← API docs](https://sillydev.co.uk/docs/panel) · Updated 10 October 2026

**Browse the docs**

## Before you start

Link the repository to your server in the panel, on the server's GitHub tab, and turn off deploy on push there, so only your workflow deploys. Deploys are run by the server's owner, so the key must belong to the owner and must not be limited to a set of permissions; limit it to this one server instead.

In the repository on GitHub, open Settings, Secrets and variables, Actions, and add the key as a secret named `SILLYDEV_API_KEY`.

## The workflow

This runs your tests on every push to main, and asks for a deploy only if they pass. The deploy request answers at once with the queued deployment; the deploy itself pulls the branch, installs dependencies and restarts the bot, as a deploy from the panel does.

.github/workflows/deploy.yml

```
name: Test and deploy

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to Silly Development
        run: |
          curl --fail-with-body -X POST \
            "https://sillydev.co.uk/panel/api/client/servers/1a7ce997/git/deploy" \
            -H "Authorization: Bearer ${{ secrets.SILLYDEV_API_KEY }}" \
            -H "Accept: application/json"
```

## How often you can deploy

A server starts at most one deploy every 15 minutes on the free plan and every minute on a paid one. A request inside that window is not refused: it waits, and its `run_after` says when it will start. Only the newest waiting deploy is kept, so a burst of pushes ends in one deploy of the latest commit.

To see how a deploy went, `GET /servers/{server}/git` lists recent deployments with their status and any error.

FAQ

## Questions

**Does this work with GitLab?**

Yes. The deploy request is the same for a GitLab repository or a public Git URL; only the CI file differs. In GitLab CI, store the key as a masked CI/CD variable and run the same curl command in a job after your tests.

Read next

- [Git deploys Link a repository and deploy it to your server from code.](https://sillydev.co.uk/docs/panel/git-deploys)
- [Keep a bot online 24/7 Why bots go offline, how to stop them crashing, and where to run one around the clock.](https://sillydev.co.uk/guides/keep-discord-bot-online-24-7)
- [Recipes Complete, copyable examples for the things people build most.](https://sillydev.co.uk/docs/panel/recipes)
