You are assisting with development in a unified Nx monorepo that consolidates all Supabase JavaScript SDKs, built with Nx for optimal developer experience and maintainability. This strategic migration from 6 separate repositories addresses critical maintenance overhead, dependency duplication, and release coordination challenges while maintaining zero breaking changes for consumers.
📚 Essential Documentation: Always refer to these guides for detailed information:
- CONTRIBUTING.md - Development guidelines, commit format, PR process
- TESTING.md - Complete testing guide with Docker requirements
- RELEASE.md - Release workflows and versioning strategy
- MIGRATION.md - Migration context from old repositories
- SECURITY.md - Security policies and responsible disclosure
supabase-js/
├── packages/core/
│ ├── supabase-js/ # @supabase/supabase-js - Main isomorphic client for Supabase
│ ├── auth-js/ # @supabase/auth-js - Authentication client
│ ├── postgrest-js/ # @supabase/postgrest-js - PostgREST client for database operations
│ ├── realtime-js/ # @supabase/realtime-js - Real-time subscriptions client
│ ├── storage-js/ # @supabase/storage-js - File storage client
│ └── functions-js/ # @supabase/functions-js - Edge Functions client
├── docs/ # Comprehensive documentation guides
│ ├── CONTRIBUTING.md # Contribution guidelines
│ ├── TESTING.md # Testing guide
│ ├── RELEASE.md # Release workflows
│ ├── MIGRATION.md # Migration guide
│ └── SECURITY.md # Security policy
├── scripts/ # Automation scripts
│ ├── release-canary.ts # Canary release automation
│ ├── release-stable.ts # Stable release automation
│ └── update-version-files.ts # Version management
├── nx.json # Nx workspace configuration
├── tsconfig.base.json # Base TypeScript configuration
├── package.json # Root package with workspace scripts
└── commitlint.config.js # Commit message validation
- Dependency Consolidation: 22 previously duplicated dependencies now centrally managed
- Atomic Changes: Cross-library fixes in single PRs
- Immediate Integration Testing: No manual release coordination needed
- Unified Versioning: Fixed version mode with automated releases using
nx release - Intelligent Building: Nx only rebuilds/tests what actually changed
Every change must maintain full backward compatibility. The migration itself introduces no breaking changes - all packages maintain their original npm names and APIs.
Uses automated canary releases with batched stable releases:
- Canary: Every commit to master → prerelease (e.g.,
2.80.1-canary.0) withcanarydist-tag - Stable: Manual promotion of validated canary to
latestdist-tag - Fixed Versioning: All packages share identical version numbers (e.g., all at 2.80.0)
- Version Line: Continuing with v2.x.x to maintain ecosystem stability
Three Release Workflows:
- Canary (
.github/workflows/main-ci-release.yml) - Automated on every master commit - Stable (
.github/workflows/release-stable.yml) - Manual by repository owners - Preview (
.github/workflows/preview-release.yml) - PR-based testing via pkg.pr.new
📖 See RELEASE.md for complete release documentation
Internal dependencies use the * protocol:
// packages/core/supabase-js/package.json
{
"dependencies": {
"@supabase/auth-js": "*",
"@supabase/realtime-js": "*",
"@supabase/functions-js": "*",
"@supabase/storage-js": "*",
"@supabase/postgrest-js": "*"
}
}Nx automatically replaces * with the actual version during release.
Always use nx affected commands to build/test only what changed, leveraging Nx's dependency graph intelligence.
Use conventional commit format for automated versioning:
fix(auth-js): resolve token refresh race condition→ Patch releasefeat(realtime-js): add presence support→ Minor releasefeat(auth)!: remove deprecated method→ Major releasechore(deps): update TypeScript to 5.8→ No version bump
Always use the interactive commit tool:
npm run commit📖 See CONTRIBUTING.md for complete commit guidelines
nx run-many --target=build --all # Build all packages
nx build auth-js # Build specific package
nx affected --target=build # Build only affected
nx build auth-js --watch # Development mode# Test specific packages (complete test suites with Docker setup/cleanup)
nx test:auth auth-js # Complete auth-js test suite (handles Docker)
nx test:storage storage-js # Complete storage-js test suite (handles Docker)
nx test:ci:postgrest postgrest-js # Complete postgrest-js test suite (handles Docker)
nx test functions-js # Standard test (uses testcontainers)
nx test realtime-js # Standard test (no Docker needed)
nx test supabase-js # Standard test (unit tests only)
# Coverage reports
nx test supabase-js --coverage
nx test:coverage realtime-js
nx test:ci functions-js # Includes coverageDocker Requirements:
| Package | Docker Required | Infrastructure | Complete Test Command | Individual Commands |
|---|---|---|---|---|
| auth-js | ✅ Yes | Auth Server + Postgres | nx test:auth auth-js |
nx test:suite auth-js, nx test:infra auth-js, nx test:clean auth-js |
| storage-js | ✅ Yes | Storage API + PostgreSQL + Kong | nx test:storage storage-js |
nx test:suite storage-js, nx test:infra storage-js, nx test:clean storage-js |
| postgrest-js | ✅ Yes | PostgREST + PostgreSQL | nx test:ci:postgrest postgrest-js |
nx test:run postgrest-js, nx test:update postgrest-js, nx test:types postgrest-js |
| functions-js | ✅ Yes | Deno relay (testcontainers) | nx test functions-js |
nx test:ci functions-js (with coverage) |
| realtime-js | ❌ No | Mock WebSockets | nx test realtime-js |
nx test:coverage realtime-js, nx test:watch realtime-js |
| supabase-js | ❌ No | Unit tests only | nx test supabase-js |
nx test:all, nx test:unit, nx test:integration, nx test:coverage, nx test:watch |
supabase-js Additional Test Commands:
nx test:all supabase-js # Unit + integration + browser tests
nx test:unit supabase-js # Jest unit tests only
nx test:integration supabase-js # Node.js integration tests
nx test:integration:browser supabase-js # Browser tests (requires Deno)
nx test:edge-functions supabase-js # Edge Functions tests
nx test:deno supabase-js # Deno runtime tests
nx test:bun supabase-js # Bun runtime tests
nx test:expo supabase-js # React Native/Expo tests
nx test:next supabase-js # Next.js SSR tests
nx test:node:playwright supabase-js # WebSocket browser tests
nx test:types supabase-js # TypeScript type checking
nx test:coverage supabase-js # Coverage report
nx test:watch supabase-js # Watch mode📖 See TESTING.md for complete testing guide and troubleshooting
nx run-many --target=lint --all # Lint all packages
nx lint storage-js # Lint specific package
nx format # Auto-format all code
nx format:check # Check formattingnx graph # Interactive dependency graph
nx show projects # List all projects
nx affected --graph # Visualize affected projectsScenario: Bug in supabase-js caused by realtime-js
Monorepo Solution:
- Fix root cause in
packages/core/realtime-js/src/ - Add unit test in
packages/core/realtime-js/test/ - Add integration test in
packages/core/supabase-js/test/ - Run complete test suites for both packages to verify impacts
- Commit:
fix(realtime-js): resolve reconnection logic affecting supabase-js - Single PR, single review, single release - all packages version together
- Implement in appropriate library under
packages/core/[library]/src/ - Write comprehensive unit tests in
packages/core/[library]/test/ - If feature affects supabase-js, add integration tests there
- Update TypeScript types if needed
- Run complete test suite for the package before committing
- Use conventional commit:
feat(storage-js): add resumable uploads
# Even for single-library fixes:
git add .
git commit -m "fix(auth-js): correct session expiry calculation"
# → Automatic canary: 2.80.1-canary.0 published to 'canary' dist-tag
# Run complete test suite for the package:
nx test:auth auth-js
# After validation, manual promotion:
nx release --tag=latest --yes # Promotes to stable with same version for ALL packages- Target: ES2022
- Module: NodeNext
- Strict: true
- Isolated Modules: true (faster compilation)
- Composite: true (incremental builds)
Each library has its own tsconfig.json extending the base configuration, allowing for library-specific adjustments while maintaining consistency.
This repository uses TypeScript project references for incremental builds and better type checking across packages.
What's Configured:
-
tsconfig.base.json - Base configuration inherited by all projects:
composite: true- Enables project referencesdeclaration: true- Required by compositemoduleResolution: "bundler"- Works with workspacesisolatedModules: true- Inherited but overridden in core packagesnoImplicitOverride: true- Inherited but overridden in core packages- No
customConditions- Removed to avoid conflicts with CommonJS packages
-
Root tsconfig.json - References all projects in the monorepo:
{ "extends": "./tsconfig.base.json", "files": [], "references": [ { "path": "./packages/core/auth-js" }, { "path": "./packages/core/realtime-js" } // ... all other packages ] } -
Core packages (auth-js, realtime-js, postgrest-js, functions-js, storage-js):
- Keep
module: "CommonJS"for backward compatibility - Override
moduleResolution: "Node"(required for CommonJS) - Override
isolatedModules: false(existing code doesn't useexport type) - Override
noImplicitOverride: false(existing code doesn't useoverridekeyword) - Add
referencesarray pointing to dependencies (managed bynx sync)
- Keep
-
Utils packages (utils-fetch):
- Inherit
moduleResolution: "bundler"from base - Can optionally add
customConditions: ["@supabase-js/source"]for source preference
- Inherit
Key Principles:
- ✅ No Breaking Changes: Build output is identical - only type-checking is affected
- ✅ Incremental Builds: TypeScript only recompiles changed projects
- ✅ Better Performance: Reduced memory usage during builds
- ✅ Automatic References: Nx sync automatically maintains project references
⚠️ NocustomConditionsin base: Would conflict withmoduleResolution: "Node"
When Adding New Packages:
- Ensure
composite: trueanddeclaration: trueare set - Add
referencesarray pointing to dependencies - If using CommonJS, override
moduleResolution: "Node"and disable strict options - Run
nx syncto update root tsconfig.json automatically
Important Notes:
- TypeScript project references work WITHOUT
customConditions- it's optional customConditionsonly optimizes source file resolution during development- Core packages use
moduleResolution: "Node"which is incompatible withcustomConditions - The
isolatedModules: falseoverride avoids requiringexport typefor type re-exports - All build outputs remain identical to pre-project-references setup
- Location:
packages/core/[library]/test/ - Pattern: Mirror source structure
- Principle: Test public APIs thoroughly
- Mocking: Mock external dependencies
Complete Test Suites (Recommended):
# Auth-js: Complete test suite (handles Docker setup/cleanup automatically)
nx test:auth auth-js
# Storage-js: Complete test suite (handles Docker setup/cleanup automatically)
nx test:storage storage-js
# Postgrest-js: Complete test suite (handles Docker setup/cleanup automatically)
nx test:ci:postgrest postgrest-jsManual Infrastructure Management (for development):
# Auth-js
nx test:infra auth-js # Start Docker containers
nx test:suite auth-js # Run tests (can run multiple times)
nx test:clean auth-js # Cleanup
# Storage-js
nx test:infra storage-js # Start Docker containers
nx test:suite storage-js # Run tests (can run multiple times)
nx test:clean storage-js # Cleanup
# Postgrest-js
nx db:run postgrest-js # Start containers
nx test:run postgrest-js # Run tests
nx db:clean postgrest-js # CleanupTests run against multiple environments:
- Node.js (native)
- Next.js (SSR/React)
- Expo (React Native)
- Bun (alternative runtime)
- Deno (secure runtime)
- Browser (via Puppeteer)
- Aggregates all other libraries
- Primary integration testing location
- Most complex cross-platform test suite (Node.js, Next.js, Expo, Bun, Deno, Browser)
- Users typically interact through this package
- Default branch: master
- Requires Docker for integration tests (GoTrue + PostgreSQL)
- Complex session management logic
- Security-critical - extra review care needed
- See auth-js README for details
- WebSocket-based, timing-sensitive
- Mock time in tests when possible
- No Docker required (uses mock WebSockets)
- See realtime-js README for details
- Requires Docker for integration tests (Storage API + PostgreSQL + Kong)
- File handling varies by platform
- See storage-js README for details
- Pure HTTP client, easiest to test
- Requires Docker for integration tests (PostgREST + PostgreSQL)
- See postgrest-js README for details
- Simplest library, minimal dependencies
- Uses testcontainers for Deno relay
- See functions-js README for details
- Prettier handles all formatting (configured in
.prettierrc) - Run
nx formatbefore committing - No formatting debates - Prettier decides
- Follow existing patterns in each library
- Extract shared code to packages/shared/ when identified
- Maintain consistency across monorepo
- JSDoc for all public APIs
- README per package with examples
- Update docs when changing APIs
Current Repository:
- Default branch:
master(confirmed current default) - Repository URL:
github.com/supabase/supabase-js
Original Repository Branches (for historical reference):
- master: auth-js, postgrest-js, realtime-js, supabase-js
- main: functions-js, storage-js
When referencing original repository history or comparing changes, be aware of these branch name differences.
- All packages publish to npm under
@supabasescope - Versions synchronized via fixed release mode (all packages always have same version)
- Changelogs generated per package from conventional commits
- "No user-facing changes" message for unchanged packages
- Three dist-tags:
latest(stable),canary(pre-release),next(legacy)
Integration tests for auth-js, functions-js, postgrest-js, and storage-js require Docker running locally:
- macOS/Windows: Ensure Docker Desktop is installed and running
- Linux: Ensure Docker daemon is running
- CI: Docker is automatically available in GitHub Actions
Check TESTING.md for port requirements and troubleshooting.
All commits are validated using commitlint with strict rules:
- Type: Required (feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert)
- Scope: Required (auth, functions, postgrest, realtime, storage, supabase, repo, deps, ci, release, docs, scripts, misc)
- Subject: Required, imperative mood, no period at end, max 100 characters
- Interactive Tool: Use
npm run committo ensure compliance
See CONTRIBUTING.md for complete details.
❌ Wrong:
"@supabase/auth-js": "3.5.0"✅ Correct:
"@supabase/auth-js": "*"❌ Wrong:
cd packages/core/auth-js && npm test✅ Correct:
nx test:auth auth-js❌ Wrong:
nx run-many --target=test --all # Won't work - no standard test target for all packages✅ Correct:
# Run complete test suite for the specific package
nx test:auth auth-js
nx test:storage storage-js
nx test:ci:postgrest postgrest-js
nx test functions-js
nx test realtime-js
nx test supabase-js❌ Wrong: Changing public API signatures without proper process
// Don't just change existing method signatures
- signIn(email: string): Promise<void>
+ signIn(credentials: Credentials): Promise<void>✅ Correct: Add new methods, deprecate old ones gradually, use proper commit format
// Add new method
signIn(credentials: Credentials): Promise<void>
// Deprecate old method with backward compatibility
/** @deprecated Use signIn(credentials) instead */
signInWithEmail(email: string): Promise<void> {
return this.signIn({ email })
}Use breaking change commit format when necessary:
feat(auth)!: remove deprecated signInWithEmail method
BREAKING CHANGE: The deprecated signInWithEmail method has been removed.
Use signIn({ email }) instead.❌ Wrong: Running npm commands directly in library directories
cd packages/core/auth-js
npm test
npm run build✅ Correct: Use Nx commands from repository root
nx test:auth auth-js
nx build auth-js --watch❌ Wrong: Using git commit directly
git commit -m "fix auth bug" # Missing scope, will fail validation✅ Correct: Use the interactive commit tool
npm run commit # Guides you through proper format❌ Wrong: Assuming you know how to run tests without checking
nx test storage-js # Wrong - should use nx test:storage storage-js✅ Correct: Check library README and TESTING.md first
# Read docs first
cat packages/core/storage-js/README.md
cat docs/TESTING.md
# Then run tests with proper setup📖 See CONTRIBUTING.md for complete PR guidelines
-
Ensure branch is up to date:
git checkout master git pull upstream master git checkout your-feature-branch git rebase master
-
Run all necessary checks:
nx format # Format code # Run complete test suite for affected packages individually nx test:auth auth-js # If auth-js changed nx test:storage storage-js # If storage-js changed # ... etc for other packages nx affected --target=lint # Lint affected packages nx affected --target=build # Build affected packages
-
Use interactive commit tool:
npm run commit
- ✅ At least 1 approving review from a code owner
- ✅ All status checks passing (CI/CD pipeline)
- ✅ No merge conflicts with the base branch
- ✅ Squash merge only (enforced by repository settings)
## Description
Brief description of what this PR does
## Type of Change
- [ ] Bug fix (fix)
- [ ] New feature (feat)
- [ ] Breaking change (feat! or fix!)
- [ ] Documentation update (docs)
- [ ] Other (chore, refactor, etc.)
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated (if applicable)
- [ ] All tests passing locally
## Checklist
- [ ] Code formatted (`nx format`)
- [ ] Tests passing (run complete test suites for affected packages)
- [ ] Builds passing (`nx affected --target=build`)
- [ ] Used conventional commits
- [ ] Documentation updated (if needed)If you need to test your changes before merging:
- Create your PR
- Comment: "Can a maintainer add the preview label for testing?"
- Wait for maintainer to add
trigger: previewlabel - Follow instructions in automated comment to install preview packages
# Visualize dependency graph
nx graph
# Show what's affected by changes
nx affected --graph
# List all projects
nx show projects
# See project details
nx show project auth-js --web
# Clear Nx cache
nx reset# 1. Create feature branch
git checkout -b feat/your-feature
# 2. Make changes in packages/core/[library]/
# 3. Test continuously
nx test [library] --watch
# 4. Format before committing
nx format
# 5. Commit with tool
npm run commit
# 6. Before pushing
# Run complete test suite for the package you changed
nx test:auth auth-js # If auth-js changed
nx test:storage storage-js # If storage-js changed
# ... etc
nx affected --target=build
nx format:check
# 7. Push and create PR
git push origin feat/your-feature# Clear cache and rebuild
nx reset
nx run-many --target=build --all
# Clean install
rm -rf node_modules
npm install
# Check for errors
nx run-many --target=lint --all
# Run specific test file (for packages with standard test target)
nx test realtime-js --testFile=RealtimeClient.test.ts
nx test supabase-js --testFile=client.test.ts- README.md - Repository overview and quick start
- CONTRIBUTING.md - Complete contribution guide
- TESTING.md - Comprehensive testing documentation
- RELEASE.md - Release workflows and automation
- MIGRATION.md - Migration context and history
- SECURITY.md - Security policy and reporting
- Supabase Documentation - Official Supabase docs
- Nx Documentation - Nx monorepo documentation
- Conventional Commits - Commit format specification
❌ Wrong: Only testing in source library ✅ Correct: Test in source library AND integration tests in supabase-js
Canary Releases (Automated):
# Triggered automatically on every commit to master
git commit -m "fix(auth): resolve token issue"
# → Automatic CI: nx release --tag=canary --yes
# → Published: 2.80.1-canary.0 to 'canary' dist-tagStable Releases (Manual):
# 1. Validate canary version
# Run complete test suites for packages individually
# 2. Preview stable promotion
nx release --dry-run
# 3. Promote canary to stable
nx release --tag=latest --yes
# Alternative: Promote specific canary
nx release --specifier=2.80.1 --tag=latest --yes- CI detects conventional commits
- Determines version bump (patch/minor/major)
- Generates prerelease version (e.g., 2.80.1-canary.0)
- Updates all package.json files
- Replaces
*with actual versions - Publishes all packages to npm with
canarydist-tag - Triggers dogfooding workflows (when configured)
- Promotes validated canary to
latestdist-tag - Generates curated per-package changelogs
- Creates GitHub release with notes
- All packages get identical stable version
The workspace is configured for hybrid releases in nx.json:
{
"release": {
"projectsRelationship": "fixed",
"version": {
"conventionalCommits": true
},
"changelog": {
"projectChangelogs": true,
"workspaceChangelog": true
}
}
}# Canary releases (automated in CI)
nx release --tag=canary --yes # Publish to 'canary' dist-tag
nx release --specifier=prerelease --tag=canary # Force prerelease bump
# Stable releases (manual promotion)
nx release --tag=latest --yes # Promote to 'latest' dist-tag
nx release --specifier=2.80.1 --tag=latest # Promote specific version
# Preview and debugging
nx release --dry-run # Preview changes
nx release --dry-run --verbose # Detailed preview
nx release --first-release --dry-run # First release preview
# Version-specific releases
nx release --specifier=patch --tag=latest # Force patch bump
nx release --specifier=minor --tag=latest # Force minor bump
nx release --specifier=major --tag=latest # Force major bump## @supabase/realtime-js 2.80.1 (2025-09-16)
- fix: correct reconnection logic (#123)
## @supabase/auth-js 2.80.1 (2025-09-16)
_No user-facing changes in this release._
## @supabase/supabase-js 2.80.1 (2025-09-16)
_No user-facing changes in this release._- Consider Monorepo Impact: Changes might affect multiple packages - always check dependencies
- Use Nx Commands: Always prefer
nxover directnpmfor workspace operations - Suggest Complete Test Suites: Use complete test suites (
nx test:auth auth-js,nx test:storage storage-js, etc.) for packages individually - Respect Fixed Versioning: All packages version together - no independent versioning
- Maintain Compatibility: Never introduce breaking changes without proper process
- Check Testing Requirements: Be aware of Docker requirements for integration tests
- Extract Shared Code: Identify patterns that could be shared across packages
- Follow Conventions: Use existing patterns and structures within each library
- Document Changes: Update JSDoc and READMEs when changing public APIs
- Use Conventional Commits: Always suggest proper commit format with scope
Q: Where does this code belong?
- Authentication logic → auth-js
- Database queries → postgrest-js
- Real-time subscriptions → realtime-js
- File operations → storage-js
- Edge function calls → functions-js
- Integration of above → supabase-js
- Shared utilities → packages/shared/ (create if needed)
Q: How to test this change?
- Unit test in source library
- Integration test in supabase-js if affects it
- Run complete test suite for the package:
nx test:auth auth-js(handles Docker automatically)nx test:storage storage-js(handles Docker automatically)nx test:ci:postgrest postgrest-js(handles Docker automatically)nx test functions-js(uses testcontainers)nx test realtime-js(no Docker needed)nx test supabase-js(unit tests only)
- Run complete test suites for all affected packages individually
Q: How will this release?
- All packages version together in fixed mode
- Your commit triggers automatic canary release for ALL packages
- Weekly promotion of validated canary to stable
- Unchanged packages show "No user-facing changes"
- Single npm install updates entire SDK suite
Remember: This monorepo optimizes for developer experience and maintenance efficiency while ensuring zero breaking changes for the millions of developers using Supabase SDKs.
- For navigating/exploring the workspace, invoke the
nx-workspaceskill first - it has patterns for querying projects, targets, and dependencies - When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through
nx(i.e.nx run,nx run-many,nx affected) instead of using the underlying tooling directly - Prefix nx commands with the workspace's package manager (e.g.,
pnpm nx build,npm exec nx test) - avoids using globally installed CLI - You have access to the Nx MCP server and its tools, use them to help the user
- For Nx plugin best practices, check
node_modules/@nx/<plugin>/PLUGIN.md. Not all plugins have this file - proceed without it if unavailable. - NEVER guess CLI flags - always check nx_docs or
--helpfirst when unsure
- For scaffolding tasks (creating apps, libs, project structure, setup), ALWAYS invoke the
nx-generateskill FIRST before exploring or calling MCP tools
- USE for: advanced config options, unfamiliar flags, migration guides, plugin configuration, edge cases
- DON'T USE for: basic generator syntax (
nx g @nx/react:app), standard commands, things you already know - The
nx-generateskill handles generator discovery internally - don't call nx_docs just to look up generator syntax