Cloning the repository
Spree is a big monorepo. For a faster clone, use a partial clone which downloads file contents on demand while keeping full commit history forgit log and git blame:
Prerequisites
You need Node.js 20+ to run the workspace scripts (includingpnpm server:setup, which both backend and TypeScript contributors use). Install it via nvm, mise, fnm, or your package manager (brew install node on macOS).
pnpm is provisioned automatically via Corepack (bundled with Node) — the repository pins its version in package.json, and the first pnpm command will fetch the matching release. If Corepack is disabled in your environment, run corepack enable once.
Spree codebase
Spree is a monorepo with three main areas:spree/— Ruby gems (core, api, admin, emails) distributed as separate packages via RubyGemspackages/— TypeScript packages (SDKs, CLI, project scaffolding, docs)server/— A Rails application cloned from spree-starter that mounts the Spree gems (not checked in — runpnpm server:setupto create it)
Backend Development (Ruby)
Engines overview
The Spree Rails engines live insidespree/ and are distributed as separate gems (Ruby packages installed via Bundler):
| Engine | Gem | Description |
|---|---|---|
core | spree_core | Models, services, business logic |
api | spree_api | REST APIs |
admin | spree_admin | Admin dashboard |
emails | spree_emails | Transactional emails |
Spree namespace
All Spree models, controllers and other Ruby classes are namespaced by theSpree keyword, eg. Spree::Product. This means that those files are also located in spree sub-directories eg. app/models/spree/product.rb.
Setup
The server app is not checked into the monorepo. It’s cloned from spree-starter on first setup, withSPREE_PATH=.. automatically configured so it uses your local Spree gems.
Step 1: Clone the server app
server/ and sets SPREE_PATH=.. in server/.env so it uses your local Spree gems.
Step 2: Configure and run
bin/setup installs system services natively (PostgreSQL, Redis, Meilisearch) via brew bundle on macOS or apt-get on Linux. If you’d rather run those services in Docker, start them from the repo root before running bin/setup:
bin/setup --reset to drop and recreate the database.
The app runs at http://localhost:3000. Admin Panel is at http://localhost:3000/admin.
Step 3 (optional): Load sample data
To populate your store with sample products, customers, orders, and configuration:
Running engine tests
Each engine has its own test suite. First install the shared dependencies at thespree/ level, then navigate into the specific engine to set up and run its tests:
core with api, admin, or emails to test other engines.
By default engine tests run against SQLite3. To run against PostgreSQL, set the DB environment variable:
Running tests in parallel
For faster test runs on multi-core machines, you can use theparallel_tests gem to distribute spec files across multiple CPU cores.
After setting up the test app, create databases for parallel workers:
bundle exec rake parallel_setup to update the worker databases.
Integration tests (Admin Panel)
The Admin Panel uses feature specs that run in a real browser via chromedriver. You only need this if you’re working on admin UI changes. Install chromedriver on macOS:Performance in development mode
You may notice that your Spree store runs slower in development environment. This is caused by disabled caching and automatic reloading of code after each change. Caching is disabled by default. To turn on caching please run:TypeScript Development
Setup
TypeScript developers don’t need Ruby installed. Docker Compose from the repository root starts the backend using a prebuilt image:pnpm server:setup needed). The API is available at http://localhost:3000.
Then install dependencies and start all packages in watch mode:
Packages
| Package | Path | Description |
|---|---|---|
@spree/sdk | packages/sdk | TypeScript SDK for the Spree Store API |
@spree/cli | packages/cli | CLI for managing Spree Commerce projects |
create-spree-app | packages/create-spree-app | Project scaffolding (npm create spree-app) |
@spree/docs | packages/docs | Developer documentation for AI agents and local reference |
@spree/admin-sdk, @spree/sdk-core) are also part of the workspace but are not published to npm.
Common commands
Run from the repository root — Turborepo orchestrates tasks across all packages:| Command | Description |
|---|---|
pnpm dev | Start Docker backend + watch mode for all packages |
pnpm build | Build all packages (Turbo resolves dependency order) |
pnpm test | Run tests in all packages |
pnpm lint | Lint all packages |
pnpm typecheck | Type-check all packages |
pnpm clean | Remove build artifacts |
Package-specific commands
You can also run commands in a single package:Type generation
TypeScript types inpackages/sdk/src/types/generated/ are auto-generated from the Rails API serializers using typelizer. To regenerate after changing serializers:
Releasing packages
Published packages use Changesets for version management. Each package owns its own.changeset/ folder, so changesets must be created from inside the package directory:
main, a GitHub Action creates a “Version Packages” PR that bumps the version and publishes to npm.
Code Style
Consistent code style is enforced via automated linters. Please make sure your changes pass linting before submitting a PR. Ruby: We use RuboCop for Ruby code. The configuration lives inserver/.rubocop.yml and is shipped with spree-starter, so it’s only available after running pnpm server:setup. Run it from the server/ directory:
Making Changes
Branch naming
Create a new branch for your changes. Do not push changes to the main branch. Branch names should be human-readable and informative:- Bug fixes:
fix/order-recalculation-total-bug - Features:
feature/my-new-amazing-feature
Commit messages
Keep your commit history meaningful and clear. Each commit should represent a logical unit of work. This guide covers this well. A few tips:- Write commit messages in the imperative mood (e.g. “Add feature” not “Added feature”)
- Keep the first line under 72 characters
- If your change references a GitHub issue, include
Fixes #<number>in the commit message or PR description to auto-close it on merge
Submitting Changes
We use GitHub Actions to run CI.-
Push your changes to a topic branch in your fork of the repository.
-
Create a Pull Request against the
mainbranch. - Wait for CI to pass.
- Wait for Spree Core team code review. We aim to review and leave feedback as soon as possible.
Pull request guidelines
To help us review your PR quickly:- Keep PRs focused. One feature or fix per PR. Smaller PRs are easier to review and merge.
- Describe your changes. Explain what you changed and why. Include screenshots for UI changes.
- Add tests. All new features and bug fixes should include appropriate test coverage.
- Update documentation. If your change affects user-facing behavior, update the relevant docs.
- Include a changeset if your change affects a published TypeScript package (
@spree/sdk,@spree/cli, orcreate-spree-app). Runpnpm changesetfrom inside that package’s directory — each package owns its own.changeset/folder. - Ensure CI passes. PRs with failing CI will not be reviewed.
Reporting Bugs
We use GitHub Issues to track bugs. Before filing a new issue, please search existing issues to avoid duplicates. When reporting a bug, please include:- Spree version you’re using
- Steps to reproduce the problem
- Expected behavior vs actual behavior
- Relevant logs or stack traces (formatted with triple backticks)
- Your environment (Ruby version, database, OS)

