Modeling Dimension Tables
PostHogOfficialPublished by PostHog
- Skill
- Guidelines
- Data and AI
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to creating dimension and lookup tables for star schema data modeling. It covers the end-to-end process of sourcing, shaping, and attaching descriptive attributes—such as country, plan, or date—to fact tables. By centralizing these dimensions, users can avoid redundant joins and ensure consistent reporting across revenue, conversion, and usage metrics. The skill emphasizes best practices like maintaining unique keys, materializing static data on slow schedules, and leveraging built-in currency conversion functions.
What it does
- Defines the three-step process: source, shape, and attach.
- Provides patterns for sourcing data via uploads, warehouse sources, or event derivation.
- Explains how to shape data into aliased, one-row-per-entity views.
- Guides users on materializing dimensions to optimize query performance.
- Outlines how to attach dimensions to fact tables for use as native fields.
- Offers specific guidance for PostHog HogQL and dbt environments.
When to use it
- When you need to enrich event or revenue data with descriptive attributes.
- When you want to implement a star schema to simplify complex analytical queries.
- When you need to create conformed dimensions for consistent reporting across models.
- When you want to avoid repeating complex join logic in every query.
- When you need to model static or slowly changing lookup data.
Advantages
- Reduces query complexity by replacing repeated joins with native fields.
- Ensures data consistency by reusing certified dimension tables.
- Optimizes performance through materialization of static lookups.
- Provides a clear, standardized workflow for both PostHog and dbt users.
Usage examples
- “How do I create a country dimension table in PostHog?”
- The agent will guide you to derive unique country codes from event properties, shape them into an aliased view, and materialize it for efficient joining.
- “What is the best way to handle plan tiers in my star schema?”
- The agent will recommend sourcing plan data from your system of record, shaping it into a unique-key dimension table, and joining it to your revenue facts.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/posthog/modeling-dimension-tables/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip modeling-dimension-tables.zip -d .agents/skills
Documentation by PostHog
Modeling dimension tables (star schema)
Dimensions are the descriptive tables (dim_country, dim_plan, dim_date) that fact tables join to for
slicing. This skill builds them once, cleanly, so every other model reuses them instead of re-deriving
lookups. Read modeling-warehouse-foundations first (joins + convertCurrency() live there). Catalog of
common dimensions: references/dimension-catalog.md; recipes in
references/posthog/ and references/dbt/.
Star schema in one screen
Facts (events, charges, revenue items) are long, keyed, and additive. Dimensions are short, one row per entity, descriptive. You model a dimension in three moves:
Source it — where does the dimension data come from?
Upload / seed a lookup (country→region, plan→tier) as a CSV (warehouse source or dbt seed).
Sync it from a system of record (your app DB, Stripe products) as a warehouse source.
Derive it from events (distinct countries seen, a plan property observed per person).
Shape it — an aliased
SELECTwith clean column names, one row per entity (dedupe hard). Save as a view; materialize it on a slowsync_frequency(7day/30day) since dimensions change rarely and are read constantly.Attach it — a saved join (dimension → a fact table) or person join (dimension → persons) so its columns appear as native fields in any query, filter, or breakdown. See foundations
joins-and-dimensions.md.
Currency is already a managed dimension — don't build it
PostHog ships exchange rates behind convertCurrency(from, to, amount, timestamp?) (Open Exchange Rates,
historical-rate-correct). Use it directly for any money conversion. Only build a currency dimension yourself
in dbt (which has no equivalent), or if you need a rate provider PostHog doesn't offer.
Rules before you model
One row per entity, unique key. A dimension with duplicate keys silently fan-outs every fact it joins. Test uniqueness (PostHog: verify in the shaping query; dbt:
unique+not_null).Drop NULL keys when you derive a dimension from events. HogQL keeps a row whose property is missing when the filter only compares it to
'', so addisNotNull(...)as well. A NULL key becomes a dimension row of its own and it matches nothing on the fact side.Alias to clean, stable names —
country_code,region,plan_tier. These names become the join surface everything else depends on.Materialize static dimensions on a slow schedule; don't leave a constantly-read lookup virtual.
Register and certify. Annotate the dimension and, if it's load-bearing, certify it in the catalog (foundations
governance.md) so other models discover it and don't build a rival copy.Prefer built-in currency (
convertCurrency) over a hand-rolled FX table on PostHog.
Build it
PostHog: shape an aliased dimension view, then materialize + join. Recipes:
references/posthog/dim_country.sql (derive + enrich from events),
dim_plan.sql (lookup/upload pattern).
dbt: conformed dim_* models with unique/not_null/relationships tests, plus a generated
dim_date. Recipes: references/dbt/.
File map
| File | Read when |
|---|---|
references/dimension-catalog.md | Common dimensions, how to source each, and the natural key. |
references/posthog/ | HogQL aliased-dimension view recipes. |
references/dbt/ | dbt dim_date / dim_country + schema.yml tests. |
Companions
modeling-warehouse-foundations (joins + currency), setting-up-a-data-warehouse-source /
suggesting-data-imports (sync/upload the source data), and the models that consume these dimensions:
modeling-revenue-metrics, modeling-conversion-metrics, modeling-activation-metrics,
modeling-product-usage-metrics.
Files
- ATTRIBUTION.mdAdded by AutoGineer869 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md5.4 KiB
- references/dbt/dim_country.sql567 B
- references/dbt/dim_date.sql917 B
- references/dbt/schema.yml686 B
- references/dimension-catalog.md3.2 KiB
- references/posthog/dim_country.sql1.2 KiB
- references/posthog/dim_plan.sql775 B
SKILL.md
Modeling dimension tables (star schema)
Dimensions are the descriptive tables (dim_country, dim_plan, dim_date) that fact tables join to for
slicing. This skill builds them once, cleanly, so every other model reuses them instead of re-deriving
lookups. Read modeling-warehouse-foundations first (joins + convertCurrency() live there). Catalog of
common dimensions: references/dimension-catalog.md; recipes in
references/posthog/ and references/dbt/.
Star schema in one screen
Facts (events, charges, revenue items) are long, keyed, and additive. Dimensions are short, one row per entity, descriptive. You model a dimension in three moves:
Source it — where does the dimension data come from?
Upload / seed a lookup (country→region, plan→tier) as a CSV (warehouse source or dbt seed).
Sync it from a system of record (your app DB, Stripe products) as a warehouse source.
Derive it from events (distinct countries seen, a plan property observed per person).
Shape it — an aliased
SELECTwith clean column names, one row per entity (dedupe hard). Save as a view; materialize it on a slowsync_frequency(7day/30day) since dimensions change rarely and are read constantly.Attach it — a saved join (dimension → a fact table) or person join (dimension → persons) so its columns appear as native fields in any query, filter, or breakdown. See foundations
joins-and-dimensions.md.
Currency is already a managed dimension — don't build it
PostHog ships exchange rates behind convertCurrency(from, to, amount, timestamp?) (Open Exchange Rates,
historical-rate-correct). Use it directly for any money conversion. Only build a currency dimension yourself
in dbt (which has no equivalent), or if you need a rate provider PostHog doesn't offer.
Rules before you model
One row per entity, unique key. A dimension with duplicate keys silently fan-outs every fact it joins. Test uniqueness (PostHog: verify in the shaping query; dbt:
unique+not_null).Drop NULL keys when you derive a dimension from events. HogQL keeps a row whose property is missing when the filter only compares it to
'', so addisNotNull(...)as well. A NULL key becomes a dimension row of its own and it matches nothing on the fact side.Alias to clean, stable names —
country_code,region,plan_tier. These names become the join surface everything else depends on.Materialize static dimensions on a slow schedule; don't leave a constantly-read lookup virtual.
Register and certify. Annotate the dimension and, if it's load-bearing, certify it in the catalog (foundations
governance.md) so other models discover it and don't build a rival copy.Prefer built-in currency (
convertCurrency) over a hand-rolled FX table on PostHog.
Build it
PostHog: shape an aliased dimension view, then materialize + join. Recipes:
references/posthog/dim_country.sql (derive + enrich from events),
dim_plan.sql (lookup/upload pattern).
dbt: conformed dim_* models with unique/not_null/relationships tests, plus a generated
dim_date. Recipes: references/dbt/.
File map
| File | Read when |
|---|---|
references/dimension-catalog.md | Common dimensions, how to source each, and the natural key. |
references/posthog/ | HogQL aliased-dimension view recipes. |
references/dbt/ | dbt dim_date / dim_country + schema.yml tests. |
Companions
modeling-warehouse-foundations (joins + currency), setting-up-a-data-warehouse-source /
suggesting-data-imports (sync/upload the source data), and the models that consume these dimensions:
modeling-revenue-metrics, modeling-conversion-metrics, modeling-activation-metrics,
modeling-product-usage-metrics.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- PostHog
- Publisher
- PostHog (Official)
- Source
- PostHog/skills · skills/omnibus/modeling-dimension-tables · commit a5d30e7
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by PostHog or PostHog.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download modeling-dimension-tables.zip