Dockerignore tester: is this path in the build context?

Paste your .dockerignore and the paths you are unsure about. This answers with Docker's own rules — which are not Git's: every pattern is anchored at the context root, and an exception can reach inside an excluded directory.

Runs entirely in your browser. Your data is never uploaded.

Docker reads one ignore file, at the root of the build context. There are no nested .dockerignore files.

Write each path relative to the build context root — the directory you pass to docker build. A trailing slash makes no difference: Docker has no directory-only patterns.

Examples

    How Docker decides, in order

    The rules are shorter than Git's, and that is exactly why a .gitignore habit gives the wrong answer here.

    1. Every pattern is anchored at the context root. node_modules means the one directory at the top of the context, not “any directory with that name”. Use **/node_modules when you mean every one of them.
    2. Each path is judged on its own, and the last rule with a say wins. A rule has a say when it matches the path itself or any directory above it.
    3. A ! line puts a path back — even one inside an excluded directory. Git refuses to do this; Docker does it happily, which is what makes * followed by !dist a working allowlist.
    4. Leading and trailing slashes are dropped before matching, and . and .. segments are resolved, so /src/ and src are the same rule.
    5. A pattern Docker cannot parse stops the build. It is not skipped: docker build exits with syntax error in pattern before anything is sent.

    The same file, read as .dockerignore and as .gitignore

    Both columns are produced by running this page's engine and our gitignore tester's engine over the same text, and both are checked by a test — so this table cannot drift from either behaviour.

    File Path Docker Git Why they differ
    node_modules packages/ui/node_modules/react/index.js In the context — no rule matched Ignored — line 1 A pattern with no slash is anchored at the context root for Docker and matches at any depth for Git.
    docs !docs/keep.md docs/keep.md In the context — line 2 Ignored — line 1 Git stops at the first excluded parent directory and never looks inside, so line 2 is not even read. Docker has no such rule.
    * !src src/main.ts In the context — line 2 Ignored — line 1 The common “allowlist” idiom works as written for Docker. For Git you need /* and !/src, because * there matches at every level.
    build/ build Excluded — line 1 Not ignored — no rule matched Here build is a file, not a directory. Git honours the trailing slash as “directories only”; Docker drops it, so the file goes too.

    Pattern syntax

    Every row is checked by a test against the same engine the tool above uses, so this table cannot drift from the behaviour either.

    Pattern Meaning Excludes Leaves in the context
    node_modules A bare name is anchored at the context root — this one directory and everything under it. Nothing deeper is touched, which is the difference from .gitignore that costs people the most time. node_modules, node_modules/react/index.js packages/ui/node_modules/react/index.js, my_node_modules
    **/node_modules ** stands for any number of directories, including none. This is the pattern that reaches every node_modules in a monorepo. node_modules/react/index.js, packages/ui/node_modules/react/index.js my_node_modules
    *.log * matches any run of characters except a slash, so this is only the logs sitting at the context root. app.log logs/app.log
    **/*.log The same pattern at any depth, root included. app.log, logs/a/b.log app.log.txt
    */temp* A slash in the middle counts directories exactly: this is one level down, no more and no less. somedir/temporary.txt temp.txt, a/b/temp.txt
    temp? ? is exactly one character, and never a slash. tempa, tempb temp, sub/tempa
    /src A leading slash is simply dropped — every pattern is anchored at the context root already, so /src and src are the same rule. src, src/main.ts a/src/main.ts
    build/ A trailing slash is dropped too. Docker has no directory-only patterns, so this also excludes a plain file called build — where .gitignore would leave it alone. build, build/out.o buildfile
    [abc].log A bracket expression matches one character from the set; ranges like [a-c] work, and [^a] negates. a.log, c.log d.log, ab.log, sub/a.log
    foo/../bar Patterns are cleaned before use: . and .. segments and repeated slashes are resolved, so this is just bar. bar foo/bar

    Results that surprise people

    Each of these is the verdict this tool gives, verified by a test. Paste any of them above to see the deciding line.

    .dockerignore Path Result Why
    node_modules packages/ui/node_modules/react/index.js Sent to the builder — no rule matched This is the answer to “why is node_modules still in my build context?” in a monorepo. Write **/node_modules to reach every one of them.
    docs !docs/keep.md docs/keep.md Sent to the builder — line 2: docs/keep.md Docker evaluates each path on its own and takes the last rule with a say, so line 2 wins. The identical .gitignore leaves the file ignored, because Git never descends into an ignored directory.
    * !dist !package.json dist/index.js Sent to the builder — line 2: dist !dist puts back the directory, and that is enough — everything under it comes with it. This idiom does not work in a .gitignore.
    *.md !README*.md README-secret.md README-secret.md Excluded — line 3: README-secret.md Last match wins, so a later plain rule overrides an earlier !. Order is the whole grammar here.
    *.log logs/app.log Sent to the builder — no rule matched Write **/*.log if you meant every log file below the context root.
    a[.txt a.txt No answer — the build stops at line 1 Docker validates every pattern before it starts, and refuses the build with “syntax error in pattern” rather than skipping the line. Here the character class opened by [ is never closed.

    Three things the patterns do not decide

    There is no docker check-ignore

    Git has git check-ignore -v, which names the deciding line. Docker has no equivalent, which is why this page exists. The usual workarounds all need a running daemon and none of them names the rule: build a throwaway image that copies the whole context and list it, or read the “transferring context” size from docker build --progress=plain. The rsync --exclude-from trick that circulates is worse than it looks — rsync's filter dialect is not Docker's, and it disagrees on precisely the anchoring cases above.

    About this tool

    The matching is a TypeScript port of github.com/moby/patternmatcher v0.6.1 and its ignorefile parser — the packages the Docker CLI and BuildKit use to filter a build context, so their answer is Docker's answer. It is pinned by 1,315 recorded path answers over 417 .dockerignore files, generated by running those upstream packages directly, and the port is checked against them on every build.

    Two limits worth stating: Go compares characters, JavaScript compares UTF-16 code units, so a character class you write yourself ([…]) counts a non-BMP character such as an emoji as two where Docker counts one; and Go's \s is narrower than JavaScript's, which can only matter inside a pattern containing a literal \s. Ordinary paths are unaffected. Everything runs in your browser — the files and paths you paste are never uploaded.

    Includes a derivative work of moby/patternmatcher, Copyright 2012–2017 Docker, Inc., licensed under the Apache License, Version 2.0. The upstream licence and NOTICE are kept in third-party/moby-patternmatcher/ in this project's repository.