You can deploy multiple distinct sites, each with its own Netlify configuration, from a single Git repository.
Let’s say you have a monorepo structure like this:
/
├── apps/
│ ├── site-a/
│ │ ├── index.html
│ │ ├── netlify.toml <-- Site A's config
│ │ └── package.json
│ └── site-b/
│ ├── index.html
│ ├── netlify.toml <-- Site B's config
│ └── package.json
├── packages/
│ └── shared-utils/
└── package.json
When you connect this repository to Netlify, you’ll notice an option to "Monorepo detected." Netlify, by default, tries to be helpful and identify your monorepo structure. You’ll see a prompt like this:
"Monorepo detected. Select the directory containing your site:"
Instead of picking the root directory, you’ll need to configure Netlify to recognize each of your sub-sites as separate deployable units.
The key is the netlify.toml file. You can have multiple netlify.toml files within your monorepo, one for each distinct site you want to deploy. Each netlify.toml will define the build settings and deploy context for its corresponding site.
Here’s how you’d set up apps/site-a/netlify.toml:
[build]
command = "npm run build:site-a"
publish = "apps/site-a/dist"
environment = { NODE_VERSION = "18.12.0" }
[functions]
node_bundler = "esbuild"
And for apps/site-b/netlify.toml:
[build]
command = "npm run build:site-b"
publish = "apps/site-b/dist"
environment = { NODE_VERSION = "18.12.0" }
[functions]
node_bundler = "esbuild"
When you add your repository to Netlify, you’ll be prompted to select the base directory for your monorepo. You’ll typically set this to the root of your repository (/).
Then, for each site you want to deploy, you’ll add it as a separate "site" within your Netlify account. When setting up a new site in Netlify from an existing repository, you’ll navigate to the "Add new site" -> "Import an existing project" flow. After selecting your repository, Netlify will usually detect the netlify.toml file.
Crucially, when setting up the second site (and subsequent sites) from the same repository, you’ll need to tell Netlify which netlify.toml to use. This is done through the site’s build settings.
- Initial Site Setup: Connect your repo. Netlify detects
netlify.tomlin the root (or a sub-directory if you specify). Let’s say this deployssite-a. - Adding a Second Site: Go to "Add new site" -> "Import an existing project." Select the same repository.
- Build Settings: When prompted for the build command, publish directory, and build settings, Netlify might default to the root
netlify.toml. You’ll need to override this.- Build command: Enter the specific command for your second site (e.g.,
npm run build:site-b). - Publish directory: Enter the specific publish directory for your second site (e.g.,
apps/site-b/dist). - Show advanced: Click "Show advanced."
- Build image: Select your preferred build image.
- Base build command: Leave this blank if you’re using individual
netlify.tomlfiles. - Build tool: You can often leave this as "npm" or "yarn."
- Environment variables: Configure as needed.
- Under "Deploy settings," you’ll see "Monorepo configuration." This is where you tell Netlify to look for a specific
netlify.tomlif it’s not in the root. However, the more common and robust way is to have distinctnetlify.tomlfiles in each app’s directory and ensure Netlify is pointed to the correct publish and build command for that specific site.
- Build command: Enter the specific command for your second site (e.g.,
The most common and recommended way to manage this is to have each sub-site have its own netlify.toml file located within its own directory. When you add a new site in Netlify, you point it to the repository root as the base directory, and then you manually configure the build command and publish directory for that specific Netlify site. Netlify will then use these settings to build and deploy only that sub-site.
For example, if you’ve already set up site-a from your monorepo, and now you want to add site-b:
- In Netlify, click "Add new site" -> "Import an existing project."
- Select your Git provider and your monorepo.
- Netlify will likely show a base directory of
/. - For "Build command," enter
npm run build:site-b(or your specific build script). - For "Publish directory," enter
apps/site-b/dist(or your specific publish folder). - Click "Deploy site."
Netlify will now associate this specific Netlify site with the apps/site-b directory and its build artifacts. You’ll have two separate Netlify sites, both pointing to the same Git repository, but configured to build and deploy different sub-directories.
The actual mechanism is that Netlify associates a single Netlify site with a specific Git repository and a set of build commands/publish directories. When you add a "new site" in Netlify, you’re creating a new association. You’re not telling Netlify to manage multiple sites from a single netlify.toml in the root. Instead, you’re creating distinct Netlify site configurations, each pointed at the same repository but with different build instructions that target different sub-project directories.
The key insight is that Netlify’s "monorepo detection" is a convenience for the first site. For subsequent sites from the same repo, you’re manually defining their build context, effectively overriding defaults and pointing Netlify’s build process to the correct sub-directory for that specific Netlify site.
If you have a shared package.json at the root that manages dependencies for all your apps (e.g., using npm workspaces or lerna), your npm run build:site-a command would typically be defined in that root package.json and would internally orchestrate the build for apps/site-a.
You can also leverage Netlify’s Deploy Contexts and environment variables to manage different configurations for different branches or deploy previews for each of your sub-sites, all within the same monorepo. For instance, you might have main branch deployments for site-a and develop branch deployments for site-b, all originating from the same repository.
The most surprising thing here is that Netlify doesn’t have a single "monorepo configuration" file that defines multiple sites. Instead, you create multiple Netlify site entries, each configured with its own build command and publish directory, all pointing to the same Git repository. Netlify’s "monorepo detection" is primarily a helper for the initial setup, guiding you to specify the base directory of your monorepo.
To see this in action, imagine you have two simple React apps, site-a and site-b, in your monorepo.
apps/site-a/package.json:
{
"name": "site-a",
"version": "1.0.0",
"scripts": {
"build": "echo 'Building Site A'"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
apps/site-a/netlify.toml:
[build]
command = "npm run build"
publish = "apps/site-a/build"
apps/site-b/package.json:
{
"name": "site-b",
"version": "1.0.0",
"scripts": {
"build": "echo 'Building Site B'"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
apps/site-b/netlify.toml:
[build]
command = "npm run build"
publish = "apps/site-b/build"
When you add your repository to Netlify for the first time, you’ll set the base directory to /. Netlify might pick up apps/site-a/netlify.toml if it’s the most prominent or if you select it during setup. This creates your first Netlify site, let’s call it "My App A".
To deploy site-b, you create a second Netlify site. You again connect the same repository. This time, you’ll explicitly configure:
- Base directory:
/ - Build command:
npm run build(which will run the script inapps/site-b/package.json) - Publish directory:
apps/site-b/build
This second Netlify site, let’s call it "My App B", will now be independently deployed from the same Git repo.
The critical point is that Netlify doesn’t dynamically discover multiple netlify.toml files and offer to deploy them as separate sites from a single UI entry. You, the user, create multiple Netlify site entries, each configured with the specific build command and publish directory relevant to its sub-project within the monorepo. Netlify then treats each of these entries as an independent deployment target for that repository.
The next challenge you’ll face is managing complex dependency hoisting and build caching across multiple sites within the same monorepo.