Build configuration

When you push to your release branch, VelvetPress clones the repo, runs your build, and packages the result into the ZIP your customers install. Not everything in the repo belongs in that ZIP — VCS metadata, node_modules, the uncompiled sources you build from, and local dev tooling all add weight (and sometimes secrets) without helping the customer's site. This page covers how VelvetPress decides what to exclude.

What gets excluded

Three layers decide whether a file ships, applied as a union — a file is dropped if any layer excludes it:

  1. Built-in defaults. Out of the box VelvetPress drops the development files no WordPress ZIP should carry: VCS metadata (.git, .github), dependency trees (node_modules), uncompiled sources (src), lockfiles, and editor / linter config. The exact patterns are pre-seeded into the dashboard's Exclude Patterns field (see below), so the dashboard always shows the live, authoritative list.

  2. Exclude Patterns (dashboard). The Exclude Patterns field under Configure Product holds the list above and lets you replace it with your own — one minimatch glob per line, where a directory needs a /** suffix (tests/**, not tests/). Leaving it empty ships everything; clearing it back to the defaults is one click on Reset to defaults. Use this for per-product rules you manage from the dashboard.

  3. .distignore (in the repo). A repo-local .distignore file adds further exclusions that live with your code. See below.

The precedence is defaults → dashboard Exclude Patterns → .distignore. Because the layers union, a .distignore rule can only add exclusions on top of whatever the first two layers already drop — it cannot re-include a file that the defaults or your Exclude Patterns already removed.

.distignore

.distignore is the WP-CLI wp dist-archive community standard: a file you commit to your repo's root that names the dev infrastructure which should never ship — docker-compose.yml, scripts/, .DS_Store, CI config, and the like. Because it's version-controlled alongside the code, the exclude list travels with the repo and is reviewed like any other change, rather than living only in the dashboard.

Syntax

.distignore uses gitignore syntax, so the rules read exactly like a .gitignore:

# Comments and blank lines are ignored

docker-compose.yml      # a single file
scripts/                # a directory and everything under it
*.log                   # a glob
!keep.log               # re-include a file an earlier pattern dropped

Negation (!pattern), trailing-slash directories, and nested ** all behave as they do in git. .distignore itself is always excluded from the artifact — it's a build instruction, not something your customers need.

When it takes effect

.distignore is read at deploy time, from the commit being packaged. It takes effect on your next push — there's no history rewrite and no need to backfill old releases. Add or edit the file, push to your release branch, and the new exclude list applies to that build.

A malformed .distignore (for example a binary file) is skipped with a warning in the build log rather than failing the build, so a stray file can never block a release.

First use case

The velvetpress.co theme ships a .distignore so its docker-compose.yml, scripts/, and editor cruft stay out of the production WordPress install on every push.

Debugging a missing file

When a file you expected is absent from a build, check the build log: the worker logs the files .distignore removed from the artifact (e.g. ".distignore excluded files from the artifact"). If your file isn't in that list, it was dropped by the built-in defaults or your dashboard Exclude Patterns instead — work back up the three layers above.