Patterns
intermediategovernance

Decision Table

Externalize complex branching logic — pricing tiers, eligibility rules, routing decisions — into a readable table that business users can maintain without a developer in the loop.

Views7
BPMN 2.0
On this page

Visual Flow

Rendering diagram…

When to Use This Pattern

Use a decision table whenever:

  • The rules change often but the surrounding process doesn't
  • Business users understand the rules better than engineers do
  • An "if this and this and this, then that" clause is starting to nest past three levels
  • The rules need to be auditable — who changed what, and when?

Classic examples: pricing tiers, shipping cost rules, fraud scoring thresholds, approval routing, lead scoring, eligibility checks, plan benefits.

If your if/else tree in code is getting commits from multiple people every week, that's a decision table screaming to be born.

How It Works

A decision table has:

  • Input columns: the variables it reads (amount, region, tier, age, …)
  • Output columns: what it returns (price, shipping method, approver, …)
  • Rows: one rule per row
  • Hit policy: what happens when multiple rows match. Common policies:
    • Unique — exactly one row should match. Error if more. Good for pricing.
    • First — use the first matching row. Good for priority rules.
    • Collect — return all matching outputs. Good for eligibility (multiple benefits).

The DMN standard formalises this with a FEEL expression language. You don't need a DMN engine to use the pattern — a versioned CSV and a tiny evaluator will get you 80% of the value.

Tip

Picking the wrong hit policy is the most common bug. Start with Unique — it screams the moment you have overlapping rules.

Implementation Guide

Step 1: Identify the inputs and outputs

List every variable that could influence the decision. Be generous up front — it's easier to delete a column than to add one later when you have 200 rows.

Step 2: Draft the rows in a spreadsheet first

Don't start in code. Put the table in a sheet where the business owner can see it and poke at it. Iterate until they agree the rules match reality.

Step 3: Pick a hit policy

For each decision, pick the one that matches your intent. "Unique, fail loudly if multiple match" is a reasonable default.

Step 4: Build a small evaluator

If you're not using a DMN engine, a 50-line evaluator will do. Inputs in, rows checked in order, matching rows' outputs returned per the hit policy. Write thorough tests; this is business-critical logic.

Step 5: Version it

Every change to the table is a diff. Treat the table like code: PRs, review, deploy pipeline. If a non-engineer edits it, the PR should explain why in plain language.

Step 6: Log every evaluation

Record inputs, matched row(s), and output for each call. When a customer asks "why was I charged this?", the log answers. When the rules change, the log lets you replay the old rules against today's data.

Tips & Best Practices

  • Keep one concern per table. "Pricing" and "fraud scoring" are separate tables even if they share inputs.
  • Cap the table size. If you're over 50 rows, split into sub-tables or move some logic into a proper function.
  • Show the table in the app. Users accepting a decision often ask "why?". A read-only view of the matched row answers it.
  • Run the table against last month's real data before deploying changes. Regressions in a decision table ship silently and cost money.

Related patterns