The Docker image auditor that actually tells you what to do. Scan. Understand. Shrink.
279
███████╗██╗ ██╗███╗ ███╗██╗███████╗██╗ ██╗
██╔════╝██║ ██║████╗ ████║██║██╔════╝╚██╗ ██╔╝
███████╗██║ ██║██╔████╔██║██║█████╗ ╚████╔╝
╚════██║██║ ██║██║╚██╔╝██║██║██╔══╝ ╚██╔╝
███████║███████╗██║██║ ╚═╝ ██║██║██║ ██║
╚══════╝╚══════╝╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝
Scan. Understand. Shrink.
slimifyinspects any Docker image, explains exactly where the bloat is, and hands you a rewritten Dockerfile + tuned.dockerignore— ready to run.
| Tool | What it does | What's missing |
|---|---|---|
untracked | Generates .dockerignore from npm deps | Node/npm only. No image analysis. No layer insight. |
docker-repack | Reorders/squashes layers post-build | Doesn't remove actual bloat. No file-level visibility. |
dive | Visual layer explorer (TUI) | Read-only. No ecosystem detection. No fix output. |
docker-slim | Strips images by tracing syscalls at runtime | Complex setup. Requires running the container. Can break apps. |
slimify does all of it in a single binary — without running your container, without Node lock-in, and without guesswork. It reads the image, finds the bloat, and tells you exactly how to fix it.
.env, id_rsa, *.pem, *.key and similar files are baked into layersUSER nonroot, correct package manager (pnpm/bun/yarn/npm), Gradle vs Maven detection.dockerignore generator — tuned to your actual dependency graph, not generic patternsaudit--exit-code gate, JSON output, quiet mode, --remote comparelinux/amd64 + linux/arm64 manifests on both GHCR and Docker Hubbrew install NotHarshhaa/tap/slimify
go install github.com/NotHarshhaa/slimify@latest
curl -sSfL https://raw.githubusercontent.com/NotHarshhaa/slimify/main/install.sh | sh
Pre-built binaries for Linux (amd64, arm64), macOS (arm64), and Windows are available on the Releases page.
Images are published to both GitHub Container Registry and Docker Hub with multi-arch (amd64 + arm64) manifests:
# GitHub Container Registry
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
ghcr.io/notharshhaa/slimify audit myapp:latest
# Docker Hub
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
harshhaareddy/slimify audit myapp:latest
# Audit any image — no config needed
slimify audit myapp:latest
# Get a full fix: rewritten Dockerfile + .dockerignore
slimify fix myapp:latest --dockerfile ./Dockerfile
# Audit a remote image without pulling first
slimify audit node:20-alpine --remote
slimify audit <image>Inspects a local or remote Docker image and produces a full bloat report.
$ slimify audit myapp:latest
slimify audit — myapp:latest
─────────────────────────────────────────────────────
Image size: 847 MB
Layers: 5
Potential savings: 312 MB (36%)
Ecosystem detected: Node.js(npm), Python(pip)
⚠ SECRETS DETECTED IN IMAGE LAYERS:
.env
These files should NEVER be baked into an image.
Add them to .dockerignore and rotate any exposed credentials.
Layer breakdown:
┌───┬──────────────────────────────────────┬──────────┬───────┬──────────┐
│ # │ Instruction │ Size │ Files │ Delta │
├───┼──────────────────────────────────────┼──────────┼───────┼──────────┤
│ 0 │ FROM node:20 │ 342 MB │ 4821 │ baseline │
│ 1 │ RUN apt-get install -y build-essenti │ 61 MB │ 312 │ +61 MB │
│ 2 │ COPY . . │ 218 MB │ 1843 │ +218 MB │
│ 3 │ RUN npm install │ 187 MB │ 24891 │ +187 MB │
│ 4 │ RUN npm run build │ 39 MB │ 521 │ +39 MB │
└───┴──────────────────────────────────────┴──────────┴───────┴──────────┘
Top offenders in COPY . . :
node_modules/ 182 MB
.git/ 28 MB
coverage/ 4.2 MB
*.map files 2.1 MB
Duplicate files across layers:
package-lock.json copied in layer 2 and layer 3 — consolidate
Recommendations:
[1] Switch to multi-stage build (Node.js) → save ~187 MB
[2] Use node:20-alpine as base → save ~95 MB
[3] Generate .dockerignore (run slimify fix) → save ~34 MB from COPY context
[4] Merge RUN apt-get + cleanup in one layer → save ~18 MB
Run `slimify fix myapp:latest --dockerfile ./Dockerfile` to apply all fixes.
Flags:
| Flag | Default | Description |
|---|---|---|
--remote | false | Audit a remote image from a registry without pulling |
--json | false | Output report as JSON (for CI/CD pipelines) |
--quiet | false | Only print the one-line savings summary |
--top N | 10 | Show top N largest files per layer |
--threshold MB | 1.0 | Only flag files larger than N MB |
--no-secrets | false | Skip scanning for secret files in layers |
--exit-code | false | Exit with code 1 if potential savings exceed threshold (CI gate) |
slimify fix <image>Generates a .dockerignore, an optimized multi-stage Dockerfile, and a slimify.yaml config.
slimify fix myapp:latest --dockerfile ./Dockerfile --out ./slimify-out/
slimify fix — myapp:latest
─────────────────────────────────────────────────────
✓ Generated .dockerignore (removes 34 MB from build context)
✓ Rewritten Dockerfile (multi-stage, alpine base)
✓ Estimated new image size: 198 MB (was 847 MB — 76% smaller)
Output written to ./slimify-out/
├── Dockerfile.slimified
├── .dockerignore
└── slimify.yaml
Flags:
| Flag | Default | Description |
|---|---|---|
--dockerfile PATH | — | Path to your existing Dockerfile (required for rewrite) |
--out DIR | . | Output directory for generated files |
--write | false | Write files in-place, overwriting existing ones |
--no-rewrite | false | Only generate .dockerignore, skip Dockerfile rewrite |
--dry-run | false | Print the generated output to stdout, don't write files |
--platform PLATFORM | — | Target platform injected into the FROM line (e.g. linux/amd64) |
slimify compare <image-a> <image-b>Diff two image versions side by side — useful for validating that a rebuild actually got smaller.
slimify compare myapp:v1.0 myapp:v2.0
# Compare remote images without pulling
slimify compare myapp:v1.0 myapp:v2.0 --remote
slimify compare
─────────────────────────────────────────────────────
Image A: myapp:v1.0 847 MiB
Image B: myapp:v2.0 198 MiB
▼ Reduction: 649 MiB (76.7% smaller)
Layers A → B: 12 → 5
New layers in B: 3
Removed layers in B: 7
Shared base layers: 2
Flags:
| Flag | Description |
|---|---|
--remote | Compare images from a remote registry without pulling |
--json | Output as JSON |
slimify ignoreStandalone ignore file generator — run it in any project directory to generate a .dockerignore without auditing an image first.
# Auto-detect ecosystem and generate
slimify ignore
# Write directly to file
slimify ignore > .dockerignore
# Update existing file, preserving custom rules
slimify ignore --write .dockerignore
# Force a specific ecosystem
slimify ignore --ecosystem go,node,php
# Scan a subdirectory (useful in monorepos)
slimify ignore --dir ./services/api
The ignore command detects your ecosystem from lock files and project structure (scans up to 4 directory levels deep):
| Detected file | Ecosystem |
|---|---|
package.json, package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb, deno.lock | Node.js |
go.mod, go.sum | Go |
requirements.txt, Pipfile, pyproject.toml, uv.lock | Python |
Cargo.toml, Cargo.lock | Rust |
pom.xml, build.gradle, build.gradle.kts | Java |
Gemfile, Gemfile.lock | Ruby |
composer.json, composer.lock | PHP |
mix.exs, mix.lock | Elixir |
*.csproj, *.fsproj, global.json, nuget.config | .NET |
Multiple ecosystems in the same project are supported.
Flags:
| Flag | Description |
|---|---|
--write PATH | Write directly to a file path |
--ecosystem LIST | Force specific ecosystems (comma-separated: go,node,python,rust,java,ruby,php,elixir,dotnet) |
--dir PATH | Directory to scan instead of . (useful for monorepos) |
Customize slimify behavior via slimify.yaml in your project root (or --config flag):
# slimify.yaml
ignore:
whitelist:
- bin/ # don't ignore this even if detected as bloat
- config/prod/
blacklist:
- node_modules/.cache/puppeteer # always ignore, even if not auto-detected
audit:
threshold_mb: 2 # flag files larger than 2 MB
top_files_per_layer: 20
fix:
base_image: node:20-alpine # override auto-selected base
multi_stage: true # always rewrite as multi-stage
output_dir: ./docker/
You can also use any cosmiconfig-compatible format: .slimifyrc, .slimifyrc.json, .slimifyrc.yaml, or slimify.config.js.
- name: Audit Docker image
uses: NotHarshhaa/slimify-action@v1
with:
image: myapp:${{ github.sha }}
fail-if-savings-above: 100 # fail PR if >100 MB of bloat detected
- name: Comment savings report on PR
uses: NotHarshhaa/slimify-action@v1
with:
image: myapp:${{ github.sha }}
comment-on-pr: true
# Native exit-code gate — no jq needed
slimify audit myapp:latest --exit-code --threshold 100
# Or parse JSON output manually
slimify audit myapp:latest --json | jq -e '.savings_mb < 100'
# Also check for secrets in CI
slimify audit myapp:latest --json | jq -e '.secret_files | length == 0'
slimify reads your Docker image as a sequence of OCI-compatible layers — no Docker daemon or docker run required for the audit step. For each layer:
.git, docs, type definitions, etc.)--squash)The fix command feeds the audit output into a Dockerfile parser, identifies stage boundaries, and rewrites using:
node_modules / build cachenpm ci, yarn --frozen-lockfile, pnpm install --frozen-lockfile, bun install--no-cache flags on package manager installsRUN instructions to eliminate dead layer spacedistroless base images for Go, Rust, and Java; alpine/slim for everything elseUSER nonroot / USER node for security best-practices in the runtime stageCOPY --chown=node:node for Node.js non-root file ownershipEverything runs locally. slimify never uploads your image or Dockerfile anywhere.
slimify | untracked | docker-repack | dive | docker-slim | |
|---|---|---|---|---|---|
| Layer-level analysis | ✅ | ❌ | ✅ | ✅ | ✅ |
| File-level breakdown | ✅ | ❌ | ❌ | ✅ | ❌ |
| Multi-ecosystem support | ✅ (9 ecosystems) | ❌ (Node only) | N/A | N/A | N/A |
.dockerignore generation | ✅ | ✅ | ❌ | ❌ | ❌ |
| Dockerfile rewriter | ✅ | ❌ | ❌ | ❌ | ❌ |
| Secrets-in-layers detection | ✅ | ❌ | ❌ | ❌ | ❌ |
| Savings estimate upfront | ✅ | ❌ | ❌ | ❌ | ❌ |
| No container runtime needed | ✅ | ✅ | ❌ | ❌ | ❌ |
| CI-friendly JSON + exit-code | ✅ | ❌ | ❌ | ❌ | ✅ |
| Multi-arch Docker image | ✅ | ❌ | ❌ | ❌ | ❌ |
| Single binary | ✅ | ❌ (npm) | ❌ (Rust) | ✅ | ✅ |
slimify audit --remote — remote registry support without local pullslimify fix --base distroless — distroless base image rewrite supportslimify audit --exit-code — native CI gate flag.dockerignore suggestions in the editorslimify watch — re-audit on every docker build in a dev loopPRs are welcome! See CONTRIBUTING.md for local setup and guidelines.
git clone https://github.com/NotHarshhaa/slimify
cd slimify
go mod tidy
go run . audit --help
.dockerignore generatorslimify © NotHarshhaa, released under the MIT License.
Content type
Image
Digest
sha256:b28b55a8b…
Size
8.2 MB
Last updated
3 months ago
docker pull harshhaareddy/slimify