Plenty of repositories hold more than one project — a bot and its dashboard, a web app beside its shared library, three services in one place. When only one of them belongs on this server, you don't want the whole repo landing in /home/container. The Git page's sync paths and exclude paths solve exactly this. This guide is the deep dive.
| At a glance | |
|---|---|
| You need | a server with a repository linked on its Git page (see Deploy from Git) |
| Plan | any |
| Time | fifteen minutes |
The two path filters
On the Git settings you'll find two lists, each holding up to 20 paths:
| Filter | What it does | Applied |
|---|---|---|
| Sync paths | Limits the deploy to only these directories — everything else in the repo is skipped | First |
| Exclude paths | Keeps named paths from being copied at all | After the sync filter |
They work together and in that order: sync paths pick the folders that come in, then exclude paths subtract anything you still don't want from within them. Leave sync paths empty and the whole repo deploys (the default); add one and suddenly only that folder lands.
Paths are plain and relative to the repo root — letters, digits, dashes, dots, and slashes, like apps/bot or services/api. No wildcards or globs; you name real directories.
The catch that trips everyone up: the Main file
Here's the part people miss. Say your repo looks like this:
my-monorepo/
├── apps/
│ ├── bot/
│ │ ├── index.js
│ │ └── package.json
│ └── web/
└── packages/
You set sync paths to apps/bot, deploy, and… the server won't start. Why? Because sync paths keep the folder structure. apps/bot/index.js lands at /home/container/apps/bot/index.js, but the Node application looks for its entry file at the root — /home/container/index.js, which doesn't exist.
The fix is one setting: point the Main file variable (Settings page → Environment) at the real location, apps/bot/index.js. Python's the same idea with the App py file variable, PHP with its PHP File. Sync paths put your folder on the server; the application's entry-file variable tells the runtime where to find it inside that folder.
⚠️ Heads up: Node's Main file field holds at most 16 characters, so a deep path like
services/worker/index.jswon't fit. If your entry path is too long, sync that folder as the only one and restructure so the entry file lands nearer the root, or keep the subfolder shallow.
Worked example 1: a bot in a subfolder
Your repo has apps/bot (the Discord bot) and apps/web (an unrelated site). This server should run only the bot.
- Sync paths: add
apps/bot. Now a deploy copies only that folder. - Main file: set it to
apps/bot/index.js. - Deploy, then Start.
package.jsoninsideapps/bottriggers the automaticnpm install, and the bot boots.
Your apps/web folder never touches the server, so there's nothing to trip over and nothing wasted.
Worked example 2: a service plus a shared library
Now a trickier shape — your service imports a shared package that lives elsewhere in the repo:
repo/
├── services/api/ (this server runs this)
├── packages/shared/ (api imports from here)
└── services/worker/ (belongs on a different server)
The service needs services/api and packages/shared, but not services/worker:
- Sync paths: add both
services/apiandpackages/shared. Sync paths are a list — you can name several folders, and only those come in. - Exclude paths: you don't even need one here, because
services/workerwas never synced. Exclude paths earn their keep when a folder you did sync contains something you want to leave out — say you syncservices/apibut want to skipservices/api/fixtures. Addservices/api/fixturesto excludes and it's dropped after the sync. - Point the Main file at
services/api/index.jsand make sure your imports resolve to the syncedpackages/sharedpath.
Everything else about deploys still applies
Sync and exclude paths only decide which files come in. The rest of the Git model is unchanged:
- Copy, don't replace. A deploy overwrites files by name and never deletes server files that aren't in the source — so your server-side
.envand data survive, exactly as in a normal deploy. Exclude paths are a second layer of protection: name a path there and even a same-named repo file won't overwrite it. - Build steps run after the copy — see Build steps on deploy if your synced folder needs compiling.
- Auto-deploy works with path filters too; a push redeploys just the synced folders.
Troubleshooting
- Deploy succeeds but the server won't start — almost always the Main file. Your entry file is inside the synced subfolder; point the Main file (or App py file / PHP File) variable at its real path.
- Files from a folder I didn't want still showed up — that folder is in (or implied by) your sync paths, or sync paths are empty (which deploys everything). Tighten the sync list, or add the unwanted path to excludes.
- My entry path is longer than 16 characters (Node) — the Main file field won't hold it. Sync a shallower folder or restructure so the entry file sits nearer the root.
- A deploy failed on the path filter — paths are plain relative directories (letters, digits, dashes, dots, slashes); no wildcards. Re-check for a typo or a leading slash.