Developer Docs

Deployment

Deploying personal cloud stages, tearing down environments, and listing deployed infrastructure.

Deployment

DevStride uses Pulumi for infrastructure-as-code and GitHub Actions for CI/CD. The ds deploy commands orchestrate both, giving you a simple interface for managing cloud environments.

Deploying a Stage

Basic Deploy

ds deploy up

Dispatches a GitHub Actions workflow that:

  1. Builds the frontend (Vite)
  2. Bundles Lambda functions (esbuild)
  3. Runs pulumi up to create/update AWS resources
  4. Uploads the frontend build to S3
  5. Invalidates the CloudFront cache
  6. Outputs your API and UI URLs

The CLI streams the workflow logs to your terminal in real time.

Specifying Options

# Deploy a specific branch
ds deploy up feature/auth-improvements

# Specify the stage name explicitly
ds deploy up --stage phil-auth

# Specify the branch explicitly
ds deploy up --branch feature/auth-improvements

# Custom DNS label (the final stage identifier in URLs)
ds deploy up --route phil-auth-v2

# Allow creating a second stack when one already exists for this branch
ds deploy up --new-stack

How cloud stage names are resolved:

  1. If --stage is provided, use it directly.
  2. If --branch (or positional argument) is provided, compute stage from {developer}-{branch}.
  3. If neither is provided, the CLI prompts you interactively.

What Gets Deployed

A full stage includes approximately 50 AWS resources:

ServiceResources
API GatewayREST API with custom domain (api-{stage}.devstride.dev)
LambdaAPI handler, event processors, FIFO consumers, webhook handlers
CognitoUser pool, app client, custom domain
DynamoDBApplication tables (imported from existing on first SST→Pulumi deploy)
S3Frontend hosting bucket, asset storage
CloudFrontCDN distribution for frontend
EventBridgeEvent bus for domain/integration events
SQS/SNSMessage queues and topics (FIFO and standard)
Step FunctionsWorkflow state machines (via @pulumi/cdk)
Secrets ManagerStage-specific configuration
IAMRoles and policies for all services

Deploy Timing

ScenarioApproximate Duration
First deploy (all resources)8-12 minutes
Incremental update (code changes)3-5 minutes
Infrastructure-only change2-4 minutes
Frontend-only change1-2 minutes

Tearing Down a Stage

Basic Teardown

ds deploy down phil-feature-auth

If you omit the stage name, the CLI prompts you to select one.

What Gets Cleaned Up

The teardown is thorough:

  1. S3 buckets are emptied (required before deletion)
  2. pulumi destroy removes all AWS resources
  3. Secrets Manager entries for this stage are deleted
  4. Neon database branch is deleted (unless --keep-neon)
  5. Pulumi stack state is removed (unless --keep-stack)
  6. Local files are cleaned: bind cache, setup state, config files, shell config entries

Options

FlagDescription
--keep-stackKeep the Pulumi stack state (skip pulumi stack rm)
--keep-neonKeep the Neon database branch
--dry-runPreview what would be cleaned up without executing

Safety Confirmation

Teardown requires you to type the stage name to confirm:

This will destroy ALL resources for stage 'phil-feature-auth'.
Type the stage name to confirm: phil-feature-auth

Listing Deployed Stages

List All Stages

ds deploy list

Shows a table of all deployed Pulumi stages with:

  • Stage name and region
  • API and UI URLs
  • Creation date and last activity
  • Resource counts

Detailed View

ds deploy list --stage phil-local

Shows expanded details for a single stage:

  • Cognito user pool ID and client ID
  • DynamoDB table names
  • Step Functions state machine ARN
  • S3 bucket name
  • CloudFront distribution ID

Options

FlagDescription
--stage <name>Show details for a single stage
--region <region>Filter by AWS region
--jsonMachine-readable JSON output
-w, --watchLive-updating table (polls every 10 seconds)

Watch Mode

ds deploy list --watch

Continuously refreshes the stage list every 10 seconds. Useful during a deploy to watch for resource changes in real time. Press Ctrl+C to exit.

URL Patterns

Deployed stages follow predictable URL patterns:

StageTypeAPI URLUI URL
devProtectedhttps://api.devstride.devhttps://app.devstride.dev
prodProtectedhttps://api.devstride.devhttps://app.devstride.dev
phil-localLocal stagehttps://api-phil-local.devstride.devhttps://app-phil-local.devstride.dev
phil-feature-authCloud stagehttps://api-phil-feature-auth.devstride.devhttps://app-phil-feature-auth.devstride.dev

Protected stages (dev, prod) use bare domains. Personal stages are prefixed with the stage name. Your local stage (phil-local) has the same URL structure as cloud stages.

Deployment Workflow Details

Under the hood, ds deploy up uses the GitHub API to dispatch a workflow:

ds deploy up
    │
    ├── Resolves stage name and branch
    ├── Validates AWS credentials (re-auth if needed)
    ├── Dispatches deploy-stage.yml via gh api
    ├── Streams workflow logs to terminal
    │
    └── GitHub Actions (deploy-stage.yml):
        ├── Checkout code
        ├── pnpm install
        ├── Build frontend (Vite)
        ├── Bundle Lambdas (esbuild)
        ├── pulumi up (infrastructure)
        ├── Upload frontend to S3
        ├── Invalidate CloudFront
        └── Output URLs

Troubleshooting

Deploy hangs or fails

Check the GitHub Actions workflow run directly:

gh run list --workflow=deploy-stage.yml --limit=5
gh run view <run-id> --log

"Stack already exists"

Your stage already has a Pulumi stack. This is normal for subsequent deploys — Pulumi updates in place. If you specifically need a second stack for the same branch, use --new-stack.

"S3 bucket not empty"

This can happen during deploy down. The CLI should handle this automatically by emptying buckets first. If it fails, manually empty the bucket in the AWS console, then re-run deploy down.

Resource conflicts between stages

Each stage has fully isolated resources (different names, different ARNs). If you see conflicts, it usually means the stage name collision — check ds deploy list for duplicate stage names.

Next Steps