DCM Projects files and templates

A DCM project requires a manifest file and one or more SQL object definition files. These files are typically stored and managed in a Git repository or your local workspace.

  • The manifest file

    • Specifies which object definition files to include.

    • Defines configurations for different environments with template variables.

  • The object definition files

    • Define a group of Snowflake objects that you want to manage together in the DCM project.

The high-level workflow to create DCM project files is:

  1. Create a DCM project folder to store your definition files

  2. Create a manifest file

  3. Create object definition files

Create a DCM project folder to store your definition files

To create a new DCM project, create a folder to store your manifest file (manifest.yml) and SQL object definition files.

snow init <project_name> --template DCM_PROJECT

The snow init command with the DCM_PROJECT template creates example definition files in your project directory. You can open and edit these files to define your DCM project.

DCM Projects follow the standardized folder structure:

  • DCM Projects object definition files must be placed under sources/definitions/.

  • The optional global macro files can be placed under sources/macros/.

  • File naming and nesting inside these project directories are flexible.

  • Saved output artifacts from DCM commands are always written to out/.

  • If you have additional scripts or project files that you want to use for DCM commands, you can add them under sources (for example, dbt project files).

  • If you have other custom scripts that you want to store within the project folder that should not be used by DCM Projects commands and not uploaded from local, add them in a folder outside of the sources folder.

  • The CLI commands only upload files within the sources folder.

Note

If you are using Git, add out/ to your .gitignore file to avoid pushing local output files to Git.

An example of a DCM project folder structure is:

my_dcm_project/
  ├── manifest.yml
  ├── sources/
  │   ├── definitions/
  │   │   ├── bronze.sql
  │   │   └── silver.sql
  │   ├── macros/
  │   │   └── global_macro.sql
  │   └── dbt/
  │       ├── my_dbt_project_1/
  │       └── my_dbt_project_2/
  ├── my_post_scripts/
  └── out/
      └── plan/

Create a manifest file

Each DCM project requires a manifest.yml file. It holds the essential configuration details of the project and allows the project folder to be identified as a DCM project.

You use the manifest file to control which DCM project objects and roles to use when deploying to different target environments and to manage sets of templating values.

The manifest file is a YAML file that contains the following properties:

manifest_version: 2
type: DCM_PROJECT
default_target:
targets:
templating:

Property

Required

Description

manifest_version

Required

Version of the manifest schema. The current version is 2.

type

Required

Type of the project. Set to DCM_PROJECT.

default_target

Optional

If you have more than one target, specify the default target. The Snowflake CLI and Workspaces use the default target if you do not specify a target using the --target flag.

targets

Required

The targets section maps each deployment target to a specific Snowflake account, DCM project object, owner role, and optionally a templating configuration. This mapping eliminates the need to pass fully qualified project names and configuration flags in every CLI command. See Project targets for more details.

templating

Optional

The templating section defines the templating configurations to use for the project. See Project templating configurations for more details.

Project targets

Each target in the manifest file contains the following properties:

targets:
  <target_name>:
    account_identifier:
    project_name:
    project_owner:
    templating_config:

Property

Description

account_identifier

The Snowflake account identifier for this target.

See Finding the region and locator for an account.

project_name

The fully qualified name of the DCM project object, for example, DCM_DEMO.PROJECTS.DCM_PROJECT_DEV.

Use the SHOW DCM PROJECTS SQL command to find it.

project_owner

The role with OWNERSHIP on this project object.

Use the SHOW DCM PROJECTS or DESCRIBE DCM PROJECT SQL command to find it.

templating_config (optional)

The name of the templating configuration defined in the templating section, to use for this target.

Map between project definitions and project objects

DCM Projects definition files aren’t strictly tied to a specific DCM project object. You can use the same set of definitions to deploy to multiple projects, either on different Snowflake accounts or by referencing different configuration profiles. For example, the same definition files on a repository branch can be deployed to both DEV and PROD accounts as shown in the following figure.

DCM definitions to DCM Project objects

Similarly, you can execute a DCM Projects object by referencing definition files from different paths. For example, your CI/CD automation can deploy definitions from your main branch, and you can manually run a PLAN from your local definition files against the same project to check how your definitions diverge from the latest deployment. You can also use this approach for ad-hoc manual deployments from other branches or local paths.

Project templating configurations

Following is the high-level structure of the templating configuration in the manifest file. You can set only defaults, or only configurations, or both.

templating:
  defaults:
    <variable_name>: <value>
  configurations:
    <configuration_name>:
      <variable_name>: <value>

Property

Description

defaults

The shared variable values, in key-value pairs, that apply across all configurations to avoid repetition.

configurations

The templating configurations to use for the project.

Individual configurations can override defaults with configuration-specific values. For details on how variables are resolved, see Configurations.

<configuration_name>

The name of the templating configuration.

Configuration names are case-insensitive.

<variable_name>

The name of the variable.

Variable names should follow Python variable naming rules.

All variables in project definitions must be declared either in defaults, the selected configuration, or at runtime.

If you want string variables to resolve empty, specify them as "".

<value>

The value of the variable.

Values can be strings, numbers, booleans, lists, or dictionaries.

Dictionaries can be defined in the manifest but cannot be overwritten at runtime.

Example: manifest.yml

This is an example of a DCM project manifest file (manifest.yml) that includes three configurations, DEV, STAGE, and PROD, with template variables and their default values:

manifest_version: 2

type: DCM_PROJECT

default_target: DCM_DEV

targets:
  DCM_DEV:
    account_identifier: MYORG-MYACCOUNT_DEV
    project_name: DCM_DEMO.PROJECTS.DCM_PROJECT_DEV
    project_owner: DCM_DEVELOPER
    templating_config: DEV

  DCM_STAGE:
    account_identifier: MYORG-MYACCOUNT_STAGE
    project_name: DCM_DEMO.PROJECTS.DCM_PROJECT_STG
    project_owner: DCM_STAGE_DEPLOYER
    templating_config: STAGE

  DCM_PROD:
    account_identifier: MYORG-MYACCOUNT_PROD
    project_name: DCM_DEMO.PROJECTS.DCM_PROJECT_PROD
    project_owner: DCM_PROD_DEPLOYER
    templating_config: PROD

templating:
  defaults:
    user: "GITHUB_ACTIONS_SERVICE_USER"
    wh_size: "SMALL"

  configurations:
    DEV:
      env_suffix: "_DEV"
      user: "INSERT_YOUR_USER"
      wh_size: "X-SMALL"
      teams:
        - name: "DEV_TEAM"
          write_access: TRUE

    STAGE:
      env_suffix: "_STG"
      teams:
        - name: "TEST_TEAM_A"
          write_access: TRUE
        - name: "TEST_TEAM_B"
          write_access: FALSE

    PROD:
      env_suffix: ""
      teams:
        - name: "Marketing"
          write_access: FALSE
        - name: "Finance"
          write_access: FALSE
          wh_size: "LARGE"
        - name: "HR"
          write_access: FALSE
        - name: "IT"
          write_access: TRUE

Create object definition files

A DCM project definition file is a template that resolves to valid SQL statements for managing Snowflake objects. Each DCM project requires at least one definition file.

You can organize your object definitions and grants across multiple files and folders. Snowflake recommends choosing a structure that represents the business logic of the project (for example, bronze, silver, and gold) rather than grouping by object type.

Definition files can only contain DEFINE, GRANT, or ATTACH statements. Other SQL commands are not supported.

To get started quickly with DCM Projects, you can convert your existing SQL deployment scripts by using the DEFINE keyword for your existing DDLs (for supported object types).

The DEFINE statement works like the CREATE OR ALTER <object> command, but with the following key differences:

  • The order and location of DEFINE statements don’t matter. Snowflake collects and sorts all statements from all definition files during project execution.

  • If you remove a DEFINE statement, Snowflake drops the corresponding object the next time you deploy the project.

  • Only a subset of Snowflake objects is supported. For details, see Supported object types in DCM Projects.

  • All objects must be defined with a fully qualified name in the format database.schema.object_name.

Definition files can contain various Jinja2 templating options and support advanced templating features, which allow you to do the following:

  • Customize file content at runtime using template variables.

  • Use Jinja2 syntax for logic such as loops and conditionals.

  • Make definition files reusable and adaptable for different scenarios.

Object definition templating

DCM Projects support the Jinja2 framework for templating SQL statements. You can declare variables and assign values using the Jinja2 syntax either from configuration profiles, in the EXECUTE DCM PROJECT command, or within Jinja. You can also construct loops through lists of values, case statements, reusable functions, and more. For more information, see the Jinja2 documentation.

Supported Jinja2 functionality includes:

  • String-replacements

  • Lists

  • Dictionaries and nested dictionaries

  • Conditions (IF statements)

  • Looping

  • Global and in-file macros

    • Macros defined in the sources/macros folder can be used across all definition files.

    • Macros defined in a file can be used within the file.

Unsupported Jinja2 functionality includes:

Note

The _snow identifier is reserved for future use, and cannot be used as a variable or macro name

Important

Do not use DCM Projects templating variables for object definitions that contain sensitive information or credentials. The rendered SQL definitions do not redact any values inserted by environment variables.

Similarly, do not enter any personal data, sensitive data, export-controlled data, or other regulated data as metadata, for example, file names, configuration and variable names, when using the Snowflake service. For more information, see Metadata fields in Snowflake.

The following is an example DCM project definition file that uses Jinja2 templating:

DEFINE WAREHOUSE DCM_PROJECT_WH_{{db}}
  WITH
    warehouse_size = '{{wh_size}}'
    auto_suspend = 300;

The following is an example of a DCM project manifest file (manifest.yml) that defines two configurations: DEV and PROD.

templating:
  configurations:
    DEV:
      db: "DEV_2"
      wh_size: "X-SMALL"
    PROD:
      db: "PROD"
      wh_size: "LARGE"

Rendering this warehouse definition with the DEV configuration (selected automatically through the target’s templating_config or at runtime) resolves to:

DEFINE WAREHOUSE DCM_PROJECT_WH_DEV_2
  WITH
    warehouse_size = "X-SMALL"
    auto_suspend = 300;

Macros

Macro files are any SQL files located in the macros folder and its sub-folders. They can only contain macros.

An example of a directory structure of a DCM project with macro files is:

My_dcm_project
 |_ manifest.yml
 |_ sources
    |_ definitions
       |_ my_definitions.sql
    |_ macros
       |_ my_global_macros.sql

Similar to functions in regular programming languages, macros help organize often-used pieces of code into reusable functions, thereby avoiding repetition and following the DRY (Don’t Repeat Yourself) principle. Macros in DCM Projects work in the same way as Jinja2 macros with the following exceptions:

  • Dedicated location for macro files in the macros folder.

  • Macros defined in macro files are automatically visible in other source files. The import Jinja tag is not permitted.

  • Duplicate definition of a macro with the same name is detected and rejected.

Automatic import of global macros

During the definition file rendering process, source files are scanned for potential macro calls. If a called macro is defined in a macro file, the implicit from […] import tag is added automatically, so no explicit import is needed.

Similar to Jinja2 macros, you can define a local macro by prefixing it with an underscore. A local macro can be used only in the file where it’s declared and isn’t visible to other files.

Template comments

In SQL commands, you can add -- before your code to comment out the line. Jinja still processes variables within the SQL code but leaves the SQL comments.

For example, the following Jinja code:

-- hello {{ project_owner_role }}

Renders as:

-- hello DCM_DEVELOPER

Commented out commands do not execute in SQL. You can use template comments to debug Jinja templating without affecting your SQL code.

To ignore Jinja code during rendering, add # inside opening and closing brackets as shown in the following example:

{# This Jinja comment will not appear in the rendered output. #}

Configurations

When using templates in your object definitions, you have the following options:

  • Assign values to variables at runtime.

  • Define different configuration profiles under templating: configurations: in the manifest.yml. Each target can reference a configuration through templating_config. See Project templating configurations for more details.

    If configuration profiles are defined and a target references one through templating_config, the configuration is automatically applied when using that target. For examples, see Plan a DCM project.

    The primary use case for configuration profiles in DCM Projects is to target different environments. Configuration profiles allow you to do the following:

    • Deploy the same code to multiple environments.

    • Test production code on a non-prod environment at a reduced scale.

    • Maintain multiple isolated environments on the same account.

    Not all templating configurations have to be referenced by a target profile. You can keep unused configurations to switch the templating config for your target from one to another.

  • Define shared default values under templating: defaults: to avoid repeating common variables across configurations. See Project templating configurations for more details.

  • Overwrite specific variables with one-time values at runtime using the --variable flag in CLI.

Variables are resolved with a three-tier hierarchy: global defaults < configuration variables < runtime execution variables.

Dictionaries

DCM Projects templating supports dictionaries as variable values, enabling structured configuration for complex multi-tenant or multi-resource deployments.

By grouping related configuration details into dictionaries, you get:

  • Granular control: Apply specific settings, such as warehouse sizes, retention policies, and grants, to individual resources without writing unique logic for every variation.

  • Cleaner code bases: Replace repetitive hard-coded scripts with dynamic loops that adapt based on the configuration.

  • Scalability: Onboard new teams or resources by adding entries to your configuration, rather than refactoring deployment pipelines.

Note

Dictionaries can be defined in the manifest but can’t be overwritten at runtime with the --variable flag or SQL USING CONFIGURATION (...) overrides. Only scalar values and lists can be overwritten at runtime.

Example use case for dictionaries: Multi-tenant environment provisioning

Consider a platform shared by multiple departments, such as Marketing, Finance, and HR, each with different compliance and compute requirements. With dictionaries, you define a single configuration that captures each team’s needs.

Manifest example:

templating:
  defaults:
    user: "GITHUB_ACTIONS_SERVICE_USER"
    wh_size: "X-SMALL"
  configurations:
    PROD:
      env_suffix: ""
      project_owner_role: "DCM_PROD_DEPLOYER"
      teams:
        - name: "Marketing"
          wh_size: "MEDIUM"
          data_retention_days: 14
          needs_sandbox_schema: true
        - name: "Finance"
          wh_size: "X-LARGE"
          data_retention_days: 90
          needs_sandbox_schema: false
        - name: "HR"
          data_retention_days: 30
          needs_sandbox_schema: false

Definition example:

Your SQL template loops through this dictionary. It automatically creates schemas, assigns the correct retention policy, and conditionally creates extra resources only for the teams that request them.

-- loop through team dictionaries
{% for team in teams %}
    {% set team_name = team.name | upper %}

    -- inject dictionary values directly into object properties
    define schema DCM_DEMO_1{{env_suffix}}.{{team_name}}
        comment = 'using JINJA dictionary values'
        data_retention_time_in_days = {{ team.data_retention_days }};

    -- pass the name to your macro
    {{ create_team_roles(team_name) }}

    define table DCM_DEMO_1{{env_suffix}}.{{team_name}}.PRODUCTS(
        ITEM_NAME varchar,
        ITEM_ID varchar,
        ITEM_CATEGORY array
    )
    data_metric_schedule = 'TRIGGER_ON_CHANGES';

    {% if team_name == 'HR' %}
        define table DCM_DEMO_1{{env_suffix}}.{{team_name}}.EMPLOYEES(
            NAME varchar,
            ID int
        )
        comment = 'This table is only created in HR';
    {% endif %}

    -- use dictionary booleans to deploy optional infrastructure
    {% if team.needs_sandbox_schema | default(false) %}
        define schema DCM_DEMO_1{{env_suffix}}.{{team_name}}_SANDBOX
            comment = 'Sandbox schema defined via dictionary flag'
            data_retention_time_in_days = 1;
    {% endif %}

{% endfor %}