CertSafari
    DBT Analytics Engineering· Lessons

    Domain 1 · Lesson 6/31

    Configuring resources in dbt_project.yml

    Defining configurations in dbt_project.yml

    14 min read
    3.23% of exam
    7 sources
    Published 12 Oct 2026
    Docs as of 12 Oct 2026

    What you will be able to do

    • Say what dbt_project.yml must contain, and which project-level keys it sets
    • Write resource paths that target every model, only your project, one folder, or a single model
    • Use the + prefix correctly, and spell multi-word resource keys the way dbt_project.yml expects
    • Work out the final value of a config set in several places, including tags, hooks and meta, which merge instead of replacing

    Key concept

    Hierarchical configuration — In dbt_project.yml, a config set at one level of the resource path applies to everything below that level. Any deeper or more specific setting overrides it. On top of that, a config in a resource's .yml properties or its config() block overrides anything set in the project file.

    1.What dbt_project.yml is for

    **dbt_project.yml is the one file every dbt project must have.** dbt treats a directory as a project only when this file is present. dbt searches the current working directory and its parents for it. To point dbt somewhere else, use the --project-dir flag or, from v1.11, the DBT_ENGINE_PROJECT_DIR environment variable. The file also stores the settings that control how dbt runs the project.

    The file carries two kinds of setting. The first kind describes the project itself: its name, the connection profile, and where each resource type lives on disk. The second kind sits under resource keys such as models:, seeds:, snapshots:, sources: and data_tests:. These keys hold configs that dbt applies to many resources at once. The table below lists the project-level keys you will meet most often.

    Common project-level keys in dbt_project.yml
    KeyWhat it sets
    nameYour project's name in snake case
    profileThe profile dbt uses to connect to your data platform
    model-pathsDirectories where your model and source files live
    seed-paths / macro-paths / snapshot-pathsDirectories for seeds, macros and snapshots
    require-dbt-versionRestricts the project to a range of dbt versions
    varsProject variables used during compilation

    Only configs belong under the resource keys. dbt separates properties, which describe a resource (descriptions, column tests, exposure types), from configs, which tell dbt how to build it (materialization, schema, tags, meta). You declare properties one resource at a time in .yml property files. You can set a config in three places: in a .yml file, in a config() macro inside the .sql file, or in dbt_project.yml for whole groups of resources. A non-config property, such as anything about macros, cannot go in the project file. This bulk setting is why teams organise models into folders: a folder-level config saves people from remembering to add a config block to every new model.

    Checkpoint 1 of 8· Check yourself

    A teammate wants to use dbt_project.yml to set something for a whole group of resources. Which of these can go there?

    Sources123

    2.Targeting resources with resource paths

    A resource path is a set of nested YAML keys that matches your folder layout. Under models:, the first level can be your project name. Below that come directory names, then subdirectory names, and at the deepest level a single resource named after its file. How deep you place a config decides how much it affects. That makes the nesting level the first thing to check when a config hits too many models or too few.

    The levels differ in exactly what they include. A config placed directly under models:, with no path, applies to every model dbt loads, including models from installed packages. Disabling everything this way is rarely what you want. A config nested under your project name applies to your own models and leaves package models alone. Add staging: below the project name and the config reaches only models/staging/. Spell out the full path down to a file name and it reaches a single model:

    A config that targets only models/staging/stripe/payments.sqlyaml
    name: jaffle_shop
    
    models:
      jaffle_shop:
        staging:
          stripe:
            payments:
              +enabled: false # this will apply to only one model

    Nested levels let you set a broad default and then make a narrow exception. In the example below, every model under events/ becomes a view. The base/ subfolder inside it overrides that and becomes ephemeral. Folder-wide materialization defaults are the most common use of this pattern. What each materialization actually builds is covered in [core materializations](lesson:1.2).

    A folder default overridden by a deeper subfolderyaml
    models:
      # Be sure to namespace your model configs to your project name
      dbt_labs:
    
        # This configures models found in models/events/
        events:
          +enabled: true
          +materialized: view
    
          # This configures models found in models/events/base
          # These models will be ephemeral, as the config above is overridden
          base:
            +materialized: ephemeral

    Sources use the same nesting. To disable a single source table defined in a YAML file inside a subfolder, list the subfolder, then the source name, then the table name, all under your project name in the sources: key.

    Checkpoint 2 of 8· Check yourself

    Your project is named jaffle_shop and has two packages installed. You need to disable every model you wrote, and only those. Where does +enabled: false go?

    Checkpoint 3 of 8· Exam question

    A team sets `materialized: view` for the `staging` directory in `dbt_project.yml`. One staging model also has `materialized: table` inside a `{{ config() }}` block at the top of its SQL file, and its `.yml` properties file sets `materialized: incremental` under a `config:` block. When `dbt run` builds that model, which materialization does dbt actually apply?

    Sources4

    3.The + prefix: telling configs apart from folders

    **In dbt_project.yml, a leading + marks a key as a config, and a key without it is read as a folder or file name.** Configs and folder names sit in the same nested dictionaries, so dbt needs a way to tell staging: (a directory) from +schema: (a setting). Projects on config-version: 2 are expected to prefix every config key with +. Writing configs without the prefix is deprecated, and the prefix does not work at all in files that use config-version: 1.

    Two situations actually break when the prefix is missing. The first is a config whose value is a dictionary, such as persist_docs. Without +, its relation: and columns: keys look like subfolders. The second is a folder whose name matches a config name, such as a models/tags/ directory next to the tags config. Folder and file names must not start with +. In dbt v2, a resource path that starts with + raises a warning, so rename any folder such as +my_folder.

    Checkpoint 4 of 8· Fill the gap

    Every model should default to a view, and models in marts/ should become tables. Which key completes the marts setting?

    models:
      +materialized: view
      jaffle_shop:
        marts:
           ? : table

    Checkpoint 5 of 8· Exam question

    An engineer writes this snippet in `dbt_project.yml`: ``` models: jaffle_shop: marts: materialized: table finance: tags: ["finance"] ``` They expect every model under `marts/finance` to materialize as a table, but all of them build as views instead. Which line in this snippet is misconfigured?

    Sources5

    4.Spelling multi-word resource keys

    Resource keys with more than one word follow different spelling rules, and the rule depends on the resource type and the file. In dbt_project.yml, saved queries and semantic models are written with dashes: saved-queries: and semantic-models:. Data tests and unit tests use underscores in every file, including the project file: data_tests: and unit_tests:. In any YAML file other than dbt_project.yml, multi-word resource types use underscores, so the saved queries key in a properties file is saved_queries:.

    How the same resource type is spelled in each kind of file
    Resource typeKey in dbt_project.ymlKey in other YAML files
    Saved queriessaved-queriessaved_queries
    Semantic modelssemantic-modelsunderscore form
    Data testsdata_testsdata_tests
    Unit testsunit_testsunit_tests

    Watch for this when copying blocks between files. A saved_queries: block pasted from a properties file into dbt_project.yml has the wrong key there. A data-tests: key written to look like semantic-models: is wrong in every file.

    Checkpoint 6 of 8· Match them up

    Match each key to the place where it is the correct spelling

    Tap a term, then the definition that fits it.

    Sources1

    5.Which value wins: precedence, clobbering and merging

    The project file has the lowest precedence of the three places a config can live. When the same config is set in more than one place, dbt uses the most specific one. A config() block inside the model file beats the config: property in a .yml file, and both beat dbt_project.yml. Within dbt_project.yml, the most deeply nested path wins. Your root project's settings also beat the settings that ship inside installed packages. That lets you change a package's behaviour from your own dbt_project.yml without editing files that dbt deps would overwrite.

    For most configs, overriding means replacing outright, which dbt calls clobbering. If dbt_project.yml sets +materialized: view for a folder and one model's config() says table, that model is a table and nothing of the view setting remains.

    A few configs combine values instead of replacing them, and these exceptions are what questions about final values usually test. tags are additive, so a model keeps its project-level tags and adds its own. pre-hook and post-hook are additive too, so a project-wide hook still runs alongside a model's own hook. For freshness, a more specific key-value pair replaces only the less specific value that has the same key.

    meta is shallow-merged, which catches people out with nested values. dbt combines the top-level keys from every level, but when the same top-level key appears at two levels, the more specific value replaces it whole. Suppose dbt_project.yml sets +meta with owner: "alice" and a dagster dictionary holding automation_condition: "eager", and a model sets meta with dagster: {asset_key: "my_key"}. The result keeps owner, but dagster contains only asset_key. The nested automation_condition is lost, because dbt never looks inside dagster to merge it.

    Checkpoint 7 of 8· Check yourself

    dbt_project.yml sets +meta: {owner: "alice", dagster: {automation_condition: "eager"}}. A model's .yml sets meta: {dagster: {asset_key: "my_key"}}. What is the model's final meta?

    Checkpoint 8 of 8· Exam question

    A `dbt_project.yml` sets `+grants: {select: ['user_a', 'user_b']}` under `models:`. A specific model's `.yml` properties file sets `config: {grants: {select: ['user_c']}}`. Which statements correctly describe how dbt resolves the grants on that model? (Select all that apply.)(Select 3)

    Sources67

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.A materialization set in dbt_project.yml overrides the one in a model's config() block, because the project file is the central source of truth.Why is that wrong?

      It works the other way round. The in-file config() block wins over .yml properties, and both win over the project file.

      Covered in Which value wins: precedence, clobbering and merging

    2. 2.Config keys need the + prefix wherever you set them, including inside config() and under a .yml config: property.Why is that wrong?

      The + prefix applies only to configs under a resource key in dbt_project.yml. config() and the .yml config property do not use it.

      Covered in The + prefix: telling configs apart from folders

    3. 3.A config placed directly under models: with no project name affects only the models in your own project.Why is that wrong?

      With no resource path, the config applies to every model, including models from installed packages. To limit it to your own models, nest it under your project name.

      Covered in Targeting resources with resource paths

    4. 4.Hooks set on a model replace the project-wide pre-hook or post-hook, just as a model's materialization replaces the folder default.Why is that wrong?

      Hooks are additive, like tags, so hooks from the project level and the model level all apply. Most other configs are clobbered.

      Covered in Which value wins: precedence, clobbering and merging

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “Every dbt project needs a dbt_project.yml file — this is how dbt knows a directory is a dbt project.”
      ↩︎ What dbt_project.yml is for
      “By default, dbt looks for the dbt_project.yml in your current working directory and its parents”
      ↩︎ What dbt_project.yml is for
      “For the multi-word resource types saved-queries and semantic-models, use dashes (-) in dbt_project.yml.”
      ↩︎ Spelling multi-word resource keys
      “For YAML files other than dbt_project.yml, use underscores (_) for multi-word resource types.”
      ↩︎ Spelling multi-word resource keys
      “The + prefix is used for configs only and applies to dbt_project.yml under the corresponding resource key.”
      ↩︎ Exam trap 2
      “Note, you can't set up a "property" in the dbt_project.yml file if it's not a config (an example is macros).”
      ↩︎ Checkpoint
      “For data tests and unit tests, use underscores (_) everywhere, including in dbt_project.yml”
      ↩︎ Checkpoint
    2. 2.
      “They can also be set one-by-one via a config() macro (right within .sql files), and for many resources at once in dbt_project.yml.”
      ↩︎ What dbt_project.yml is for
    3. 3.
      “Some bulk configurations are easier done at the directory level so people don't have to remember to do everything in a config block”
      ↩︎ What dbt_project.yml is for
    4. 4.
      “the nested dictionary keys that provide the path to a directory of that resource type, or a single instance of that resource type”
      ↩︎ Targeting resources with resource paths
      “this will disable all models (not a thing you probably want to do)”
      ↩︎ Targeting resources with resource paths
      “To apply a configuration to all models in your project only, use your project name as the <resource-path>:”
      ↩︎ Exam trap 3
      “this will apply to all models in your project, but not any installed packages”
      ↩︎ Checkpoint
    5. 5.
      “For projects using config-version 2, dbt expects configuration keys to use the + prefix. Specifying configurations without the + prefix is deprecated.”
      ↩︎ The + prefix: telling configs apart from folders
      “A config shares a key with part of a resource path, such as a directory of models named tags.”
      ↩︎ The + prefix: telling configs apart from folders
      “Currently, the only config which supports + for controlling config merge behavior is grants.”
      ↩︎ The + prefix: telling configs apart from folders
    6. 6.
      “Configurations in your root dbt project have higher precedence than configurations in installed packages.”
      ↩︎ Which value wins: precedence, clobbering and merging
      “Whenever a more specific value is available, it will completely replace the less specific value.”
      ↩︎ Which value wins: precedence, clobbering and merging
      “Within the project file, configurations are also applied hierarchically. The most specific config always takes precedence.”
      ↩︎ Key concept
      “an in-file config() block --> properties defined in a .yml file --> config defined in the project file.”
      ↩︎ Exam trap 1
      “pre-hook and post-hook are also additive.”
      ↩︎ Exam trap 4
      “tags are additive.”
      ↩︎ Prediction
      “meta dictionaries are shallow-merged, meaning dbt merges only the top-level keys and does not look inside nested dictionaries.”
      ↩︎ Checkpoint
    7. 7.
      “In this case, the model that's nested the deepest will have the highest priority.”
      ↩︎ Which value wins: precedence, clobbering and merging

    Ready to test yourself?

    Practise the 11 questions on this subdomain.

    Spotted a mistake, or was something unclear? Tell us.