Hierarchical .dropboxignore for Dropbox on Windows (NTFS ADS) and Linux (xattrs)
Project description
dbxignore
Hierarchical .dropboxignore files for Dropbox. Drop a .dropboxignore into any folder under your Dropbox root and matching paths get the Dropbox ignore marker set automatically — no more node_modules/ cluttering your sync. Windows (NTFS alternate data streams) and Linux (user.* xattrs) supported.
Upgrading from v0.2.x
The project was renamed from dropboxignore to dbxignore in v0.3.0
(the old name collides with an unrelated 2019 PyPI project). Upgrade is
a one-time manual step:
dropboxignore uninstall --purge # on v0.2.x — removes state, logs, service
pip install dbxignore # or: uv pip install dbxignore
dbxignore install # registers the new service under new names
Your .dropboxignore rule files carry over untouched — they're never
modified by install/uninstall.
Requirements
- Windows 10/11 (NTFS), or a modern Linux distro with a systemd user session
- Dropbox desktop client installed
- Python ≥ 3.11 with
uv. The pre-built.exe(Windows only) is an alternative on Windows.
Install (Windows, from source)
uv tool install git+https://github.com/kiloscheffer/dbxignore
dbxignore install
dbxignore install registers a Task Scheduler entry that launches the daemon (pythonw -m dbxignore daemon) at every user logon.
Install (Linux)
Requires a systemd user session (standard on Ubuntu, Fedora, Debian, Arch, and most modern distros; WSL2 requires systemd=true in /etc/wsl.conf).
uv tool install git+https://github.com/kiloscheffer/dbxignore
dbxignore install # writes systemd user unit, enables it
systemctl --user status dbxignore.service
dbxignore install writes ~/.config/systemd/user/dbxignore.service and runs systemctl --user enable --now so the daemon starts at login.
For non-stock Dropbox installs, export DBXIGNORE_ROOT before running dbxignore install — the install step will read the variable from your shell environment and write a corresponding Environment="DBXIGNORE_ROOT=..." line into the generated unit's [Service] block. Without this, a shell-exported value won't reach the daemon when systemd launches it. If your Dropbox location ever changes, re-run dbxignore install after updating the export.
To uninstall:
dbxignore uninstall # disables unit, removes the file
dbxignore uninstall --purge # clears markers, state files, logs, systemd drop-in
Notes:
- Dropbox on Linux marks ignored paths with the xattr
user.com.dropbox.ignored=1. Files on filesystems that don't supportuser.*xattrs (tmpfs withoutuser_xattr, vfat, some FUSE mounts) are skipped with aWARNINGin the daemon log — not a fatal error. - Several common operations strip xattrs silently:
cpwithout-a,mvacross filesystems, most archivers,vim's default save-via-rename. The watchdog plus hourly sweep re-apply markers automatically; no action needed. - Linux symlinks cannot carry
user.*xattrs (kernel restriction). A symlink matched by a rule logs oneWARNINGper sweep and is skipped. Its target is not affected.
Install (.exe)
- Download
dbxignore.exeanddbxignored.exefrom the latest Release. - Place both in a stable directory (e.g.
%LOCALAPPDATA%\dbxignore\bin\) and add it to yourPATH. - Run
dbxignore install.
Platform support
- Windows 10 / 11 — first-class (v0.1). Uses NTFS Alternate Data Streams.
- Linux — first-class (v0.2). Uses
user.com.dropbox.ignoredxattrs. Tested on Ubuntu 22.04 / 24.04. Requires a systemd user session. - macOS — planned for v0.3. Dropbox on macOS uses a different attribute mechanism (Apple File Provider) that requires runtime detection — not yet implemented.
.dropboxignore syntax
Full .gitignore syntax via pathspec. Matching is case-insensitive to accommodate NTFS. A file named .dropboxignore is never itself ignored — it needs to sync so your other machines see the same rules.
Example (put in a project root):
# everything javascripty
node_modules/
# Python
__pycache__/
.venv/
*.egg-info/
# Rust
target/
# build output
/dist/
/build/
# except this one specific artifact we want to share
!dist/release-notes.pdf
Commands
| Command | Purpose |
|---|---|
dbxignore install / uninstall |
Register / remove the daemon with the platform's user-scoped service manager (Task Scheduler on Windows, systemd user unit on Linux). uninstall --purge also clears every existing marker, removes local dbxignore state (state.json, daemon.log*, the state directory), and on Linux removes any systemd drop-in directory. Any stray marker on a .dropboxignore file itself is logged at WARNING before being cleared. |
dbxignore daemon |
Run the watcher + hourly sweep in the foreground. Usually invoked by Task Scheduler. |
dbxignore apply [PATH] |
One-shot reconcile of the whole Dropbox (or a subtree). |
dbxignore status |
Is the daemon running? Last sweep counts, last error. |
dbxignore list [PATH] |
Print every path currently bearing the ignore marker. |
dbxignore explain PATH |
Which .dropboxignore rule (if any) matches the path? |
Behaviour
- Source of truth.
.dropboxignorefiles declare what is ignored. Removing a rule unignores the matching paths on the next reconcile. A path marked ignored via Dropbox's right-click menu but not matching any rule will be unignored. - Hybrid trigger. The daemon reacts to filesystem events in real time and runs an hourly safety-net sweep. If the daemon is offline, an initial sweep at the next start catches any drift.
- Multi-root. Personal and Business Dropbox roots are discovered automatically from
%APPDATA%\Dropbox\info.json(Windows) or~/.dropbox/info.json(Linux).
Negations and Dropbox's ignore inheritance
Dropbox marks files and folders as ignored using xattrs. When a folder carries the ignore marker, Dropbox does not sync that folder or anything inside it — children inherit the ignored state regardless of whether they individually carry the marker. This matters for gitignore-style negation rules in your .dropboxignore.
If you write a negation whose target lives under a directory ignored by an earlier rule — the canonical case is build/ followed by !build/keep/ — the negation cannot take effect. Dropbox will ignore build/keep/ because build/ is ignored, no matter what xattr we put on the child. dbxignore detects this at the moment you save the .dropboxignore, logs a WARNING naming both rules, and drops the conflicted negation from the active rule set.
Negations that don't conflict with an ignored ancestor work normally. For example:
*.log
!important.log
Here nothing marks a parent directory as ignored (*.log matches files, not dirs), so the negation works — important.log gets synced, the other .log files don't.
Limitation. Detection uses static analysis on the rule's literal path prefix. Negations that begin with a glob (!**/keep/, !*/cache/) have no literal anchor to analyze and are accepted without conflict-check — if they land under an ignored ancestor at runtime, they silently fail to take effect. If you need guaranteed semantics, prefer negations with a literal prefix.
Configuration
Environment variables read at daemon startup:
| Variable | Default | Purpose |
|---|---|---|
DBXIGNORE_DEBOUNCE_RULES_MS |
100 |
Debounce window for .dropboxignore file events. |
DBXIGNORE_DEBOUNCE_DIRS_MS |
0 |
Debounce for directory-creation events (0 = react immediately, no coalescing). |
DBXIGNORE_DEBOUNCE_OTHER_MS |
500 |
Debounce for other file events. |
DBXIGNORE_LOG_LEVEL |
INFO |
Daemon log level. |
DBXIGNORE_ROOT |
(unset) | Escape hatch for non-stock Dropbox installs: overrides info.json discovery and treats the given absolute path as the sole Dropbox root. If the path doesn't exist, a WARNING is logged and no roots are returned (so dbxignore apply exits with "No Dropbox roots found"). |
Logs (rotated, 25 MB total):
- Windows —
%LOCALAPPDATA%\dbxignore\daemon.log. - Linux — two sinks, same records. The rotating file at
$XDG_STATE_HOME/dbxignore/daemon.log(fallback~/.local/state/dbxignore/daemon.log) is authoritative for offline debugging and bug-report bundling;journalctl --user -u dbxignore.servicesurfaces the same records via systemd-journald for live tailing and cross-service filtering.
State:
- Windows —
%LOCALAPPDATA%\dbxignore\state.json. - Linux —
$XDG_STATE_HOME/dbxignore/state.json(fallback~/.local/state/dbxignore/state.json).
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dbxignore-0.3.2.tar.gz.
File metadata
- Download URL: dbxignore-0.3.2.tar.gz
- Upload date:
- Size: 217.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
abcad02f1a5645523416ad711f1e031522150abf21adcceaf32675a88cae10b6
|
|
| MD5 |
2099398220b474d0cc6177e97d54d675
|
|
| BLAKE2b-256 |
4276f2aae039c93092396afe140f1cfc944984538aad9ba5c50315bb2efb41cf
|
Provenance
The following attestation bundles were made for dbxignore-0.3.2.tar.gz:
Publisher:
release.yml on kiloscheffer/dbxignore
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dbxignore-0.3.2.tar.gz -
Subject digest:
abcad02f1a5645523416ad711f1e031522150abf21adcceaf32675a88cae10b6 - Sigstore transparency entry: 1389261379
- Sigstore integration time:
-
Permalink:
kiloscheffer/dbxignore@da72f90808b96648979ce2414303727c0bdf33ea -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/kiloscheffer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@da72f90808b96648979ce2414303727c0bdf33ea -
Trigger Event:
push
-
Statement type:
File details
Details for the file dbxignore-0.3.2-py3-none-any.whl.
File metadata
- Download URL: dbxignore-0.3.2-py3-none-any.whl
- Upload date:
- Size: 38.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ac5ea38bcb94c9c3ee4233febaf97a0bc8b0332e2c4644c097e9acf0f935061
|
|
| MD5 |
09d6d56c1f2e3fb253ae9b82448bd818
|
|
| BLAKE2b-256 |
b4ff1ea0d01464af26045768e893ec62efc153dbe28f4afd68270e2d0229a1f1
|
Provenance
The following attestation bundles were made for dbxignore-0.3.2-py3-none-any.whl:
Publisher:
release.yml on kiloscheffer/dbxignore
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dbxignore-0.3.2-py3-none-any.whl -
Subject digest:
7ac5ea38bcb94c9c3ee4233febaf97a0bc8b0332e2c4644c097e9acf0f935061 - Sigstore transparency entry: 1389261403
- Sigstore integration time:
-
Permalink:
kiloscheffer/dbxignore@da72f90808b96648979ce2414303727c0bdf33ea -
Branch / Tag:
refs/tags/v0.3.2 - Owner: https://github.com/kiloscheffer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@da72f90808b96648979ce2414303727c0bdf33ea -
Trigger Event:
push
-
Statement type: