Skip to main content

Monorepo builds

Deploy separate services from one repository with explicit root directories, Docker contexts, and automatic-deployment filters.

Share
Last updated on November 5, 2026
On this page

Deploy each independently operated application in a repository as a separate Bex service. Give it its own build/start commands, configuration, and deployment policy. A shared repository does not make services share environment variables or scale together.

Runnable shared-package sample​

bash
curl -fsSLO https://bex.co/examples/shared-package-monorepo-latest.zip
curl -fsSLO https://bex.co/examples/shared-package-monorepo-latest.zip.sha256
shasum -a 256 -c shared-package-monorepo-latest.zip.sha256
unzip shared-package-monorepo-latest.zip
cd shared-package-monorepo
npm install
npm run start:api
npm run start:worker-api
npm test
npm run rehearse

See also shared-package-monorepo README for Docker/Blueprint details. The archive includes a complete two-service Node workspace with a shared package, root lockfile, Dockerfiles built from the repository root, and a Blueprint whose filters include packages/shared/** and package-lock.json while ignoring docs/**.

Each service returns its own service identity plus sharedMessage / sharedVersion from the workspace package. npm run rehearse prints an explanatory push-deploy matrix checked against upstream filter composition (Bex d0f17feb3ece1ce20c8c85384e8ee68ff4b2e1d3); it is not live hosted evidence. Push the same scenarios from a repository you own after connecting Git and applying the Blueprint — inspect per-service deploy history and / responses.

Choose the service root​

rootDir selects the directory used for a service's build. Omit it to use the repository root. A self-contained Node.js app under apps/api can use:

yaml
services:
  - type: web
    name: api
    runtime: node
    repo: https://github.com/acme/monorepo
    rootDir: apps/api
    buildCommand: npm ci
    startCommand: npm start
    autoDeployTrigger: commit
    buildFilter:
      paths:
        - apps/api/**
      ignoredPaths:
        - apps/api/docs/**

This assumes apps/api contains its own package manifest and lockfile, and its start command listens on 0.0.0.0:$PORT. Replace the example repository and commands. Validate using the Blueprint guide before applying.

Native commands execute in the built application's working directory. Adjust build/start commands and static publish paths when changing the root. A package that relies on a root-level workspace lockfile or sibling package may need to build from the repository root instead, using package-manager workspace commands. Do not solve missing files with ../ traversal in a configured root path.

Dockerfile and build context​

Bex resolves the Dockerfile relative to rootDir. By default, the Docker build context is also that directory. An explicit dockerContext selects a context relative to the repository root, independently of rootDir.

For shared source, keeping the service root at the repository root makes the relationship clear:

yaml
services:
  - type: web
    name: api
    runtime: docker
    repo: https://github.com/acme/monorepo
    dockerfilePath: apps/api/Dockerfile
    dockerContext: .
    autoDeployTrigger: commit
    buildFilter:
      paths:
        - apps/api/**
        - packages/shared/**
        - package-lock.json

Write Dockerfile COPY paths relative to that build context, and check .dockerignore. A path to the Dockerfile does not make its containing directory the context. See Docker deployments for registry and image requirements.

To see this split against your own files, use the Docker build-context inspector. Supply the repository file inventory, Dockerfile and ignore files, then compare the resolved rootDir, dockerContext and dockerfilePath. An empty dockerContext inherits rootDir; an explicit . selects the repository root while the Dockerfile stays relative to rootDir. The inventory command lists paths without reading file contents. Confirm completeness only for the actual build source; the inspector distinguishes ignored files from absent inventory entries and leaves unsupported cases unresolved.

Decide which pushes deploy​

Bex checks the tracked repository/branch, auto-deploy setting, changed files under rootDir, and buildFilter. Build-filter globs are repository-relative:

  • With included paths, a changed file must match one of them.
  • An ignoredPaths match excludes that file even if an include also matches.
  • With no included paths, changes are eligible unless ignored.

Root-directory and build-filter checks both apply. Adding a sibling package to a filter does not bypass a narrow rootDir gate. If shared-code changes must redeploy a service, use a root and filter combination that admits them, such as the repository-root Docker example above. Include relevant lockfiles and shared configuration as well as application source.

If a webhook carries no changed-path information, Bex currently allows the path-filter checks to pass; filters are not a strict guarantee against deployment.

Use the deployment-filter explorer with your own render.yaml, pushed branch, head-commit message and changed paths. Include the added, removed and modified paths from every commit in the push. Its service traces show branch and auto-deploy gates before the independent root-directory and build-filter gates. Different files can satisfy those two path gates. An ignored file cannot satisfy the build filter even when it also matches an include. A literal rootDir: . is a path prefix in this push gate, so omit rootDir when you intend no root-directory restriction.

The explorer evaluates declared settings with creation defaults from the source revision shown in its report. That revision is not evidence of the platform version currently deployed. Existing Blueprint updates can preserve omitted branch, root and auto-deploy settings, and a deploy request can override the repository or branch. Confirm the service's current settings and webhook delivery before interpreting a result as a live deployment decision. Repository selection, billing, capacity and build success are outside this local check.

Filters control push-triggered deployments, not access to files or authorization. An explicit manual deploy is a separate operation. Do not use filters to enforce a release approval policy; Bex does not implement checksPass CI gating.

Verify and troubleshoot​

Test an application change, an ignored documentation change, and a shared-library change in a non-production branch/workspace. Check which service deploys and which commit it builds.

For a missing file, inspect the root, context, Dockerfile path, lockfile placement, and ignore rules. For a missing deployment, inspect branch and auto-deploy settings, webhook delivery, root matching, and filters. For an unexpected service restart, also check Blueprint sync and configuration changes. Build logs distinguish a source-path failure from an application startup failure.

Was this page helpful?

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex