Skip to main content
Blog|
Knowledge base

How to leave files out of your app build with .hostneyignore

|
Nov 14, 2026|8 min read
KNOWLEDGE BASEHow to leave files out of yourapp build with .hostneyignoreHOSTNEY™hostney.comNovember 14, 2026

Short answer: add a file called .hostneyignore to the root of your repository and list the files and folders your app does not need to run, using the same patterns as .gitignore . When Hostney builds your app, it removes everything the file lists from its copy of your repository before the build starts. Those files are not installed, not built, not put in your app’s container and not uploaded with a static site. The build log shows what was removed. A .dockerignore is not read.

When you deploy an app from Git on Hostney, every build starts from a fresh copy of your repository at the commit you pushed. Everything you committed is in that copy: the code that runs, and also the test suites, documentation, design files, sample data and the screenshots in your README. Most of it never runs in production, and some of it should never be published. .hostneyignore is how you tell the build which is which.

What it changes#

A rule in .hostneyignore works as if the file had never been committed, for the build only. Your repository stays exactly as it is. Git, your other branches and your teammates’ clones are not touched.

What that means depends on the kind of app.

Apps that run in a container, such as Next.js, Nuxt, Express and other Node.js servers, and Python and Ruby apps. The container image is built from your project, and for most Node.js apps that means the whole project. A tests/ folder with its fixtures, a docs/ site or a folder of Photoshop files ends up in the image next to the code that serves your pages. The image gets bigger, and a bigger image takes longer to build, to store and to start. Hostney caps images at 2 GB, and a few large files nobody uses are a common way to reach that cap. The cost repeats with every build, including the ones you did not plan, like the rebuild every Node.js app needed for the October 2026 Node.js security release.

Static sites, such as Vite, Astro, Create React App or a static Next.js export. Only the build output is published, but these frameworks copy the public/ folder into that output unchanged. A draft page, a raw data export or an unoptimised video sitting in public/ gets a public address the moment you deploy. Listed in .hostneyignore , it is gone before the framework copies anything.

Monorepos. A repository that holds several apps, a docs site and shared packages builds each app from its own root directory, and each app can keep its own .hostneyignore in its folder. More on that below.

What it is not for#

.hostneyignore keeps a file out of your deploy. It does not take the file out of your repository. A password, an API key or a .env file committed to Git is still in the repository and in its history, where anyone with access to the repository can read it. Take secrets out of the repository and set them as environment variables in your app’s settings, where you can mark each one as a secret so its value is never shown again.

Write the file#

Create a file called .hostneyignore at the root of your repository. It uses the same syntax as .gitignore :

# Not needed to run the app
tests/
docs/
*.psd
/fixtures/large-sample.sql

# Everything in assets/raw except the logo
assets/raw/*
!assets/raw/logo.svg

The rules are Git’s:

  • # starts a comment, and blank lines are skipped.
  • A pattern with no / matches at any depth. *.psd leaves out every Photoshop file in the repository, and tests/ every folder called tests .
  • A / at the start or in the middle ties the pattern to the place it names. /fixtures/large-sample.sql is only that file, in the fixtures folder at the root.
  • A trailing / matches folders only.
  • * and ? match within one name, [abc] matches one of the listed characters, and ** matches across folders. docs/**/*.png is every PNG anywhere under docs .
  • \ escapes a special character, for a name that starts with # or ! .
  • ! brings back something an earlier rule left out.

If you have written an exclude list for rsync or passed a few --exclude patterns to tar, the idea is the same: a list of patterns for files to skip. The syntax is Git’s, so a pattern you know from .gitignore behaves the same way here.

Bringing a file back#

! works the way it does in Git, including its one trap: you cannot bring back a file whose folder is already left out. Once a rule removes a folder, the folder goes as a whole and nothing inside it is looked at again. So this does not keep the logo:

assets/raw/
!assets/raw/logo.svg

Leave out the folder’s contents instead of the folder itself, and the ! rule works:

assets/raw/*
!assets/raw/logo.svg

Rules are read from top to bottom and the last rule that matches decides, so put a ! rule after the rule it makes an exception to.

Where the file goes#

At the root of your repository, with patterns relative to the repository root.

If your app builds from a root directory, the usual setup in a monorepo, you can put a second .hostneyignore in that folder:

.hostneyignore              patterns relative to the repository root
apps/web/.hostneyignore     patterns relative to apps/web

Inside apps/web , the folder’s own file wins. When one of its rules matches a file, that rule decides, and the repository’s rules decide only for files it has no rule for. Each app in a repository can keep its own list that way, and an app can use ! to bring back something the repository’s file leaves out everywhere else. A typical case is a repository with the Next.js front end of a headless WordPress site in apps/web , the WordPress theme in another folder and the design files next to both.

The repository’s file applies to the whole copy of the repository, including the folders of other apps and shared packages. In an npm, pnpm or Yarn workspace, Hostney installs at the workspace root and builds in your app’s folder, so a rule that leaves out a shared package your app imports breaks the build.

A change to .hostneyignore applies from the next build. Builds you already have keep the files they were built with, so promoting an older build brings back what that build contained.

What the build log shows#

Every build that finds a .hostneyignore says what it did, before the install starts:

.hostneyignore: removed 5 file(s) and folder(s) before the build: assets/raw/hero.tiff, design/home.psd, docs, fixtures/large-sample.sql, tests.

That is the example file above at work: the tests and docs folders went whole, the Photoshop file and the SQL sample went on their own, and everything in assets/raw went except the logo. The line lists the first 20 names and counts the rest. With a root directory, it names both files. When no rule matched anything, the log says that too, so a typo in a pattern does not go unnoticed:

.hostneyignore: 6 rule(s), nothing in the repository matched - nothing removed.

If a rule removes a file the build reads at the top of your app, such as package.json , your lockfile, requirements.txt or Gemfile , a warning follows right after the removal line:

WARNING: .hostneyignore removed package-lock.json, which the build reads. If the build fails, remove that rule.

The build usually fails on the missing file a few lines later, and the warning tells you where to look.

The .git folder is never touched, and no rule can remove your app’s root directory or a folder above it. A rule that would do that stops the build, and the log names the folder it would have removed.

When the build stops instead#

Hostney applies the file exactly as written, or not at all. A static site’s files are public, so skipping a rule we could not apply would publish the very file you asked to keep out. If the file cannot be applied in full, nothing is removed, the build stops and the log says why:

  • The file is larger than 64 KB, is not a text file, or is a link or a folder.
  • A line is longer than 1,024 characters.
  • It has more than 1,000 rules. Combine them with wildcards.
  • Its wildcard patterns are too complex to match in reasonable time. Patterns with many * in a row are the usual cause.
  • A rule would remove your app’s root directory or a folder above it.
  • The repository has more than 500,000 files and folders, or going through it takes longer than a minute.

Fix the file, push, and the next build applies it. The build is not retried automatically, because a retry would read the same file.

Why .dockerignore is not read#

A .dockerignore is written for a Dockerfile, almost always one that copies the project into the image and then installs and builds inside it. That is why most of them leave out node_modules , .next , dist and build : that Dockerfile creates those itself.

Hostney builds your app first and then writes its own Dockerfile, which copies the result of the build into the image. Read against a typical .dockerignore , it would leave out the node_modules and build output your app needs to run. So a .dockerignore in your repository changes nothing on Hostney, and what you want left out goes in .hostneyignore .

.gitignore has a different job. Files it matches are never committed, so they never reach a build in the first place. .hostneyignore is for the files you do commit, because you or your team need them, that the app does not.

A starting point for a Node.js app#

# Tests and their data
tests/
__tests__/
*.test.js
*.spec.ts
coverage/

# Docs and design files
docs/
*.psd
*.fig
*.sketch

# Editor and CI settings the app never reads
.github/
.vscode/

Check two things before you use it. When Skip tests is off in your app’s Build settings, the build runs your test script, so leave the tests out only while it is on. And make sure nothing your build or start command reads is on the list: a config file in docs/ that your build imports, or a script in a folder you left out. The first build after you add the file shows in its log exactly what went, which is the quickest way to check the list does what you meant.

Related articles