Templating

This document outlines the available Jinja2 macros in the Posit Bakery templating system for creating Docker images with package installations.

Macros must be explicitly imported in every file in which they are used.

References: - Source Code - Jinja2 Template Designer Documentation

Available Variables

The following variables are available by default for use in an image’s Jinja2 templates. Additional values passed using --value to bakery create or specified in the values field of an image version will also be available.

Currently, Containerfile templates render as a unique file for each variant and OS. Using variant and OS based Jinja2 conditionals outside of Containerfile templates is not currently supported and will lead to unexpected results or errors.

  • Image: A dictionary containing information about the current image, version, variant, and OS.
    • Image.Name: The name field of the image, e.g. package-manager, workbench, connect.
    • Image.DisplayName: The display name field of the image, e.g. Package Manager, Workbench, Connect.
    • Image.Version: The current version being rendered, e.g. 2025.08.0.
    • Image.Variant: The current variant being rendered, e.g. Standard, Minimal.
    • Image.OS: A dictionary containing information about the current OS being rendered.
      • Image.OS.Name: The name field of the OS, e.g. ubuntu, debian, rhel.
      • Image.OS.Family: The generalized family of the OS, e.g. debian (includes Ubuntu), rhel.
      • Image.OS.Version: The version field of the OS, e.g. 22.04, 20.04, 9, 8, 8.6, 7.
      • Image.OS.Codename: The codename of the OS version if defined, e.g. jammy, noble, bookworm.
    • Image.DownloadURL: The URL to download a development version artifact for installation. Only defined for development version builds.
    • Image.IsDevelopmentVersion: A boolean indicating whether the current version is a development version.
  • Path: A dictionary containing paths relative to the root build context.
    • Path.Base: The base path for the build context. Usually the parent directory of bakery.yaml.
    • Path.Image: The path to the current image’s directory.
    • Path.Version: The path to the current image version’s directory.
  • Dependencies: A dictionary containing retrieved dependency versions to be used in the image version rendering.
    • Dependencies.python: A list of Python versions retrieved based on the version’s dependencies field (preferred if the version exists) or the image’s dependencyConstraints field in the bakery.yaml configuration. Undefined if no Python version constraints are specified.
    • Dependencies.R: A list of R versions retrieved based on the version’s dependencies field (preferred if the version exists) or the image’s dependencyConstraints field in the bakery.yaml configuration. Undefined if no R version constraints are specified.
    • Dependencies.quarto: A list of Quarto versions retrieved based on the version’s dependencies field (preferred if the version exists) or the image’s dependencyConstraints field in the bakery.yaml configuration. Undefined if no Quarto version constraints are specified.

Custom Jinja2 Filters

In addition to the built-in Jinja2 filters, the following custom filters are available in all templates:

  • tagSafe: Replaces disallowed characters in a tag with a hyphen (-).
  • stripMetadata: Removes trailing metadata suffixes that start with - or + (e.g. 1.2.3-rc1 becomes 1.2.3).
  • condense: Removes spaces, periods, and hyphens.
  • regexReplace <find> <replace>: Replaces occurrences of the find regex with replace.
  • quote: Wraps a string in double quotes.
  • split: Splits a string by a separator (e.g. { "a,b,c" | split(",") }).

Templating Macros

APT Package Management

Importing

To use the APT macros, import the apt module in your Jinja2 template:

{%- import "apt.j2" as apt -%}

Apt Setup

Performs initial setup, including update, upgrade, installation of essential packages, installation of Posit Cloudsmith repositories, purging removed packages, and cleaning the apt cache.

Essential packages include ca-certificates, curl, gnupg, and tar.

{{ apt.setup() }}

To wrap setup() in a Docker RUN statement, use:

{{ apt.run_setup() }}

Setup Posit Cloudsmith Apt Repositories

Renders commands to set up Posit Cloudsmith apt repositories. Requires curl to be installed prior to execution.

NOTE: This macro is included in apt.setup() or apt.run_setup(), so it does not need to be called separately unless apt.setup() is not used.

{{ apt.setup_posit_cloudsmith() }}

To wrap setup_posit_cloudsmith() in a Docker RUN statement, use:

{{ apt.run_setup_posit_cloudsmith() }}

Apt Clean Commands

Renders commands to clean and remove the apt cache to ensure minimal image layers. Clean commands should be run at the end of any RUN statement that modifies packages, but it is implicitly included in most other macros that modify packages.

{{ apt.clean_command() }}

Apt Update and Upgrade

Renders commands to update the apt cache, upgrade packages, run dist-upgrade, and remove unneeded packages. Pass False to the clean argument to skip cleaning the cache if you want to append additional commands. Clean is True by default.

NOTE: This macro is called by apt.setup() and apt.run_setup(), so it does not need to be called separately unless apt.setup() is not used.

{{ apt.update_upgrade(clean = True) }}

To wrap update_upgrade() in a Docker RUN statement, use:

{{ apt.run_update_upgrade() }}

Install Packages

Renders commands to install all packages from given list and files.

If update is True, the apt cache will be updated before installation. If clean is True, the apt cache will be cleaned after installation. Both are True by default.

One of packages or files must be provided. packages can be a list, a comma-separated string, or a single string. files can be a list, a comma-separated string, or single string. Positional arguments are accepted for packages and files, but keyword arguments are recommended for clarity.

COPY {{ Path.Version }}/deps/packages.txt /tmp/packages.txt  # Example copy command
{{ apt.install(packages=["git", "curl"], files=["/tmp/packages.txt"], update=True, clean=True) }}

To wrap install() in a Docker RUN statement, use:

{{ apt.run_install(packages="git,curl", files="/tmp/packages.txt") }}

DNF Package Management

Importing

To use the DNF macros, import the dnf module in your Jinja2 template:

{%- import "dnf.j2" as dnf -%}

DNF Setup

Performs initial setup, including upgrade, installation of essential packages, installation of Posit Cloudsmith repositories, removal of unneeded packages, and cleaning the dnf cache.

Essential packages include ca-certificates, curl, gnupg, and tar.

{{ dnf.setup() }}

To wrap setup() in a Docker RUN statement, use:

{{ dnf.run_setup() }}

Setup Posit Cloudsmith DNF Repositories

Renders commands to set up Posit Cloudsmith DNF repositories. Requires curl to be installed prior to execution.

NOTE: This macro is included in dnf.setup() or dnf.run_setup(), so it does not need to be called separately unless dnf.setup() is not used.

{{ dnf.setup_posit_cloudsmith() }}

To wrap setup_posit_cloudsmith() in a Docker RUN statement, use:

{{ dnf.run_setup_posit_cloudsmith() }}

DNF Clean Command

Renders commands to clean the dnf package cache. Clean commands should be run at the end of any RUN statement that modifies packages, but it is implicitly included in most other macros that modify packages.

{{ dnf.clean_command() }}

DNF Update and Upgrade

Renders commands to upgrade packages, remove unneeded packages, and clean the cache. Pass False to the clean argument to skip cleaning the cache if you want to append additional commands. Clean is True by default.

NOTE: This macro is called by dnf.setup() and dnf.run_setup(), so it does not need to be called separately unless dnf.setup() is not used.

{{ dnf.update_upgrade(clean = True) }}

To wrap update_upgrade() in a Docker RUN statement, use:

{{ dnf.run_update_upgrade() }}

Install Packages

Renders commands to install all packages from given list and files.

If clean is True, the dnf cache will be cleaned after installation. Clean is True by default.

One of packages or files must be provided. packages can be a list, a comma-separated string, or a single string. files can be a list, a comma-separated string, or single string. Positional arguments are accepted for packages and files, but keyword arguments are recommended for clarity.

{{ dnf.install(packages=["git", "curl"], files=["/tmp/packages.txt"], clean=True) }}

To wrap install() in a Docker RUN statement, use:

{{ dnf.run_install(packages="git,curl", files="/tmp/packages.txt") }}

Python Installation and Package Management

Importing

To use the Python macros, import the python module in your Jinja2 template:

{%- import "python.j2" as python -%}

Build and Install Python using UV

Adds a build stage to build Python versions using uv. This should only be called prior to the final stage of the build, typically the first call in a Containerfile.

{{ python.build_stage(["3.11", "3.12"]) }}

Usually, this should be called with Dependencies.python to dynamically specify versions based on the image’s dependencyConstraints field:

{{ python.build_stage(Dependencies.python) }}

The macro accepts an optional prerun parameter to specify commands to run before the Python build. This is useful for declaring build args or executing prerequisite installations:

# Example prerun to declare a build argument
{{ python.build_stage(Dependencies.python, prerun=python.declare_build_arg()) }}

# Example prerun to install additional build dependencies
{{ python.build_stage(Dependencies.python, prerun="RUN apt install -y make gcc") }}

To copy the Python installations from the build stage to the current stage, use:

{{ python.copy_from_build_stage() }}

Declare Build Argument

Declares a Docker ARG for a Python version. Useful as a prerun parameter to build_stage() or in Containerfiles that need a Python version as a build argument.

The name parameter defaults to PYTHON_VERSION. The default parameter sets a default value for the argument.

{{ python.declare_build_arg() }}

To declare with a custom name and default:

{{ python.declare_build_arg(name="PY_VER", default="3.12") }}

To reference the build argument in a Containerfile:

{{ python.build_arg() }}

Get Version Directory

Returns the expected directory for a Python version built with uv.

{{ python.get_version_directory("3.12.11") }}

Install Packages

Installs packages to a Python version from a list of packages or requirements files.

If clean is True, requirements files will be removed after they are installed. Clean is True by default.

If break_system_packages is True, the --break-system-packages flag will be passed to pip, allowing installation of packages that may conflict with system-managed packages. This is True by default for compatibility with externally managed Python environments.

One of packages or requirements_files must be provided. packages can be a list, a comma-separated string, or a single string. requirements_files can be a list, a comma-separated string, or single string. Positional arguments are accepted for packages and requirements_files, but keyword arguments are recommended for clarity.

COPY {{ Path.Version }}/deps/requirements.txt /tmp/requirements.txt  # Example copy command
{{ python.install_packages("3.12.11", packages="numpy,pandas", requirements_files="/tmp/requirements.txt", clean=True) }}

To install the same packages to multiple versions and wrap the commands with a RUN statement, use:

{{ python.run_install_packages(["3.13.7", "3.12.11"], packages=["numpy", "pandas"], requirements_file="/tmp/requirements.txt") }}

Or, to install to all Python versions defined in Dependencies.python:

{{ python.run_install_packages(Dependencies.python, packages=["numpy", "pandas"], requirements_file="/tmp/requirements.txt") }}

To disable the --break-system-packages flag:

{{ python.run_install_packages(Dependencies.python, packages=["numpy"], break_system_packages=False) }}
Note

The install_packages macro uses requirements_files (plural), while run_install_packages uses requirements_file (singular). Both accept a list, a comma-separated string, or a single string.

R Installation and Package Management

Importing

To use the R macros, import the r module in your Jinja2 template:

{%- import "r.j2" as r -%}

Install R

Renders a command to download and runs the Posit r-install script for a given version of R. Requires curl to be installed prior to execution.

{{ r.install("4.4.3") }}

To install multiple R versions and wrap them in RUN statements, use:

{{ r.run_install(["4.4.3", "4.5.0"]) }}

Usually, this should be called with Dependencies.R to dynamically specify versions based on the image’s dependencyConstraints field:

{{ r.run_install(Dependencies.R) }}

Get Version Directory

Returns the expected installation directory for an R version.

{{ r.get_version_directory("4.4.3") }}

Install Packages

Render commands to install R packages from lists and files to the given R version.

One of packages or package_list_files must be provided. packages can be a list, a comma-separated string, or a single string. package_list_files can be a list, a comma-separated string, or single string. Positional arguments are accepted for packages and package_list_files, but keyword arguments are recommended for clarity.

The macro takes a _os argument to specify the target OS. The OS information is used to find a suitable p3m.dev repository URL for binary packages. If no OS is provided or does not appear supported, source packages will be used by default. It is suggested to always pass _os=Image.OS to reduce build times and image size.

If clean=True and package_list_files is provided, the files will be removed after installation. Clean is True by default.

COPY {{ Path.Version }}/deps/packages.txt /tmp/packages.txt  # Example copy command
{{ r.install_packages("4.4.3", packages="ggplot2,dplyr", package_list_files="/tmp/packages.txt", _os=Image.OS, clean=True) }}

To install the same packages to multiple R versions and wrap the commands with a RUN statement, use:

{{ r.run_install_packages(["4.4.3", "4.5.0"], packages="ggplot2,dplyr", _os=Image.OS) }}

Or, to install to all R versions defined in Dependencies.R:

{{ r.run_install_packages(Dependencies.R, packages="ggplot2,dplyr", _os=Image.OS) }}

Quarto Installation and Management

Importing

To use the Quarto macros, import the quarto module in your Jinja2 template:

{%- import "quarto.j2" as quarto -%}

Install Quarto

Returns the command to download and install a Quarto version. Requires curl to be installed prior to execution.

The macro takes an optional with_tinytex argument to include the command to install TinyTeX using the installed Quarto binary. Default is False.

If with_tinytex is True, tinytex_update_path can be set to True to append the --update-path option to the install command. This will add TinyTeX binaries to the system PATH.

{{ quarto.install("1.8.24", with_tinytex=True, tinytex_update_path=True) }}

To install multiple Quarto versions and wrap them in RUN statements, use:

{{ quarto.run_install(["1.8.24", "1.9.0"], with_tinytex=True) }}

Usually, this should be called with Dependencies.quarto to dynamically specify versions based on the image’s dependencyConstraints field:

{{ quarto.run_install(Dependencies.quarto, with_tinytex=True) }}

Get Version Directory

Returns the expected directory for an installed Quarto version.

{{ quarto.get_version_directory("1.8.24") }}

Install TinyTeX

Returns the command to install TinyTeX using a given Quarto binary.

This command takes a full path to the Quarto binary, which can be constructed using quarto.get_version_directory(). Workbench manages its own installation of Quarto and thus must specify its own full path to the Quarto binary.

If update_path is True, the command will have --update-path appended to add TinyTeX binaries to the system PATH. Default is False.

{{ quarto.install_tinytex_command(quarto.get_version_directory("1.8.24"), update_path=True) }}

Goss Testing

Importing

To use the Goss macros, import the goss module in your Jinja2 template:

{%- import "goss.j2" as goss -%}

Build Argument Environment Variable

Returns a reference to a build argument passed as an environment variable to Goss tests. This is useful for accessing build-time values in Goss test templates.

{{ goss.build_arg_env_var("PYTHON_VERSION") }}

This outputs { .Env.BUILD_ARG_PYTHON_VERSION } which Goss will substitute with the value of the BUILD_ARG_PYTHON_VERSION environment variable at test runtime.

wait-for-it

Importing

To use the wait-for-it macros, import the wait-for-it module in your Jinja2 template:

{%- import "wait-for-it.j2" as waitforit -%}

Install wait-for-it

Returns the command to download and install the wait-for-it script. Requires curl to be installed prior to execution.

{{ waitforit.install() }}

To wrap install() in a Docker RUN statement, use:

{{ waitforit.run_install() }}

See Also

Back to top