Deploying to DigitalOcean
Prerequisites
Section titled “Prerequisites”Install the DigitalOcean CLI and authenticate:
# Install doctlbrew install doctl # macOSsnap install doctl # Ubuntu
# Authenticatedoctl auth initDeploy with doctl
Section titled “Deploy with doctl”Create from App Spec
Section titled “Create from App Spec”The fastest path is deploying from your .do/app.yaml spec (see App Platform for the full spec).
# Create the appdoctl apps create --spec .do/app.yaml
# List your appsdoctl apps list
# Trigger a new deploymentdoctl apps create-deployment <app-id>
# Check deployment statusdoctl apps list-deployments <app-id>
# View runtime logsdoctl apps logs <app-id> --type runUpdate an Existing App
Section titled “Update an Existing App”# Update the app spec (adds new env vars, changes instance size, etc.)doctl apps update <app-id> --spec .do/app.yamlDeploy from the Dashboard
Section titled “Deploy from the Dashboard”- Go to App Platform in the DigitalOcean console and click Create App.
- Select GitHub as the source and authorize DigitalOcean to access your repository.
- Choose the repository and branch (typically
main). - App Platform auto-detects the Dockerfile or you can set the build command to
npx cruz buildand run command tonode build/server/index.js. - Add environment variables under the Environment Variables section. Mark secrets with the Encrypt toggle.
- Attach a Managed PostgreSQL database — App Platform injects
DATABASE_URLautomatically. - Optionally attach a Managed Redis cluster for cache and queues.
- Review the plan and click Create Resources.
App Platform provisions everything and deploys your app. Subsequent pushes to the configured branch trigger automatic deployments.
GitHub Actions CI/CD
Section titled “GitHub Actions CI/CD”Automate deployments with GitHub Actions. This workflow builds, tests, and triggers a deployment on every push to main.
name: Deploy to DigitalOceanon: push: branches: [main]
jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 cache: npm - run: npm ci - run: npx cruz typecheck - run: npx cruz test
deploy: needs: test runs-on: ubuntu-latest steps: - uses: digitalocean/app_action@v2 with: app_name: my-cruz-app token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}Generate a personal access token in the DigitalOcean dashboard under API > Tokens and add it as a repository secret named DIGITALOCEAN_ACCESS_TOKEN.
DigitalOcean Spaces Setup
Section titled “DigitalOcean Spaces Setup”Spaces provides S3-compatible object storage. Create a Space and generate API keys.
# Spaces are created in the DigitalOcean console under "Spaces Object Storage"# Choose a region (nyc3, sfo3, ams3, sgp1, fra1)Generate Spaces access keys in the dashboard under API > Spaces Keys. Configure them in your app:
SPACES_ENDPOINT=https://nyc3.digitaloceanspaces.comSPACES_BUCKET=my-cruz-uploadsSPACES_ACCESS_KEY=your-spaces-access-keySPACES_SECRET_KEY=your-spaces-secret-keySPACES_REGION=nyc3The adapter uses the S3 protocol, so the spacesEndpoint maps directly to the s3Endpoint config:
new DigitalOceanAppPlatformAdapter({ databaseUrl: process.env.DATABASE_URL, spacesBucket: process.env.SPACES_BUCKET, spacesEndpoint: process.env.SPACES_ENDPOINT, // https://nyc3.digitaloceanspaces.com spacesAccessKey: process.env.SPACES_ACCESS_KEY, spacesSecretKey: process.env.SPACES_SECRET_KEY,})Enable the built-in CDN on your Space for edge-cached file delivery.
Domains and SSL
Section titled “Domains and SSL”App Platform handles SSL automatically. To use a custom domain:
- Go to your app’s Settings > Domains.
- Add your domain (e.g.,
app.example.com). - Update your DNS provider with the CNAME record App Platform provides.
- SSL is provisioned automatically via Let’s Encrypt. No manual certificate management.
# Or via doctldoctl apps update <app-id> --spec .do/app.yaml# Include the domain in the spec:# domains:# - domain: app.example.com# type: PRIMARYDatabase Migrations
Section titled “Database Migrations”The recommended approach is a PRE_DEPLOY job in your app spec. This runs before the new version receives traffic:
jobs: - name: migrate github: repo: your-org/your-repo branch: main build_command: npm ci run_command: npx cruz db migrate kind: PRE_DEPLOY instance_size_slug: basic-xxs envs: - key: DATABASE_URL scope: RUN_TIME value: ${db.DATABASE_URL}If the migration fails, the deployment is rolled back automatically. You can also run migrations manually:
doctl apps console <app-id> --command "npx cruz db migrate"Monitoring with DigitalOcean Insights
Section titled “Monitoring with DigitalOcean Insights”App Platform includes built-in monitoring:
- CPU and memory usage per instance in the App Platform dashboard.
- HTTP request metrics (latency, error rate, throughput) under Insights.
- Runtime logs via
doctl apps logs <app-id> --type runor the dashboard log viewer. - Build logs via
doctl apps logs <app-id> --type build. - Alerts can be configured in the DigitalOcean Monitoring dashboard for CPU, memory, and bandwidth thresholds.
For deeper observability, connect an external provider (Datadog, Grafana Cloud) via log forwarding in the app settings.