| name | turborepo-workflow |
| description | Expert guidance on Turborepo build orchestration and remote caching workflow. Use this skill when running build commands, troubleshooting caching issues, working with monorepo task execution, or investigating CI/CD pipeline problems. Covers the critical pattern of always using root-level pnpm scripts, understanding the turbo-wrapper.js authentication system, filter syntax for targeting packages, and remote cache configuration. |
Turborepo Workflow
This skill covers the build orchestration and remote caching patterns used in the Squareone monorepo.
Critical Rules
⚠️ ALWAYS use root-level pnpm scripts - Never run individual package scripts or call turbo directly (unless environment variables are pre-set in CI/CD).
Why This Matters
Only the root package.json scripts use the wrapper (scripts/turbo-wrapper.js) that enables remote caching with authentication.
Individual package.json scripts bypass the wrapper and remote caching, resulting in slower builds and missed cache hits.
Correct vs Incorrect Usage
✅ Correct
pnpm test --filter @lsst-sqre/squared
pnpm build
pnpm lint
pnpm type-check
pnpm dev --filter squareone
❌ Wrong
cd packages/squared && pnpm test
turbo run test --filter @lsst-sqre/squared
cd apps/squareone && pnpm dev
Exception: Direct Turbo Calls in CI/CD
Direct turbo calls are acceptable only when TURBO_API, TURBO_TOKEN, and TURBO_TEAM are already set as environment variables:
export TURBO_API="https://roundtable.lsst.cloud/turborepo-cache"
export TURBO_TOKEN="$SECRET_TOKEN"
export TURBO_TEAM="team_squareone"
turbo run build
In Docker builds or CI/CD where these env vars are injected, direct turbo calls work because the wrapper script detects them first (Priority 1).
Common Commands
Build Commands
pnpm build
pnpm build --filter @lsst-sqre/squared
pnpm build --filter squareone
NODE_OPTIONS="--max_old_space_size=4096" pnpm build
Development Commands
pnpm dev
pnpm dev --filter squareone
pnpm dev --filter @lsst-sqre/squared
Testing Commands
pnpm test
pnpm test --filter @lsst-sqre/squared
pnpm test-storybook
pnpm test-storybook:watch
pnpm test-storybook --filter @lsst-sqre/squared
Quality Commands
pnpm lint
pnpm lint --filter squareone
pnpm type-check
pnpm type-check --filter @lsst-sqre/squared
pnpm format
Storybook Commands
pnpm storybook
pnpm storybook --filter @lsst-sqre/squared
pnpm build-storybook --filter squared
Filter Syntax
Turborepo's filter syntax allows targeting specific packages:
pnpm build --filter @lsst-sqre/squared
pnpm dev --filter squareone
pnpm test --filter @lsst-sqre/squared --filter squareone
pnpm build --filter ...@lsst-sqre/squared
pnpm build --filter @lsst-sqre/squared...
Remote Cache Authentication
The monorepo uses a custom Turborepo cache server at https://roundtable.lsst.cloud/turborepo-cache for faster builds through remote caching.
See the complete documentation at docs/dev/remote-cache.rst.
Authentication Methods
The turbo-wrapper.js script checks for authentication in priority order:
- Environment variables -
TURBO_API, TURBO_TOKEN, TURBO_TEAM all set (CI/CD)
- 1Password -
.env.op file + op CLI available (secure local development)
- Plain .env file -
.env file present (local development without 1Password)
- No authentication - Local cache only (external contributors)
Authentication Messages
When running commands, you'll see:
- ✅
🔑 Using environment variables for Turborepo remote cache authentication
- ✅
🔐 Using 1Password for Turborepo remote cache authentication
- ✅
🔑 Using .env for Turborepo remote cache authentication
- ℹ️
ℹ️ Running Turborepo without remote cache (local cache only)
Setting Up Authentication
For 1Password Users
-
Create .env.op file from template:
cp .env.op.example .env.op
-
Edit .env.op to reference your 1Password vault items
-
Install 1Password CLI:
brew install 1password-cli
-
Sign in to 1Password:
op signin lsstit.1password.com
For Plain .env Users
-
Create .env file from template:
cp .env.example .env
-
Add your credentials to .env:
TURBO_API=https://roundtable.lsst.cloud/turborepo-cache
TURBO_TOKEN=your_token_here
TURBO_TEAM=team_squareone
-
Never commit .env files - they're in .gitignore
Obtaining Access Tokens
- Visit https://roundtable.lsst.cloud
- Log in with your credentials
- Navigate to the token management page
- Create a new token with the
write:turborepo scope
- Store it securely in 1Password or
.env file
Verifying Remote Cache
Cache Hit Messages
Look for these indicators in Turborepo output:
>>> FULL TURBO
>>> Remote caching enabled
@lsst-sqre/squared:build: cache hit, replaying output...
squareone:build: cache hit, replaying output...
Debug Mode
For detailed caching information:
TURBO_LOG_LEVEL=debug pnpm build
Troubleshooting
Remote Cache Not Working
Symptoms: No "Remote caching enabled" message, slow builds
Solutions:
- Verify authentication message shows up
- Check network connectivity to https://roundtable.lsst.cloud
- Ensure token hasn't expired
- Verify token has the
write:turborepo scope
- Try with
TURBO_LOG_LEVEL=debug to see detailed logs
- Verify credentials are correct in
.env or .env.op
1Password CLI Not Found
Symptoms: Warning message about 1Password CLI not available
Solutions:
op --version
brew install 1password-cli
op signin lsstit.1password.com
Cache Poisoning / Stale Cache
Symptoms: Build failures or incorrect behavior despite clean checkout
Solutions:
pnpm build --force
rm -rf node_modules/.cache/turbo
pnpm clean && pnpm install
Build Errors in Monorepo
Symptoms: Build fails with mysterious errors
Solutions:
- Ensure you're using root-level scripts (not running from package directories)
- Check that all dependencies are installed:
pnpm install
- Try a clean build:
pnpm clean && pnpm build
- Verify turbo.json configuration is correct
- Check for circular dependencies
Package Not Building
Symptoms: Specific package fails to build or isn't found
Solutions:
ls packages/
cat turbo.json
pnpm build --filter @lsst-sqre/package-name
cat packages/package-name/package.json
Temporarily Disabling Remote Cache
Sometimes useful for testing local-only builds:
mv .env .env.backup
mv .env.op .env.op.backup
pnpm build:local
npx turbo build
Turborepo Configuration
The monorepo's build pipeline is configured in turbo.json:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**", "build/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
},
"lint": {},
"type-check": {}
}
}
Understanding Pipeline
build - Depends on dependencies' builds (^build), caches outputs
test - Depends on build, caches coverage
lint - No dependencies, can run in parallel
type-check - No dependencies, can run in parallel
Cache Outputs
Turborepo caches specified output directories:
.next/** - Next.js build output
dist/** - Package build output
build/** - Other build artifacts
coverage/** - Test coverage reports
Package Dependencies
The monorepo has these package relationships:
@lsst-sqre/squared (component library)
├── @lsst-sqre/global-css (styles)
│ └── @lsst-sqre/rubin-style-dictionary (tokens)
├── @lsst-sqre/eslint-config
└── @lsst-sqre/tsconfig
squareone (Next.js app)
├── @lsst-sqre/squared
├── @lsst-sqre/global-css
└── @lsst-sqre/eslint-config
Building squared automatically builds its dependencies (global-css, rubin-style-dictionary).
CI/CD Integration
In CI/CD pipelines:
env:
TURBO_API: ${{ secrets.TURBO_API }}
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
steps:
- run: pnpm install
- run: pnpm build
- run: pnpm test
Environment variables take priority, so the wrapper automatically uses them without needing .env files.
Best Practices
- Always run from repository root with filters
- Use root-level pnpm scripts for all Turborepo commands
- Never commit .env or .env.op files (in .gitignore)
- Verify remote cache is working via authentication messages
- Use filters to target specific packages for faster iteration
- Check turbo.json when adding new scripts or packages
- Clean caches if experiencing unexplained build issues
- Document new scripts in root package.json with clear names
Performance Tips
NODE_OPTIONS="--max_old_space_size=4096" pnpm build
pnpm test --filter @lsst-sqre/squared
Common Patterns
After Pulling Changes
pnpm install
pnpm build
Before Committing
pnpm lint
pnpm type-check
pnpm test
Adding New Package
- Create package in
packages/ or apps/
- Add to
pnpm-workspace.yaml (usually automatic)
- Add scripts to package's
package.json
- Update
turbo.json if needed
- Run
pnpm install from root
Debugging Build Issues
pnpm clean
pnpm install
TURBO_LOG_LEVEL=debug pnpm build --force
pnpm build --filter @lsst-sqre/package-name --force
Related Documentation
docs/dev/remote-cache.rst - Complete remote cache documentation
scripts/turbo-wrapper.js - Wrapper script source code
turbo.json - Pipeline configuration
pnpm-workspace.yaml - Workspace configuration
Infrastructure
The Turborepo cache server is deployed as part of the Rubin Science Platform:
Components:
turborepo-cache-proxy - Exchanges Gafaelfawr token for cache authentication
turborepo-remote-cache - Cache server implementation
- Google Cloud Storage - Backend storage for artifacts