Skip to main content

Deploy from CI with GitHub Actions

Use the official serverpod/serverpod_cloud_deploy action to deploy your Serverpod Cloud project on every push to your main branch. Setup takes about ten minutes once you have a personal access token.

Before you start

  • A personal access token. See Create a token on the Personal access tokens page.
  • The project's scloud.yaml committed to the repository. It's created by serverpod cloud launch or serverpod cloud project link.
  • Either: generated Serverpod files committed to the repository, or a CI step that runs serverpod generate (covered as a variant below).
  • One Serverpod project per repository, located no more than two subdirectory levels below the repository root.

Add the token as a repository secret

In your GitHub repository, go to Settings → Secrets and variables → Actions → New repository secret. Name the secret SERVERPOD_CLOUD_TOKEN (or anything else, as long as it matches the workflow below) and paste the token value.

Add the workflow file

Create .github/workflows/deploy.yml with the following workflow:

.github/workflows/deploy.yml
name: Deploy to Serverpod Cloud

on:
push:
branches: [main]

permissions:
contents: read

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Flutter SDK
uses: subosito/flutter-action@v2

- name: Activate serverpod command
run: dart pub global activate serverpod_cli

- uses: serverpod/serverpod_cloud_deploy@v1
with:
token: ${{ secrets.SERVERPOD_CLOUD_TOKEN }}

What each step does:

  • The actions/checkout@v4 step clones the repository into the runner.
  • The subosito/flutter-action@v2 step installs the Flutter SDK, which also provides Dart. The deploy action needs Dart to install the Serverpod Cloud CLI.
  • The dart pub global activate serverpod_cli step puts the Serverpod CLI on the runner so any pre-deploy hooks (for example, serverpod generate) can run.
  • The serverpod/serverpod_cloud_deploy@v1 step installs the Serverpod Cloud CLI as scloud, reads your scloud.yaml, and runs scloud deploy against your project using the token.

Push to trigger the workflow

Commit the workflow file and push to main. Open the Actions tab in your repository to watch the run. When it succeeds, confirm the deploy went live:

serverpod cloud status deployment show

You should see a recent deployment moving through Upload → Cloud build → Rollout, finishing with the rocket on Rollout.

Run serverpod generate in CI (variant)

If you don't want to commit generated Serverpod files, run serverpod generate as a workflow step instead. The Flutter SDK in the workflow below provides the Dart toolchain serverpod generate needs and is also handy if the project's pre-deploy hook builds a Flutter web client.

.github/workflows/deploy.yml
name: Deploy to Serverpod Cloud

on:
push:
branches: [main]

permissions:
contents: read

env:
# Replace with your Cloud project ID and the path to your server package.
PROJECT_ID: your-project-id
SERVER_DIR: ./path/to/server

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Flutter SDK
uses: subosito/flutter-action@v2

- name: Generate Serverpod code
working-directory: ${{ env.SERVER_DIR }}
run: |
dart pub get
dart pub global activate serverpod_cli
serverpod generate

- uses: serverpod/serverpod_cloud_deploy@v1
with:
token: ${{ secrets.SERVERPOD_CLOUD_TOKEN }}
project_id: ${{ env.PROJECT_ID }}
project_dir: ${{ env.SERVER_DIR }}

The flutter-action@v2 step is required if the generate step pulls Flutter packages. Pass project_id and project_dir to the action so it knows which project to deploy and where the server code lives.

Action inputs

InputRequiredWhat it does
tokenyesYour personal access token, passed from the repository secret.
working_directorynoThe directory the action runs in. Defaults to the repository root.
project_idnoThe Cloud project to deploy to. Inferred from scloud.yaml when present.
project_dirnoPath to the server package. Useful for monorepos where the server isn't at the repository root.
project_config_filenoPath to scloud.yaml if it's not in the default location.

Troubleshooting

Authentication fails. The run output says "The credentials for this session seem to no longer be valid." The token input is empty, the secret name in the workflow doesn't match what's in your repository's secrets, or the token was revoked. Check the secret name against what your workflow references in ${{ secrets.<name> }}, and create a new token if the old one is gone. Ignore the hint to run scloud auth login, which can't work in CI.

Project not found. Either scloud.yaml isn't committed and the action can't resolve the project, or project_id was passed but doesn't match a project on your Cloud account. Commit scloud.yaml, or pass the correct project_id as an action input.

Generated files missing. The primary workflow assumes generated Serverpod files are committed. Either commit them, or switch to the variant workflow that runs serverpod generate in CI.