Docker .dockerignore Pattern Tester

Check which files a .dockerignore actually excludes. Put the patterns above a line of three dashes and the paths below it.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Test. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

A star with no slash

Matches at the top level only, which is the opposite of .gitignore

node_modules
*.log
---
app.log
logs/app.log

Brace expansion

Matched literally, so the pattern excludes nothing at all

*.{log,tmp}
---
app.log
app.tmp

A re-inclusion under an excluded directory

Works here, unlike in .gitignore, because the last match wins

secrets/
!secrets/public.pem
---
secrets/private.key
secrets/public.pem

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Copying a .gitignore across unchanged

    A single star does not cross a slash in .dockerignore, so patterns that matched at any depth in git now match only at the top level, and files you expected to be excluded are uploaded.

    Instead:Prefix them with **/ where you meant any depth.

  2. Using brace expansion

    Docker matches the braces literally. The pattern excludes nothing and looks correct in every other context.

    Instead:Write one line per alternative.

  3. Putting a negation above the exclusion it undoes

    The last matching pattern wins, so a negation only does work when an exclusion above it matched the same path.

    Instead:Order it exclusion first, negation second.

This is Go's glob dialect, not your shell's

Docker matches with Go's filepath.Match plus ** and !. Two of its rules differ from what the same string means in a shell or in .gitignore, and both differences make a pattern match less than expected.

A single star never crosses a slash

So *.log matches app.log and not logs/app.log. In .gitignore the same pattern matches at any depth, which is why a file copied across from one to the other stops working. **/*.log is the form that matches everywhere.

Braces are not expanded

*.{log,tmp} is matched literally, so it excludes a file whose name genuinely contains braces, which is to say nothing at all. Your shell expands them and so do most JavaScript glob libraries, so the pattern looks correct everywhere except where it runs.

The last matching pattern decides

Docker evaluates every pattern against every path rather than skipping the contents of an excluded directory, which is what .gitignore does. So secrets/ followed by !secrets/public.pem does re-include the file, and the same two lines reversed do not.

A pattern is anchored at the context root

There is no leading-slash anchor because everything is already relative to the root, and a leading slash is stripped. A pattern with no slash in it matches only at the top level.

A directory pattern covers its contents

node_modules excludes node_modules and everything under it, without needing a trailing slash or a star. The trailing slash is stripped and changes nothing.

Where this can be wrong

It implements the same rules and is not the same code. Unusual character classes and escaping are where a difference would show. When an answer matters, build with --progress=plain and read what was actually transferred.