Guides

Monorepos

Detect deployable packages, bulk-import a stack into one project, choose build modes, and use path filters — without running docker-compose on the platform.

Bytstack treats a monorepo as one project (a stack) with many services. Connect the GitHub repository once, review detected packages, then create and deploy the ones you select.

Naming: A Bytstack workspace is your team/billing boundary (members, plan, GitHub App). A package-manager workspace (pnpm/npm/yarn) is how your monorepo declares packages. This guide is about the latter — never call env vars “workspace env.”

What we detect

Analyze (GET /v1/github/repos/:owner/:name/analyze-workspace or Import → Monorepo) reads the repo tree and merges signals from:

SourceWhat it finds
pnpm / npm / yarn / bun workspacesPackages under workspace globs
Turborepo / NxPipeline/project graph hints; libraries demoted
docker-compose.ymlApp services with build:; managed Postgres and Redis offers from known images
Heuristic fallbackpackage.json with start/build scripts when no workspace file exists

Noise packages (eslint-config, tsconfig, docs-only, etc.) are ignored. Each candidate includes a suggested service type, rootDir, default path filters, and a recommended build mode.

Checklist import UX

  1. Connect the GitHub App to the repo.
  2. Open New → Import monorepo (or run bytstack analyze).
  3. Review the checklist: services selected by default, optional Postgres offer, plan remaining counts.
  4. Adjust names, types, path filters, and build mode per row.
  5. Confirm — Bytstack creates the project, selected services, optional managed Postgres, and enqueues first deploys.

Bulk import is atomic for service rows: if quota would be exceeded, you get an upgrade CTA and zero partial creates.

Isolated vs workspace build mode

ModeWhen to useBuild behavior
isolated (default)Package has its own Dockerfile / self-contained installBuild context = service rootDir
workspaceNeeds repo-root install + filter (pnpm --filter, etc.)Clone repo root; run package-manager filter for workspacePackage

Use workspace only when the package truly depends on the monorepo install graph. Wrong mode usually fails at install or “cannot find package” — see Troubleshooting.

Path filters & shared packages

  • pathFilters — glob list; a push deploys the service only when a changed file matches (empty list = always deploy).
  • dependencyPaths — extra paths (e.g. packages/domain) that should also trigger this service.

Include shared packages and the lockfile / workspace root files your install depends on when relevant (e.g. pnpm-lock.yaml, pnpm-workspace.yaml), or dependents may skip when only the lockfile changes.

Example: change under packages/domain redeploys api + worker that list that path, while a UI-only package with apps/web/** stays idle.

Compose mapping (no Compose runtime)

We do not run docker-compose.yml on the platform.

Compose roleBytstack mapping
App with build:Candidate service
postgres / PostGIS imagesOptional managed Postgres offer
redis, valkey, bitnami/redis, redis-stack-serverOptional managed Redis offer
MySQL, Mongo, KeyDB, Kafka, NATS, etc.Unsupported offer — warning only; no service created

Redis offers: Accepted Redis offers create a managed Redis (Valkey) instance. Setup after import is Managed Redis. The checklist suggests a use case from your repo — Job queue when the stack has a worker or a QUEUE_REDIS_URL / Bull / Sidekiq signal, otherwise Cache — and an env var name taken from the compose env keys it saw (QUEUE_REDIS_URL, CACHE_URL, REDIS_URL, or REDIS_HOST → REDIS_URL). You can change both before importing. redis-stack-server is offered as managed Redis, but Redis Stack modules (RediSearch, JSON, TimeSeries, Bloom) are not available.

Bring your own (BYO): For unsupported infra, run it outside Bytstack and set the connection URL as a normal Variables entry on the services that need it. Do not expect Compose infra images to become Bytstack services.

Compose passwords and other secrets from compose files are never imported into the env store. After you accept a Postgres offer, the platform injects project-scoped DATABASE_URL. Redis connection URLs are injected the same way once the instance is ready — nothing is written at import time, so the variable appears when Redis becomes available.

Dalufy walkthrough

The fixture monorepo lives at examples/workspace/dalufy in the Bytstack repo (pnpm workspace: api, web, worker + compose Postgres).

  1. Mirror or push the fixture to GitHub and connect the App.
  2. Analyze — expect api, web, worker selected by default plus a Postgres offer.
  3. Import with the Postgres offer opted in.
  4. Confirm Compose passwords are not in Project → Environment; DATABASE_URL is platform-injected.
  5. Create env group backend, attach to api + worker; set web to ${{service.api.URL}} (or a public prefix) — see Variables.
  6. Prefer workspace build mode where the detector suggested it; confirm builds go live.
  7. Push a change under a shared package path → only dependents redeploy.
  8. Edit a group var → only attached services redeploy.

CLI equivalent:

bytstack analyze --repo your-org/dalufy
bytstack import --all --repo your-org/dalufy --project-name dalufy --yes
bytstack deploy --all --watch

Limits

See Pricing & limits for services per plan, bulk-import max, env group caps, and persistent environments.