Multi-Service Monorepo
Pilum is designed for monorepos with multiple services. This guide covers project organization, dependency management, and deployment strategies.
Recommended Structure
my-project/├── .pilumignore # Exclude examples, tests, etc.├── services/│ ├── api-gateway/│ │ ├── pilum.yaml│ │ ├── Dockerfile│ │ └── main.go│ ├── user-service/│ │ ├── pilum.yaml│ │ ├── Dockerfile│ │ └── main.go│ └── worker/│ ├── pilum.yaml│ ├── Dockerfile│ └── main.go├── shared/ # Shared libraries (no pilum.yaml)│ ├── auth/│ └── database/└── tools/ # CLI tools └── my-cli/Service Discovery
Pilum automatically discovers all pilum.yaml files in your project:
$ pilum listServices found: api-gateway gcp us-central1 user-service gcp us-central1 worker gcp us-central1 my-cli homebrewFlat vs Nested Structure
Both structures work. Choose based on your team’s preferences:
Flat (services at root):
my-project/├── api-gateway/│ └── pilum.yaml├── user-service/│ └── pilum.yaml└── worker/ └── pilum.yamlNested (grouped by domain):
my-project/├── services/│ ├── api/│ │ └── pilum.yaml│ └── workers/│ ├── email-worker/│ │ └── pilum.yaml│ └── payment-worker/│ └── pilum.yaml└── tools/ └── cli/ └── pilum.yamlService Dependencies
Use depends_on to control deployment order:
name: databaseprovider: gcp# ...name: apiprovider: gcpdepends_on: - database # Deploys after databasename: workerprovider: gcpdepends_on: - api # Deploys after api - database # Also depends on databasePilum builds a dependency graph and deploys in topological order:
$ pilum deploy --tag=v1.0.0Deploying 3 services... [1/3] database [2/3] api [3/3] workerCircular Dependencies
Pilum detects and rejects circular dependencies:
$ pilum checkError: circular dependency detected: api -> worker -> apiSelective Deployment
Deploy Specific Services
# Deploy only api and workerpilum deploy api worker --tag=v1.0.0Deploy Changed Services Only
Use --only-changed to deploy only services with git changes:
# Deploy services changed since main branchpilum deploy --only-changed --tag=v1.0.0
# Compare against specific refpilum deploy --only-changed --since=v1.0.0 --tag=v1.1.0This also includes services that depend on changed services:
$ pilum deploy --only-changed --tag=v1.0.0 --debugDEBUG: Service database has direct changesDEBUG: Service api included (depends on changed service)Found 2 service(s) with changes (1 direct, 1 via dependencies)Parallel Execution
Pilum deploys independent services in parallel:
# Auto-detect optimal worker countpilum deploy --tag=v1.0.0
# Limit parallelismpilum deploy --max-workers=2 --tag=v1.0.0
# Sequential (one at a time)pilum deploy --max-workers=1 --tag=v1.0.0Services with dependencies are deployed in order, but independent services run concurrently.
Mixed Providers
A single monorepo can have services for different providers:
name: apiprovider: gcpproject: my-gcp-projectregion: us-central1name: lambda-handlerprovider: awsregion: us-east-1function_name: my-lambdaname: my-cliprovider: homebrewproject: my-orgDeploy all services together:
pilum deploy --tag=v1.0.0Multi-Region Services
A single service can deploy to multiple regions:
name: global-apiprovider: gcpproject: my-projectregions: - us-central1 - europe-west1 - asia-east1Pilum expands this into three deployments:
$ pilum listServices found: global-api (us-central1) gcp global-api (europe-west1) gcp global-api (asia-east1) gcpDeploy specific regions:
# Deploy all regionspilum deploy global-api --tag=v1.0.0
# Deploy specific regionpilum deploy "global-api (us-central1)" --tag=v1.0.0Excluding Services
Use .pilumignore to exclude directories:
# Development onlyexamplesfixturestest-*
# Archived servicesarchived/*-deprecated
# Templatestemplates/See Ignore Files for full syntax.
Naming Conventions
Consistent naming helps with filtering and organization:
| Pattern | Example | Use Case |
|---|---|---|
{domain}-{type} | user-api, user-worker | Domain-driven design |
{type}-{name} | api-gateway, worker-email | Type-first grouping |
{env}-{name} | prod-api, staging-api | Environment separation |
CI/CD Tips
Deploy Changed Services
- name: Deploy changed services run: pilum deploy --only-changed --tag=${{ github.sha }}Deploy by Label/Path
# Deploy services in changed directories- name: Get changed services id: changes run: | SERVICES=$(git diff --name-only origin/main | grep pilum.yaml | xargs dirname | sort -u) echo "services=$SERVICES" >> $GITHUB_OUTPUT
- name: Deploy run: pilum deploy ${{ steps.changes.outputs.services }} --tag=${{ github.sha }}Validation on PR
- name: Validate configs run: pilum check
- name: Preview deployment run: pilum dry-run --tag=pr-${{ github.event.pull_request.number }}Next Steps
- Ignore Files — Exclude directories
- Service Configuration — Configure services
- CLI Commands — All available commands