Getting Started
This guide walks you through onboarding a new project to Skiff2 from scratch.
Skiff2 runs services on Cloud Run, which caps a single instance at 8 vCPU and 32 GiB of memory (and CPU/memory are paired — more CPU requires more memory). If your application is extremely resource intensive — needs more RAM or CPU than a single Cloud Run instance can provide, requires GPUs, or relies on long-running background processes — we recommend not using Skiff2 and instead choosing a platform suited to heavier workloads.
The skiff-template repo is the fastest way to get going. It ships with a FastAPI backend, a Vite + MUI (varnish) React frontend, Docker Compose for local dev, and the Skiff2 config and GitHub Actions already wired up. Click Use this template on GitHub, then follow the steps below to register your project.
Register your project in skiff2
Add a project-config.json file to the skiff2-projects/ directory in the Skiff-Commodore repo and open a pull request.
Name the file <your-project-name>.project-config.json:
{
"name": "my-project",
"ai2Project": "my-ai2-project",
"primaryContact": "user:you@allenai.org",
"projectAdmins": ["group:my-team@allenai.org"],
"team": "my-team",
"repo": "allenai/my-project"
}
Notes on the config:
repomust already exist on GitHub before your PR is merged.- The ReViz GitHub team must have at least Read access to
repo(and anyremoteRepos). We use this to confirm the repo exists when reviewing your PR and to help debug deploy issues. Add it under Settings → Collaborators and teams → Add teams in your repo. ai2Projectvalid values are listed in the AI2 project tag keys.projectAdminsandprimaryContactwill be made admins on the project.
See the project-config.json reference for all options.
example.project-config.json as a starting point.Once your PR is merged, Skiff2 will automatically:
- Create a GCP project
- Provision SSL certificates and DNS records
- Set the following GitHub Actions variables on your repo:
SKIFF2_PROJECT_IDSKIFF2_WORKLOAD_IDENTITY_PROVIDERSKIFF2_SERVICE_ACCOUNT
If you only need a GCP project, you can stop here!
Create a Dockerfile
Create a Dockerfile in your repo. For example, a simple Node.js app:
FROM node:24-alpine
WORKDIR /app
COPY . .
RUN npm ci && npm run build
CMD ["node", "server.js"]
Create skiff2.json
Add a skiff2.json at the root of your repo to describe your services:
{
"$schema": "https://storage.googleapis.com/skiff2-general/skiff2-config.schema.json",
"services": [
{
"name": "web",
"cwd": ".",
"isRootService": true
}
]
}
name— a short identifier for this servicecwd— directory containing theDockerfile, relative toskiff2.jsonisRootService: true— routes the top-level domain (my-project.apps.allenai.org) to this service
If you need custom DNS routing to the service (i.e. a TLD) you can set customDomains.
By default, Cloud Run services are private (accessible only to @allenai.org accounts via IAP). For public-facing apps, set allowUnauthenticated: true on your service.
See the skiff2.json reference for all available options.
Set up GitHub Actions
Create a workflow file at .github/workflows/deploy.yml:
name: Skiff2 Build & Deploy
on:
push:
branches:
- main # will need to add more branches here if you plan on deploying to other environments.
# needed to authenticate with google
permissions:
contents: read
id-token: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
build_deploy:
runs-on: ubuntu-latest
environment:
name: ${{ github.ref_name }}
url: ${{ steps.deploy-services.outputs.default_url }}
steps:
- name: Skiff2 Setup
id: setup
uses: allenai/skiff2-actions/shared-actions/setup@main
with:
workload_identity_provider: ${{ vars.SKIFF2_WORKLOAD_IDENTITY_PROVIDER }} # prepopulated on project setup
service_account: ${{ vars.SKIFF2_SERVICE_ACCOUNT }} # prepopulated on project setup
project_id: ${{ vars.SKIFF2_PROJECT_ID }} # prepopulated on project setup
- name: Skiff2 Build
id: build
uses: allenai/skiff2-actions/shared-actions/build@main
with:
project_id: ${{ vars.SKIFF2_PROJECT_ID }}
- name: Skiff2 Deploy Infra
if: github.ref_name == 'main'
uses: allenai/skiff2-actions/shared-actions/deploy-infra@main
with:
project_id: ${{ vars.SKIFF2_PROJECT_ID }}
command: apply
- name: Skiff2 Deploy Services
id: deploy-services
uses: allenai/skiff2-actions/shared-actions/deploy-services@main
with:
project_id: ${{ vars.SKIFF2_PROJECT_ID }}
command: apply
The four steps do the following:
- Setup — Authenticates to GCP using Workload Identity Federation and configures Docker for Container Registry
- Build — Builds your Docker images and pushes them to GCR
- Deploy Infra — Runs Terraform to update shared infrastructure (load balancer, SSL certificates, DNS). Only runs on
main. - Deploy Services — Runs Terraform to update your Cloud Run services
Push to main
Once merged, your workflow will run and your app will be live at:
| Domain | Notes |
|---|---|
my-project.pandajungle.org | Always provisioned |
my-project.allen.ai | Provisioned by default |
my-project.apps.allenai.org | Provisioned by default |
Multiple services
If your repo has multiple services (e.g. a frontend and an API), add each to skiff2.json:
{
"services": [
{
"name": "ui",
"cwd": "./ui",
"isRootService": true
},
{
"name": "api",
"cwd": "./api"
}
]
}
The api service will be routed from prod-api.my-project.pandajungle.org automatically. (The prod- prefix is the environment name — deploys from main map to the prod environment by default. See Environments.)