How to use
- Copy the installation command and review the source package before installing it in your own agent environment.
- Check the source document for required tools, credentials and supported hosts.
- Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/looker-open-source/looker-skills --skill lookml-exploreBefore you start
- Installation does not include a model subscription, API allowance or permission to access your files.
- Repository stars and installation counts describe activity, not an independent quality or security test.
Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.
Instructions
1. Core Standards
- Naming Convention:
snake_casefor the Explore name. - Required Parameters:
description: 100% Coverage. Every Explore MUST have a description.label: A user-friendly name for the Explore in the UI.view_name: Defaults to explore name, but explicit definition is safer.
- Joins:
relationship: Required (onetoone, manytoone).sql_on: Required. Use${left.id} = ${right.id}syntax.type: defaults toleft_outer. Useinnerorfull_outerexplicitly if needed.
- Formatting:
- Do NOT use
fromto rename views just for aesthetics. Useview_labelinstead. - Exception: Polymorphic joins, Self-joins, Rescoping extensions.
2. Advanced Configuration
always_filter: specific filters that users can change but cannot remove.sql_always_where: specific restrictions that users cannot change.persist_with: Link explore cache to datagroups (e.g.,default_datagroup).fields: Use inclusive lists to strictly control content when necessary (ALL_FIELDS*,-view.field).
3. Performance Optimization (Aggregate Tables)
Aggregate Tables (Aggregate Awareness) allow Looker to query smaller, pre-aggregated tables instead of the raw granular data, drastically improving query performance.
Anatomy of an Aggregate Table
explore: orders {
aggregate_table: rollup_name {
query: {
dimensions: [created_date, status]
measures: [total_revenue, count]
filters: [orders.created_date: "6 months"]
}
materialization: {
datagroup_trigger: ecommerce_etl
# partition_keys: ["created_date"] # BigQuery/Presto optimization
# increment_key: "created_date" # Incremental builds
# increment_offset: 3 # Rebuild last 3 periods
}
}
}Key Parameters
- Query: Defines the "shape" of the rollup.
- Dimensions: Include all dimensions commonly used in dashboards (including filters).
- Measures: Include base measures (sum, count). Looker can derive averages from sum+count.
- Filters: Optional. Restricts the rollup to a subset of data (e.g., "last 6 months").
- Materialization:
- datagroup_trigger: (Recommended) Rebuilds when the ETL job completes.
- sql_trigger_value: Rebuilds when a SQL query returns a new value.
- increment_key: (Advanced) Appends new data instead of full rebuilds. Best for massive tables.
- indexes / partition_keys / cluster_keys: Dialect-specific optimizations.
- Best Practices:
- Timeframes: Include the finest grain needed (e.g.,
date). Looker can roll updatetomonthoryearautomatically. - Exact Match: The user's query must be a strict subset of the aggregate table's fields to satisfy the awareness logic.
- Filter Awareness: If a user filters on a field not in the aggregate table, Looker cannot use it (unless it's an "exact match" special case). Add common filter fields to the
dimensionslist.
4. Extending Explores
- Extends: Use
extends: [base_explore]to inherit joins, fields, and descriptions from another explore. - Use Case: Create a "Base" explore with common joins, then "Extended" explores for specific analysis (e.g.,
orders->marketing_orders).
Examples
Basic Explore
explore: orders {
label: "Orders"
description: "Analyze order data, including user and product details."
view_name: orders
join: users {
relationship: many_to_one
sql_on: ${orders.user_id} = ${users.id} ;;
}
}Explore with Filters & Caching
explore: events {
label: "Web Events"
description: "User interaction events."
persist_with: default_datagroup
# Users can change this filter, but it defaults to '7 days'
always_filter: {
filters: [events.created_date: "7 days"]
}
# Users CANNOT change this filter.
sql_always_where: ${events.is_test_data} = false ;;
join: sessions {
relationship: many_to_one
sql_on: ${events.session_id} = ${sessions.session_id} ;;
}
}
## Aggregate Table (Advanced)
explore: orders { aggregatetable: monthlysalessummary { query: { dimensions: [createdmonth, status, products.category] measures: [totalrevenue, count] filters: [orders.createddate: "2 years"] } materialization: { datagrouptrigger: ecommerceetl partitionkeys: ["createdmonth"] incrementkey: "createdmonth" increment_offset: 1 # Rebuild current and previous month } } }
## Extended Explore
explore: ordersextended { extends: [orders] label: "Orders (Marketing View)" viewname: orders
Add new joins specific to this view
join: marketingchannels { sqlon: ${orders.channelid} = ${marketingchannels.id} ;; relationship: manytoone } }
Reference Skills
For more complex scenarios, refer to these specialized skills:
- Advanced Explore Configuration: UNNESTing, lateral flattens, and row-level security.
- Joins Deep Dive: Detailed join types, relationships, and aliasing.




