Skip to content

allcupsnotinprivate/rye-monorepository

Repository files navigation

Monorepo Example with Rye, uv and Docker

This repository contains several Python services and shared libraries managed via Rye and built with uv.

📁 Project Structure

.
├── deploy                      # Dockerfiles and docker-compose
├── pyproject.toml             # Root pyproject (virtual) - ONLY dev dependencies
├── requirements-dev.lock      # Lock file of development dependencies (tests, linters, etc.)
├── requirements.lock          # Common lock file for dependencies if a single lock is used
└── src
    ├── libs                   # Shared code used by services
    │   ├── pyproject.toml     # Separate pyproject for building/publishing libs
    │   └── src/libs/...       # Library source code
    ├── service_A              # Service A: random number generator
    │   ├── pyproject.toml     # Separate pyproject for building/publishing service A
    │   └── src/service_a/...  # Service A source code (named after service)
    └── service_B              # Service B: echo + random, depends on A and libs
        ├── pyproject.toml     # Separate pyproject for building/publishing service B
        └── src/service_b/...  # Service B source code (named after service)

🧰 Requirements

  • Python 3.12+
  • Rye
  • uv
  • Docker

📋 Architecture Principles

Root pyproject.toml (Virtual Project)

The root pyproject.toml serves as a virtual project for local development coordination:

  • ONLY contains development dependencies (linters, formatters, test tools, etc.)
  • NO production dependencies - these belong in individual service/library pyproject.toml files
  • This prevents production dependencies from being missed during Docker builds
  • Provides a unified development environment for the entire monorepo
  • Acts as constraints for dependency resolution across all workspace members

Workspace Configuration

All packages in src/ that should be used as final packages or dependencies must be defined in the workspace:

[tool.rye.workspace]
members = [
    "src/service_*",
    "src/libs",
]

This configuration:

  • Automatically discovers all services matching the src/service_* pattern
  • Includes shared libraries from src/libs
  • Enables cross-package dependencies within the monorepo
  • Coordinates dependency resolution across all workspace members

Service Package Naming

Each service's source code is organized with the package named after the service:

src/service_A/src/service_a/  # Package named 'service_a'
src/service_B/src/service_b/  # Package named 'service_b'

This prevents PYTHONPATH conflicts when running services locally, as each service has its own uniquely named package.

🚀 Quick Start

Local Development Setup

# Sync all dependencies using Rye
rye sync

# Run individual services locally using Rye scripts
rye run run-service-A
rye run run-service-B

Docker Deployment

# Build and run using Docker Compose
cd deploy
docker-compose up --build

🛠️ Local Development & Debugging

The root pyproject.toml includes convenient scripts for running and debugging services locally:

[tool.rye.scripts]
run-service-A = { cmd = "python src/service_A/src/service_a/main.py", target = "src/service_A", env = {PYTHONPATH = "src/service_A/src"} }
run-service-B = { cmd = "python src/service_B/src/service_b/main.py", target = "src/service_B", env = {PYTHONPATH = "src/service_B/src"} }

Script Features:

  • target: Sets the working directory to the service's root
  • env.PYTHONPATH: Ensures proper module resolution for the service
  • Individual execution: Each service runs with its own isolated Python path

Usage Examples:

# Run Service A locally
rye run run-service-A

# Run Service B locally  
rye run run-service-B

# Run with additional environment variables
CUSTOM_VAR=value rye run run-service-A

🏗️ Development Workflow

  1. Install dependencies: rye sync
  2. Develop locally: Use rye run run-<service-name> scripts
  3. Test changes: Run tests for individual services or the entire monorepo
  4. Build containers: Use Docker Compose for integration testing
  5. Deploy: Deploy individual services or the entire stack

📦 Dependency Management

  • Root level: Development tools only (pytest, black, mypy, etc.)
  • Service level: Service-specific production and development dependencies
  • Library level: Library dependencies that can be shared across services
  • Lock files: Centralized dependency resolution while maintaining service isolation

About

Python monorepo template with Rye, uv, and Docker - multiple services with shared libraries

Topics

Resources

License

Stars

Watchers

Forks