How to create minimal docker image (for Python)?

Hello, I’d like to create minimal a docker image for a Python project. I created a new project using poetry2nix template (nix flake init --template github:nix-community/poetry2nix) and added a new target for building docker image. I also added a Flask dependency. However, the resulting image is rather big, it has 163 MB. It contains whole closure of the app. But it seems like there are many packages that are needed only during the build-time but not during the run-time. After running nix-store --query --tree ./result/, I found out that python depends on bash, which depends on glibc which depends on xgcc. I’d expect there to be only a static binary of python, or python binary with some shared objects.

Is there a way to include only packages that are necessary during the runtime? I guess, I’d like something similar to multistage docker images, where in the first stage you have all build dependencies and the second stage you start from SCRATCH and include only what is needed during the runtime.

Here is the example project: Matúš Ferech / nix-python-big-docker · GitLab
Here is how I tried to build the docker image:

  description = "Application packaged using poetry2nix";

  inputs = {
    flake-utils.url = "github:numtide/flake-utils";
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    poetry2nix = {
      url = "github:nix-community/poetry2nix";
      inputs.nixpkgs.follows = "nixpkgs";

  outputs = {
    flake-utils.lib.eachDefaultSystem (system: let
      # see for more functions and examples.
      pkgs = nixpkgs.legacyPackages.${system};
      inherit (poetry2nix.lib.mkPoetry2Nix {inherit pkgs;}) mkPoetryApplication;
    in {
      packages = rec {
        app = mkPoetryApplication {
          projectDir = self;
        default = self.packages.${system}.app;
        docker = pkgs.dockerTools.buildImage {
          name = "app";
          tag = "0.1.0";
          config = {
            Cmd = ["${app}/bin/app"];

      devShells.default = pkgs.mkShell {
        inputsFrom = [self.packages.${system}.app];
        packages = [pkgs.poetry];

For example with added Flask dependency image created by Nix has 199MB. I build the same image with docker and distroless and it has 133MB. Here is the Dockerfile I used:

# Build a virtualenv using the appropriate Debian release
# * Install python3-venv for the built-in Python3 venv module (not installed by default)
# * Install gcc libpython3-dev to compile C Python modules
# * In the virtualenv: Update pip setuputils and wheel to support building new packages
FROM debian:11-slim AS build
RUN apt-get update && \
    apt-get install --no-install-suggests --no-install-recommends --yes python3-venv gcc libpython3-dev && \
    python3 -m venv /venv && \
    /venv/bin/pip install --upgrade pip setuptools wheel poetry

# Build the virtualenv as a separate step: Only re-execute this step when requirements.txt changes
FROM build AS build-venv
COPY pyproject.toml poetry.lock /
RUN /venv/bin/poetry export --with-credentials --format requirements.txt --output /requirements.txt
RUN /venv/bin/pip install --disable-pip-version-check -r /requirements.txt

# Copy the virtualenv into a distroless image
COPY --from=build-venv /venv /venv
COPY . /app
ENTRYPOINT ["/venv/bin/python3", "app"]