Object dependencies are the logic engine of Variant Configuration. They control what values are allowed, which BOM components get selected, how pricing surcharges are calculated, and which operations go into the routing.
This reference covers every dependency type, its syntax, where it gets assigned, how the system processes them, and what each table stores.
Sources: SAP Help: Object Dependencies Overview | SAP Help: Preconditions | SAP Help: Constraints | SAP Help: Processing Sequence | SAP Help: Object Variables ($SELF/$PARENT/$ROOT)
The Dependency Types
SAP supports four dependency types. Preconditions, Selection Conditions, and Procedures all use the same generic transactions:
| Type | Create | Change | Display | Purpose |
|---|---|---|---|---|
| Precondition | CU01 | CU02 | CU03 | Hide disallowed characteristic values |
| Selection Condition | CU01 | CU02 | CU03 | Select BOM items, operations, PRTs |
| Procedure | CU01 | CU02 | CU03 | Infer values, change master data fields |
| Constraint | CU21 (create) | CU22 (change) | CU23 (display) | Describe relationships between objects |
Additional analysis transactions:
| Transaction | Purpose |
|---|---|
| CU04 | Report — list dependencies for a material or class |
| CU06 | Where-used list — find which objects reference a dependency |
Preconditions
Assigned to: Characteristic values (mainly) and characteristics Purpose: Hide disallowed values. If the precondition is not met, the value is invisible on the configuration screen.
A precondition attached to a characteristic value means: "this value is only available when the condition is true."
Example: A bike has characteristic MODEL with values Racing, Standard, Mountain. Characteristic GEARS has values 10, 12, 17, 21. Value 21 is only available when MODEL = Racing.
Model = 'Racing' and specified MODEL
This precondition is attached to value 21 of characteristic GEARS. The user can only select 21 gears if MODEL is already set to Racing.
Key rules:
- Preconditions on characteristics hide the entire characteristic
- Preconditions on characteristic values hide individual values
- Use constraints instead of preconditions when possible (easier to locate and debug)
- The syntax is a boolean expression that evaluates to true or false
Selection Conditions
Assigned to: BOM items and routing operations Purpose: Determine which components and operations are needed for a specific configuration.
A selection condition controls whether a BOM item (component) or routing operation is included in the production order. If the condition evaluates to false, the component or operation is excluded.
Syntax (BOM):
$parent.<CHARACTERISTIC> = '<VALUE>' AND $parent.<OTHER_CHAR> <OP> <VALUE>
Example: Select a specific handlebar component only when the bike model is Racing.
$parent.MODEL = 'Racing'
Example with multiple conditions:
$parent.MODEL = 'Racing' and $parent.COLOR = 'Red'
Key differences from preconditions:
- Selection conditions control BOM/routing inclusion, not UI visibility
- They use
$parent.to reference characteristics of the configurable material - They also serve as required conditions: if a characteristic has a selection condition, it becomes mandatory to fill
Procedures
Assigned to: Characteristics, characteristic values, or configuration profile Purpose: The workhorse of VC logic. Infer values, set defaults, calculate formulas, update master data fields.
Procedures execute every time the user changes a characteristic value. They can set defaults (user-overridable) or force values (user-cannot-override).
Core syntax patterns:
| Pattern | Syntax | Use Case |
|---|---|---|
| Force value | $self.COLOR = 'Red' |
Set a value the user cannot change |
| Default value | $self.COLOR ?= 'Blue' |
Set a default the user can override |
| Conditional | $self.COLOR = 'Red' if $self.TYPE = 'Standard' |
Set value based on another char |
| Multi-condition | $self.COLOR = 'Red' if $self.TYPE = 'Standard' and $self.SIZE > 10 |
Complex conditions |
| Default on unset | $self.COLOR ?= 'Blue' if not ($self.COLOR specified) |
Set default only if not already entered |
| Text concat | $self.DESCRIPTION = $self.TYPE || '-' || $self.COLOR |
Build descriptions |
| Arithmetic | $self.AREA = $self.WIDTH * $self.LENGTH |
Calculate values |
Setting variant pricing surcharges:
$self.surcharge2 = 'HD-003_02' if $self.HD_COLOR = 'Black'
This works with a reference characteristic pointing to SDCOM-VKOND and condition type VA00.
Pricing factor syntax:
$SET_PRICING_FACTOR ($SELF, <reference characteristic>, <variant key>, <factor>)
Summing values from child BOM items:
$SUM_PARTS ($SELF, <characteristic>)
Used to calculate total weight of components and write to VCSD_UPDATE-BRGEW (gross weight).
Counting BOM items:
$COUNT_PARTS ($SELF)
Deleting defaults:
$DEL_DEFAULT ($SELF, <characteristic>, <term>)
Procedures vs Constraints
Use procedures for value inference and defaults. Use constraints for cross-object relationship enforcement. They serve different purposes and complement each other.
Constraints
Assigned to: Configuration profile (via dependency nets) Purpose: Describe relationships between different objects in a configuration. Handle complex cross-object logic.
Constraints are grouped together in dependency nets. The net is assigned to the configuration profile.
A constraint has four sections:
| Section | Purpose |
|---|---|
| OBJECTS | Declare all classes and objects involved |
| CONDITION | Prerequisite for processing the constraint |
| RESTRICTIONS | Check and set value relationships |
| INFERENCES | Define which values to infer automatically |
Example: A hard disk can only be 16GB for a tower casing or 8GB for a mini tower.
OBJECTS:
CASE IS_A(300) CASE_CLASS,
HD IS_A(300) HD_CLASS
CONDITION:
CASE.MODEL = 'Tower' OR CASE.MODEL = 'Mini'
RESTRICTIONS:
HD.SIZE = '16GB' IF CASE.MODEL = 'Tower',
HD.SIZE = '8GB' IF CASE.MODEL = 'Mini'
INFERENCES:
HD.SIZE
Key difference from procedures:
- Constraints use general object references (no
$SELF/$PARENT/$ROOT) - Constraints only execute when all objects in the OBJECTS section exist in the configuration
- Constraints have more overhead but execute only when required
- Constraints enforce consistency across different BOM levels
Dependency nets (constraint nets) are created via CU21, changed via CU22, displayed via CU23. The net groups related constraints — individual constraints are created inside the net. The net is then assigned to the configuration profile (CU41 assignment tab).
Local vs. Global Dependencies
| Local | Global | |
|---|---|---|
| Created for | A single object (characteristic, BOM item, etc.) | Created centrally |
| Naming | System-assigned sequential number | User-defined name |
| Reusability | Tied to one object, cannot be reused | Can be assigned to many objects |
| Best practice | Avoid for production models | Use for everything |
Rule: Always use global dependencies. The sequential numbering of local dependencies makes them impossible to manage at scale.
Object Variables: $SELF, $PARENT, $ROOT
These three variables control which object a dependency refers to in multi-level configurations.
| Variable | Refers To |
|---|---|
| $ROOT | The highest-level configurable material in the configuration |
| $SELF | The material to which the dependency is directly assigned |
| $PARENT | The object immediately above $SELF |
Behavior by assignment:
- Dependencies on the header material: $SELF and $ROOT are the same. $PARENT has no meaning.
- Dependencies on BOM items: $PARENT is the configurable material (the BOM owner), $SELF is the BOM item material.
- In constraints: Object variables are not used. Objects are declared by class in the OBJECTS section.
Multi-level nuance: If the BOM is exploded in production, $ROOT always refers to the material that transfers requirements. If the BOM is relevant to SD, $ROOT always refers to the header material.
Processing Sequence
Every time the user enters or changes a characteristic value, the system processes dependencies in a strict sequence.
1. Procedures (exactly once):
a. Procedures on the configuration profile (in order)
b. Procedures on characteristics
c. Procedures on characteristic values
2. Constraints (processed after Procedures, only when objects exist and conditions are met)
3. Preconditions
4. Selection conditions
Significant implications:
- A Procedure can set a value that triggers another Procedure's condition, but Procedures only run once. If you need chaining, use the configuration profile procedure list or restructure the logic.
- Constraints are evaluated after Procedures and before Preconditions. This ensures procedures have already set final values before constraint validation begins.
- Preconditions and selection conditions run last. This ensures the UI only shows valid values after all inference is done.
Dependency Groups
Dependencies can be tagged with a dependency group (CUKB-KNGRP). This controls when the system evaluates them.
| Group | Behavior |
|---|---|
| (empty/default) | Process during interactive configuration |
| SAP_PRICING | Process during pricing (can be triggered separately) |
Use the SAP_PRICING group when you want to calculate pricing-related values independently of the main configuration. This prevents pricing formulas from executing during every click in the configuration UI.
Database Tables
Every dependency lives in these tables:
| Table | What It Stores |
|---|---|
| CUKB | Administrative info: name (KNNAM), type (KNART), group (KNGRP), version, status, created by, created date |
| CUKN | Actual source code: blocks of code (KNBLK, up to 2886 chars per block) linked by dependency number (KNNUM) |
| CUOB | Assignment: which object (KNOBJ) has which dependency (KNNUM) assigned, and what table (KNTAB) the object belongs to |
How to trace dependency assignments:
Object (CABN/CAWN/KLAH/CUCO/PLPOD) → KNOBJ → CUOB-KNOBJ
CUOB-KNNUM → CUKB-KNNUM (dependency name)
CUOB-KNNUM → CUKN-KNNUM (source code in KNBLK)
Every object in VC has a field called KNOBJ. This number links to CUOB. The field CUOB-KNTAB tells you what kind of object the dependency is assigned to (CABN for characteristics, CAWN for values, KLAH for classes, CUCO for config profiles, PLPOD for routing operations).
To view VC dependencies for a given object, use CU50 configuration simulation or CU03 to display object dependencies.
Where Dependencies Are Assigned
| Object | Dependency Types Allowed | Transaction |
|---|---|---|
| Characteristic | Precondition, Selection Condition, Procedure | CT04 → Extras → Dependencies |
| Characteristic Value | Precondition, Procedure | CT04 → Values tab → select value → Extras → Dependencies |
| Class | Precondition, Procedure | CL02 → Extras → Dependencies |
| BOM Item | Selection Condition, Procedure, Action | CS02 → select item → Goto → Object dependencies |
| Routing Operation | Selection Condition, Procedure, Action | CA02 → select op → Goto → Object dependencies |
| Config Profile | Procedure, Constraint (via dependency net) | CU41 → Dependencies tab |
| Config Profile (net) | Constraint | CU21 → Dependency Net |
Syntax Reference
Operators:
| Operator | Meaning |
|---|---|
| = | Equal |
| <> | Not equal |
| >, >=, <, <= | Comparison (numeric characteristics only) |
| in () | Set membership: $self.COLOR in ('Red', 'Blue') |
| AND / and | Logical AND |
| OR / or | Logical OR |
| NOT / not | Logical NOT |
| specified | Check if a characteristic has a value: $self.COLOR specified |
Numbers: Use without quotes. Strings: Use single quotes: 'Red'
Procedure assignment operators:
| Operator | Meaning |
|---|---|
| = | Force value (user cannot change) |
| ?= | Default value (user can override) |
| ?= if not (specified) | Set default only if user hasn't entered a value |
Keyword case: Characteristics and keywords are case-insensitive.
Best Practices from Real Projects
Use Constraints Instead of Preconditions
Preconditions are attached to individual characteristic values. Finding all of them means checking every value of every characteristic. Constraints live in one place (the config profile dependency net). Easier to find, debug, and audit.
Assign Procedures to the Configuration Profile
Procedures on the config profile run in a defined order. Procedures scattered across characteristics lose this ordering guarantee. Use the profile procedure list for all production logic.
Always Comment Your Code
Object dependency logic looks simple when you write it. Six months later it is cryptic. Add a comment for every non-obvious condition.
($self.COLOR = 'Red') if $self.TYPE = 'Premium'
/* Premium models force red as standard color */
Avoid Local Dependencies
Local dependencies use system-assigned sequential numbers (0001, 0002...). You cannot tell what they do from the number. You cannot reuse them. Every production dependency should be a named global dependency.
Use Parentheses for Group Conditions
($SELF.COLOR = 'Red', $SELF.SIZE = 'Medium') IF $SELF.TYPE = 'Standard'
Parentheses make the intent clear and prevent operator precedence surprises.
Understand Procedure vs. Constraint Performance
Procedures load faster but execute on every value change. Constraints have more overhead but only run when needed (when all objects in the OBJECTS section exist). For simple single-object logic use procedures. For cross-object validation use constraints.
SAP_PRICING Dependency Group
Assign pricing-only logic to the SAP_PRICING dependency group. This prevents recalculating pricing formulas during every configuration step, improving UI responsiveness.
Common Mistakes
- Using Actions: SAP marked them obsolete.
- Too many preconditions: Makes models hard to debug. Use constraints instead.
- No comments: Six months later you will not remember why you wrote
$self.X = '3' if $self.Y in ('A', 'B'). - Mixing force and default: Understand the difference between
=and?=. Using=when you meant?=blocks user choice. - Wrong object variable:
$PARENTon a header material dependency has no effect.$ROOTon a BOM item dependency might not be what you intend in deep multi-level BOMs. - Forgetting that Procedures run once: If Procedure A sets a value that Procedure B needs, and B runs before A, B gets the old value. Order your profile procedure list carefully.
Dependencies are where the complexity of Variant Configuration lives. The individual types are simple. The challenge is knowing which type to use, where to assign it, and how the processing sequence affects the result. Get those three right, and the syntax takes care of itself.