This guide walks through bootstrapping a local DevStride development environment from a clean checkout. There is no single onboarding command that does this for you — it's a short, one-time sequence of shell config, AWS SSO setup, and a hand-filled .env file, followed by two commands (ds run backend and ds run ui) that you'll use every day after that.
ds setup, ds deploy, or similar all-in-one bootstrap command. Every ds invocation maps to one of eight Commander programs under cli/commands/ (run, migrations, data, golden, script, stripe, g, worktree) — bootstrapping is the manual sequence below. This guide uses a few CLI mechanics (the -u/-b flags, the bind cache, personal stages) before they're formally explained; the very next page, Introduction to the ds CLI, covers all of them, and the Command Reference has the full flag list.| Tool | Purpose | Notes |
|---|---|---|
| Node.js 22 | Runtime for backend, frontend, and the CLI | Install via nvm: nvm install 22 && nvm alias default 22 && nvm use 22 |
| pnpm | Package manager for the monorepo | Pinned by the packageManager field in package.json — get the matching version via Corepack (bundled with Node 22): corepack enable |
| AWS CLI v2 | Required for AWS SSO auth | brew install awscli, plus pip3 install aws-sso-credential-process aws-export-credentials so SST can use SSO credentials |
| AWS SSO access | Every AWS-bound ds command (i.e. not -u, ds run local, or ds worktree) authenticates against AWS SSO before running | Provisioned by a team lead — you'll get an email to set up SSO |
| Docker | Runs local DynamoDB for the backend test suite only | Not needed for local development — see the callout below |
ds run backend does not start Docker or any local services — it runs pnpm install, cleans up orphaned CloudFormation stacks, and then pnpm exec sst dev. In normal (non-test) code, DynamoDB access always points at real AWS. Docker/local DynamoDB is only spun up by the backend test suite itself (NODE_ENV=test), and only if you run cd backend && pnpm test. You don't need Docker running to develop locally — only to run tests.The table above is what the application needs. This one is what a DevStride developer actually works with day to day. None of it changes how the app runs, but all four are worth having in place before your first task.
| Tool | Why you want it | Install |
|---|---|---|
| DevStride plugin for Claude Code | The plan → build → review → release loop. .claude/settings.json in the main repository registers the marketplace and auto-enables the plugin, but it does not install it — each machine needs the install once. Full walkthrough: Getting the Skills. | claude plugin install devstride@devstride |
GitHub CLI (gh) | Pull requests, reviews, and CI status. The delivery skills drive gh directly rather than the web UI, and /devstride:doctor reports it as missing if it is not authenticated. | brew install gh && gh auth login |
| Neon skills for Claude Code | Our Postgres is Neon everywhere — personal stages, the golden source database, and production. These give an agent correct guidance on branch types, pooled versus direct endpoints, and egress cost. | npx skills add neondatabase/agent-skills -g -s neon-postgres -s neon-postgres-branches -s neon-postgres-egress-optimizer |
| AWS SSO | Already listed as a hard prerequisite above — repeated here because it is the one item on this list that blocks work outright rather than merely making it easier. | See step 2 below |
Use -g for the skills and claude plugin install for the plugin, rather than
installing either into a repository checkout. Both are per-developer tooling on
their own update cadence, nothing about them is pinned in the DevStride
repository, and a repo-local copy only goes stale and leaves git status dirty.
Skip the umbrella neon skill in that package. It covers Neon Auth, the Data
API, Object Storage, Functions, and the AI Gateway — none of which DevStride
uses, since everything outside Postgres is AWS and SST. Installing it only
offers agents alternatives that conflict with the architecture.
claude plugin list versions
first, then update with claude plugin marketplace update devstride && claude plugin update devstride@devstride and restart.Do this once, in order, from the repo root.
Add to your shell config (e.g. .zshrc):
export DEVSTRIDE_STAGE=${your_name} # e.g. phil
export DEVSTRIDE_DEV_PROFILE=devstride-${your_name} # e.g. devstride-phil
export DEVSTRIDE_REGION=eu-central-1 # or whichever region is nearest you
export AWS_CONFIGURE_SSO_DEFAULT_SSO_START_URL=https://devstride.awsapps.com/start
export AWS_CONFIGURE_SSO_DEFAULT_SSO_REGION=us-east-1
sso(){
unset AWS_PROFILE
export AWS_PROFILE=$1
aws sts get-caller-identity &> /dev/null || aws sso login || (unset AWS_PROFILE && aws-configure-sso-profile --profile $1)
eval $(aws-export-credentials --env-export)
}
alias ds='./ds'
DEVSTRIDE_STAGE becomes the name of your own personal cloud stage — every developer deploys to their own isolated stage, keyed off this value.
Install the AWS CLI v2, then configure SSO with the same profile name as DEVSTRIDE_DEV_PROFILE:
aws configure sso
SSO start URL [None]: https://devstride.awsapps.com/start
SSO Region [None]: us-east-1
# after logging in via the browser:
CLI default client Region [None]: eu-central-1 # nearest region for you
CLI default output format [None]: json
CLI profile name [AWSAdministratorAccess-xxxxxxxxxxxx]: devstride-${your_name}
Then install the two helper packages SST needs to consume SSO credentials:
pip3 install aws-sso-credential-process
pip3 install aws-export-credentials
./ds wrapper runs aws sts get-caller-identity (falling back to aws sso login) before every command, unless you pass -u to skip auth. It also (re)generates a stage/region bind cache at .ds/bind/<stage>-<region>.env — pass -b to force a fresh bind even if a cached one exists. Usage: ds [-b] [-r] [-u] <command> [subcommand] [args].nvm install 22
nvm alias default 22
nvm use 22
corepack enable
pnpm install
.env fileCopy the sample and fill in real values by hand:
cp .env.sample .env
.env.sample ships with changeme placeholders — you get the real values from a teammate and paste them in yourself. Nothing in ds reaches into AWS Secrets Manager (or anywhere else) to populate your local .env..env.sample lists the following, all needing real values before the app will run correctly:
| Group | Variables |
|---|---|
| Domain | DOMAIN |
| Giphy | GIPHY_API_KEY |
| GitHub App | GITHUB_APP_CERT, GITHUB_APP_ID, GITHUB_APP_NAME, GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_WEBHOOK_SECRET |
| Pusher | PUSHER_APP_CLUSTER, PUSHER_APP_ID, PUSHER_APP_KEY, PUSHER_APP_SECRET |
| Stripe | STRIPE_PUBLIC_KEY, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET |
| OpenAI | OPENAI_API_KEY |
| Database | DB_CONNECTION_STRING, DB_CONNECTION_STRING_READ_ONLY |
| Encryption | ENCRYPTION_KEY (see step 5) |
| SMTP (optional) | USE_SMTP, SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM |
ENCRYPTION_KEYENCRYPTION_KEY must be exactly 32 bytes (64 hex characters) — it's used to encrypt sensitive data such as database credentials in transit:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
Paste the result into .env as ENCRYPTION_KEY. Never commit this value — each environment should have its own unique key.
ds run backendds run backend
This is both how you run the backend day-to-day and how your personal SST stage gets created the first time — ds run backend runs pnpm install, cleans up any orphaned CloudFormation stacks, then runs pnpm exec sst dev, which provisions your stage's AWS resources on first run. Once it finishes deploying, stop it (Ctrl+C) — you need to run migrations and push config before it's actually usable.
ds migrations run
ds migrations run-sql currently does exactly the same thing as ds migrations run (both run Drizzle SQL migrations to the latest version) — it's a leftover alias from a historical split of the migration path. Either works; ds migrations run is the one documented going forward.ds script set-configds script set-config
This reads your local .env, validates that every required variable is set (DB connection strings, Stripe, OpenAI, GitHub App, Pusher, Slack, encryption key, and more), and pushes them up into an SST DEVSTRIDE_CONFIG secret (base64-encoded JSON) that your running Lambda / sst dev process reads at runtime.
ds script set-config is a one-way push from your local .env up to SST. It does not fetch or sync anything down. The running backend never reads .env directly at runtime — the CLI-side dotenv.config() only feeds the CLI/build-time process used to synth sst.config.ts; the deployed Lambda/sst dev process gets its secrets exclusively through the SST Config binding that this command populates. If you change a value in .env, you must re-run ds script set-config for it to take effect.Ask a teammate to set up a Stripe test account for you, then:
STRIPE_SECRET_KEY / STRIPE_PUBLIC_KEY in .env.https://api.{stage}.devstride.dev/v1/subscriptions/stripe/webhooks, listening for customer.subscription.created, customer.subscription.deleted, customer.subscription.trial_will_end, and customer.subscription.updated. Copy the signing secret into STRIPE_WEBHOOK_SECRET.ds script set-config so the updated values are pushed up.ds stripe add-products
Once bootstrapping is done, this is all you run day to day, in two terminal tabs:
ds run backend
ds run ui
ds run backend starts SST's live-lambda dev mode against your personal stage. ds run ui spawns the Vite dev server in frontend/, wired up with VITE_* env vars derived from your bound stage.
The backend test suite needs Docker for a local DynamoDB — this is the only place Docker is required:
docker pull amazon/dynamodb-local
cd backend && pnpm test
./ds resolves and runs a command, and the flags used aboveds command, organized by category