SyncFolder — Desktop User Guide
Using Filter Patterns for Folder and File Filters
SyncFolder lets you control exactly which folders and files are processed during a synchronisation task by writing filter patterns in the filter fields of each task location. The pattern syntax is based on glob, with a few differences specific to SyncFolder. This chapter explains how filters work, the supported syntax, and practical examples to get you started quickly.
How Filters Work in SyncFolder
Every task location has a root folder. When SyncFolder runs a task it walks the entire directory tree starting from that root. Filters are evaluated at each level of the walk to decide whether a folder or file should be included in — or excluded from — the synchronisation.
Four separate filter lists are available per location — one exclusion and one inclusion list for folders, and the same for files:
| Filter list | Default behaviour | Effect when a pattern matches |
|---|---|---|
| Folder exclusion filters | No folders excluded | The matched folder and its entire subtree are skipped. Exclusion always takes priority over the folder inclusion list. |
| Folder inclusion filters | All folders included (when list is empty) | When one or more patterns are defined, only folders that match at least one pattern are descended into — provided they are not also matched by the folder exclusion list. |
| File exclusion filters | No files excluded | Matched files are skipped. Exclusion always takes priority over the file inclusion list. |
| File inclusion filters | All files included (when list is empty) | When one or more patterns are defined, only files that match at least one pattern are processed — provided they are not also matched by the file exclusion list. |
Folder filter evaluation order
For every folder encountered during the tree walk, SyncFolder applies the following logic:
| Inclusion list | Exclusion list | Matches inclusion | Matches exclusion | Result |
|---|---|---|---|---|
| Empty | Empty | — | — | ✅ Descended into |
| Empty | Has patterns | — | No | ✅ Descended into |
| Empty | Has patterns | — | Yes | ❌ Skipped |
| Has patterns | Empty | Yes | — | ✅ Descended into |
| Has patterns | Empty | No | — | ❌ Skipped |
| Has patterns | Has patterns | Yes | No | ✅ Descended into |
| Has patterns | Has patterns | No | No | ❌ Skipped (no inclusion match) |
| Has patterns | Has patterns | Yes | Yes | ❌ Skipped (exclusion wins) |
| Has patterns | Has patterns | No | Yes | ❌ Skipped |
File filter evaluation order
For every file encountered, the same logic applies:
| Inclusion list | Exclusion list | Matches inclusion | Matches exclusion | Result |
|---|---|---|---|---|
| Empty | Empty | — | — | ✅ Included |
| Empty | Has patterns | — | No | ✅ Included |
| Empty | Has patterns | — | Yes | ❌ Excluded |
| Has patterns | Empty | Yes | — | ✅ Included |
| Has patterns | Empty | No | — | ❌ Excluded |
| Has patterns | Has patterns | Yes | No | ✅ Included |
| Has patterns | Has patterns | No | No | ❌ Excluded (no inclusion match) |
| Has patterns | Has patterns | Yes | Yes | ❌ Excluded (exclusion wins) |
| Has patterns | Has patterns | No | Yes | ❌ Excluded |
Pattern Scope: Any-Depth vs. Root-Relative
A pattern can match an item anywhere in the tree, or be anchored to the root of the location. The leading characters of the pattern determine the scope.
| Pattern form | Scope | Example |
|---|---|---|
Bare name (no leading /) |
Any-depth — matches the item at any level of the tree. Internally converted to **/pattern. |
obj — excludes every folder named obj, wherever it appears. Equivalent to **/obj. |
Leading / |
Root-relative — matches only directly under the root of the location | /build — excludes a folder named build only when it sits directly under the root. |
Path with separators, no leading / |
Any-depth sub-path — matches the path segment at any level | services/logs — excludes a logs folder inside any services folder, at any depth. |
Path with separators, leading / |
Root-relative sub-path — anchored to the root | /services/logs — excludes a logs folder inside a services folder at the root only. |
.gitignore. Developers migrating patterns from a .gitignore file can use bare names directly. Use a leading / to anchor a pattern to the root.
The Root Reference Point
All folder patterns are evaluated relative to a reference point — the folder against which bare names and paths are anchored. The reference point depends on whether you have configured a subfolder selection for the task location.
Scenario 1: No subfolder selection — root folder only
When only the root folder is configured (e.g. C:\Projects\Project2026), all patterns are evaluated relative to that root. A bare name matches at any depth; a leading / restricts the match to direct children of the root.
| Pattern | What the user expects | Result |
|---|---|---|
| * | All direct subfolders of Project2026 | ✅ Correct |
| ** | All subfolders at all levels | ✅ Correct |
| /* | Direct subfolders only (explicit root anchor) | ✅ Correct — / anchors to root |
| /** | All subfolders (explicit root anchor) | ✅ Same as ** |
| bin | Any folder named bin at any depth | ✅ Correct — bare name = any-depth |
| /bin | Only the bin folder directly under root | ✅ Correct — leading / = root only |
The leading / explicitly anchors the pattern to the root of the location. Without it, the pattern matches at any depth in the tree.
Scenario 2: Subfolder selection — reference point shifts
When you select one or more subfolders as the starting point (e.g. Package1 and Package2 inside Project2026), the reference point shifts to each selected subfolder individually. Patterns are evaluated relative to the content inside each selected folder, not relative to the root.
For example, the bare pattern app1 will match Project2026\Package1\app1 and Project2026\Package2\app1 — at any depth under each selected subfolder.
| Pattern | Result | Intuitive? |
|---|---|---|
| * | All direct subfolders of Package1 and Package2 | ✅ |
| ** | All subfolders of Package1 and Package2 at any depth | ✅ |
| /* | Same as * — anchored to the reference point (each selected subfolder) | ✅ |
| /** | Same as ** | ✅ |
| app1 | Any folder named app1 inside Package1 or Package2, at any depth | ✅ |
| /app1 | Only a folder named app1 directly inside Package1 or Package2 | ✅ |
Package1 and Package2 in your patterns. A pattern that excludes app1 will exclude it under both packages. If you need to filter differently per package, configure each package as a separate task location.
Pattern Syntax Reference
SyncFolder supports the following pattern tokens. Note that brace expansion ({a,b}) and character sets ([a-z]) are not supported.
| Token | Meaning | Example pattern | Matches |
|---|---|---|---|
| Bare name | Matches the named item at any depth in the tree. Internally converted to **/name. |
bin |
bin, src/bin, a/b/bin |
Leading / |
Anchors the pattern to the root of the location (or selected subfolder) | /bin |
Only bin directly under the root |
* |
Any sequence of characters, not including a path separator | *.tmp |
report.tmp, cache.tmp |
** |
Any sequence of characters, including path separators (zero or more path segments) | **/logs |
logs, src/logs, a/b/c/logs |
? |
Exactly one character (not a path separator) | file?.txt |
file1.txt, fileA.txt |
/ regardless of the operating system. Backslashes are treated as escape characters and may produce unexpected results.
Folder Exclusion Filter Examples
Excluding well-known build and tooling folders
# Any-depth — bare name matches everywhere
bin
obj
# Root-relative — IDE and test output at root only
/.vs
/TestResults
# Any-depth — bare name matches everywhere
node_modules
# Root-relative — build output at root only
/.next
/dist
/.cache
/.turbo
# Any-depth — bare name matches everywhere
__pycache__
# Root-relative
/.venv
/venv
/.mypy_cache
/.pytest_cache
# Root-relative — these belong at root
/.git
/.svn
/.hg
/.idea
/.vscode
Excluding folders by name pattern
# Exclude every folder whose name starts with a dot (any depth — bare pattern)
.*
# Exclude all folders named "temp" or "tmp" at any depth (two separate patterns)
temp
tmp
# Exclude all numbered release folders directly under root
/release*
Excluding folders at a specific sub-path
# Exclude "logs" inside any "services" folder, at any depth
services/logs
# Exclude "logs" only inside "services" directly at root
/services/logs
# Exclude a "snapshots" folder inside any direct child of root
/*/snapshots
Folder Inclusion Filter Examples
The folder inclusion list lets you restrict the tree walk to only the folders you care about. When the list is empty, all folders that pass the exclusion list are descended into. When one or more patterns are defined, SyncFolder only descends into matching folders — all others are skipped, even if no exclusion pattern covers them.
Processing only specific named folders
# Only descend into folders named "src" — at any depth (bare name)
src
# Only descend into "src" directly under root
/src
# Only process the "app" and "lib" folders (two separate patterns, any depth)
app
lib
Including folders by pattern
# Only process folders whose name starts with "Package" (any depth)
Package*
# Only process numbered sprint folders directly under root
/sprint*
# Include all direct subfolders of root (no restriction at first level)
/*
Combining folder inclusion with folder exclusion
— Folder inclusion list —
# Only descend into Package folders (any depth)
Package*
— Folder exclusion list —
# But skip any bin or obj inside them (any depth)
bin
obj
File Exclusion and Inclusion Filter Examples
File exclusion and inclusion patterns use the same glob syntax. They are configured in two separate lists in the task location settings. Remember that exclusion always takes priority — a file matching both lists will be excluded.
Exclusion list: excluding files by extension
# Skip compiled and intermediate output files (any depth — bare pattern)
*.obj
*.pdb
*.ilk
*.suo
*.user
# Skip common log and temporary files
*.log
*.tmp
*.bak
*~
Exclusion list: excluding files by name pattern
# Skip all hidden files (names starting with a dot, any depth)
.*
# Skip desktop.ini and Thumbs.db anywhere in the tree (bare name = any depth)
desktop.ini
Thumbs.db
# Skip numbered backup copies such as "report(1).docx"
*(?).*
Using the inclusion list to restrict which files are processed
When the inclusion list is empty, all files that pass the exclusion list are processed. Add patterns to the inclusion list when you want to process only specific file types, regardless of what else is present in the folder tree.
— Inclusion list —
# Process only C# source and project files (bare name = any depth)
*.cs
*.csproj
*.sln
*.xaml
*.designer.cs).
Combining exclusion and inclusion lists
— Exclusion list —
*.designer.cs # Skip auto-generated designer files
*.g.cs # Skip source-generated files
— Inclusion list —
*.cs # Process all C# files (any depth) …
*.xaml # … and all XAML files
Excluding multiple file extensions separately
Since brace expansion is not supported, list each extension as a separate pattern:
# Exclude common image formats — one pattern per extension
*.bmp
*.gif
*.ico
*.jpg
*.jpeg
*.png
*.tif
*.tiff
*.webp
Best Practices
- Prefer folder exclusions over file exclusions for large subtrees. Excluding a folder stops all traversal into it immediately, which is far more efficient than letting SyncFolder walk thousands of files only to exclude them one by one.
- Use bare names for tooling folders that appear throughout the tree. A bare name like
binautomatically matches at any depth — you do not need to write**/bin. This keeps filter lists short and readable. - Use a leading
/to restrict a pattern to the root. When a folder or file is meaningful only at the root of the location (e.g./.vs,/publish), prefix it with/to avoid accidentally matching a same-named item deeper in the tree. - Migrating from .gitignore is straightforward. SyncFolder's bare-name behaviour matches .gitignore — a bare name matches at any depth. Patterns from a
.gitignorefile can generally be reused as-is, with the exception of brace expansion and character sets which are not supported. - Brace expansion and character sets are not supported. Instead of
*.{jpg,png}or[Tt]emp, write each variation as a separate pattern:*.jpgand*.png, ortempandTemp. - Use the folder inclusion list to whitelist, not just to restrict. When a root contains many unrelated subfolders, it is cleaner to list the folders you want (inclusion) than to list all the folders you don't want (exclusion). Use whichever approach results in fewer patterns.
- Use separate task locations when you need per-subfolder filter control. Because subfolder selection shifts the reference point to each selected folder, you cannot target one selected subfolder differently from another within the same filter list. Split them into separate task locations instead.
- Use the inclusion list to whitelist file types, not to override exclusions. Exclusion always wins. Use the inclusion list to define which file types are in scope, then use the exclusion list to trim specific files within those types.
- Avoid overly broad patterns like
**/*in exclusion lists. Such patterns exclude everything and are almost never what you intend. Be as specific as the situation requires. - Test new filters on a small folder copy first. Run a preview sync against a subset of your data before applying a new pattern to a large production location.
- Comment your filter lists. Lines beginning with
#are treated as comments. Use them to explain why a pattern exists, especially for non-obvious exclusions. - Keep a shared filter template for each project type. Maintaining one canonical filter set per technology stack (WinUI, .NET, Node, etc.) and reusing it across task locations reduces configuration drift and review overhead.
- Revisit filters after major toolchain upgrades. Build tools frequently change the names or locations of their output folders. After upgrading an SDK or package manager, verify that your existing exclusion patterns still cover the new output paths.
Last updated: 15 May 2026