# How to Implement Native Filters and Dependent/Cascading Filters in Apache Superset Dashboards

> Learn how to implement native filters and dependent cascading filters in Apache Superset dashboards. Configure filter relationships easily for advanced data exploration.

- Repository: [The Apache Software Foundation/superset](https://github.com/apache/superset)
- Tags: how-to-guide
- Published: 2026-03-03

---

**Native filters in Apache Superset are configured via the `native_filter_configuration` JSON array in dashboard metadata, where dependent filters declare parent relationships through the `cascadeParentIds` property, enabling automatic client-side and server-side cascading behavior.**

Apache Superset’s native filter system allows dashboard builders to create interactive, cascading filter experiences without writing custom SQL. By leveraging the `cascadeParentIds` configuration and the built-in React state management, you can build dependent filters that automatically adjust their available options based on parent selections.

## Understanding the Native Filter Architecture

### Backend Storage and Validation

The dashboard model stores native filter configurations inside the `json_metadata` column. When a dashboard is saved or loaded, Superset validates the `native_filter_configuration` array.

In [`superset/models/dashboard.py`](https://github.com/apache/superset/blob/main/superset/models/dashboard.py) (lines 389-395), the dashboard reads the native filter configuration from the JSON metadata:

```python

# From superset/models/dashboard.py

native_filter_configuration = json_metadata.get("native_filter_configuration", [])

```

The Data Access Object (DAO) layer exposes this configuration via REST endpoints. In [`superset/daos/dashboard.py`](https://github.com/apache/superset/blob/main/superset/daos/dashboard.py) (lines 339-350), the `get_native_filter_configuration` method returns the raw configuration for API consumers:

```python

# From superset/daos/dashboard.py

def get_native_filter_configuration(self, dashboard_id: int) -> list[dict]:
    dashboard = self.get_by_id(dashboard_id)
    return dashboard.json_metadata.get("native_filter_configuration", [])

```

### Frontend State Management

On the frontend, Superset maintains a normalized Redux store for native filters. The state slice defined in [`superset-frontend/src/dashboard/components/nativeFilters/state.ts`](https://github.com/apache/superset/blob/main/superset-frontend/src/dashboard/components/nativeFilters/state.ts) stores each filter keyed by its UUID, including its current value, default value, and configuration.

This centralized state enables any component to access parent filter values when evaluating dependencies.

## Implementing Cascading Dependencies

### Declaring Parent-Child Relationships

Cascading behavior is declared in the filter configuration object through the `cascadeParentIds` array. This array contains the UUIDs of filters that must have values selected before the dependent filter becomes active.

A typical configuration looks like this:

```json
{
  "native_filter_configuration": [
    {
      "id": "NATIVE_FILTER-1",
      "name": "Country",
      "type": "filter_select",
      "targets": [{ "datasetId": 42, "column": { "name": "country" } }],
      "defaultDataMask": { "filterState": { "value": [] } }
    },
    {
      "id": "NATIVE_FILTER-2",
      "name": "City",
      "type": "filter_select",
      "cascadeParentIds": ["NATIVE_FILTER-1"],
      "targets": [{ "datasetId": 42, "column": { "name": "city" } }],
      "defaultDataMask": { "filterState": { "value": [] } }
    }
  ]
}

```

In this example, the **City** filter declares **Country** as its parent via `cascadeParentIds`. Until a user selects a country, the City filter remains disabled or hidden.

### Client-Side Dependency Resolution

The frontend uses a dedicated React hook to resolve parent-child relationships. In [`superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useFilterDependencies.ts`](https://github.com/apache/superset/blob/main/superset-frontend/src/dashboard/components/nativeFilters/FilterCard/useFilterDependencies.ts) (lines 41-49), the `useFilterDependencies` hook reads the `cascadeParentIds` from a filter's configuration and selects the corresponding parent filter objects from the Redux store:

```typescript
// From useFilterDependencies.ts
const useFilterDependencies = (filter: Filter) => {
  const parentIds = filter.cascadeParentIds ?? [];
  const parentFilters = useSelector((state: State) =>
    parentIds.map(id => state.nativeFilters.filters[id]),
  );
  return parentFilters;
};

```

This hook enables UI components to determine if a filter should be disabled based on whether all parent filters have selected values.

### Automatic Value Reset on Parent Change

When a parent filter value changes, Superset automatically resets dependent filter values to prevent stale selections. This logic resides in [`superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx`](https://github.com/apache/superset/blob/main/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterValue.tsx) (lines 184-190):

```typescript
// From FilterValue.tsx
if ((filter.cascadeParentIds ?? []).length) {
  (filter.cascadeParentIds ?? []).forEach(parentId => {
    const parent = filters[parentId];
    // Logic that clears dependent filter if parent value becomes empty
    if (!parent?.defaultDataMask?.filterState?.value?.length) {
      // Reset current filter value
    }
  });
}

```

This ensures data consistency: if a user clears the **Country** selection, the **City** filter automatically clears its value and becomes disabled until a new country is chosen.

## Configuration via the UI

### Setting Dependencies in the Filter Modal

Dashboard editors configure cascading relationships through the **Filters Config Modal**. In [`superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx`](https://github.com/apache/superset/blob/main/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx) (lines 325-327), the form stores the selected parent IDs in the `cascadeParentIds` array:

```typescript
// From FiltersConfigForm.tsx
const dependencies = formFilter?.dependencies || filterToEdit?.cascadeParentIds || [];

```

When a user selects "Depends on" in the UI, the modal populates this array and persists it to the dashboard's `json_metadata` upon saving.

## Practical Implementation Example

Below is a complete example showing both the JSON configuration and a custom React component that respects cascading dependencies.

### Dashboard JSON Configuration

```json
{
  "native_filter_configuration": [
    {
      "id": "NATIVE_FILTER-REGION",
      "name": "Sales Region",
      "type": "filter_select",
      "targets": [{ "datasetId": 15, "column": { "name": "region" } }],
      "defaultDataMask": { "filterState": { "value": [] } }
    },
    {
      "id": "NATIVE_FILTER-TERRITORY",
      "name": "Sales Territory",
      "type": "filter_select",
      "cascadeParentIds": ["NATIVE_FILTER-REGION"],
      "targets": [{ "datasetId": 15, "column": { "name": "territory" } }],
      "defaultDataMask": { "filterState": { "value": [] } }
    }
  ]
}

```

### Custom Filter Component with Dependency Support

```tsx
import React from 'react';
import { Filter } from '@superset-ui/core';
import { useFilterDependencies } from 'src/dashboard/components/nativeFilters/FilterCard/useFilterDependencies';
import { Select } from '@superset-ui/core';

interface Props {
  filter: Filter;
  onChange: (value: any) => void;
}

export const CascadingSelect: React.FC<Props> = ({ filter, onChange }) => {
  const parentFilters = useFilterDependencies(filter);

  const isDisabled = parentFilters.some(
    p => !(p?.defaultDataMask?.filterState?.value?.length),
  );

  return (
    <Select
      placeholder={filter.name}
      disabled={isDisabled}
      value={filter.defaultDataMask?.filterState?.value ?? []}
      onChange={onChange}
      options={[]} // Options fetched dynamically based on parent selections
    />
  );
};

```

When this component is rendered inside Superset's `FilterCard`, it automatically disables the **Sales Territory** dropdown until a **Sales Region** is selected, and clears the territory value if the region is cleared.

## Summary

- **Native filters** are stored in `native_filter_configuration` within a dashboard's `json_metadata`, as defined in [`superset/models/dashboard.py`](https://github.com/apache/superset/blob/main/superset/models/dashboard.py).
- **Cascading dependencies** are declared via the `cascadeParentIds` array, which lists the UUIDs of parent filters that must have values before the child filter activates.
- **Client-side enforcement** occurs through the `useFilterDependencies` hook in [`useFilterDependencies.ts`](https://github.com/apache/superset/blob/main/useFilterDependencies.ts), which selects parent filters from the Redux store and determines if the current filter should be disabled.
- **Value reset logic** in [`FilterValue.tsx`](https://github.com/apache/superset/blob/main/FilterValue.tsx) automatically clears dependent filter selections when parent values change, preventing stale data.
- **UI configuration** is handled by [`FiltersConfigForm.tsx`](https://github.com/apache/superset/blob/main/FiltersConfigForm.tsx), which persists the `cascadeParentIds` array to the dashboard metadata when users select "Depends on" in the filter modal.

## Frequently Asked Questions

### What is the difference between native filters and filter boxes in Superset?

Native filters are the modern, recommended approach for dashboard filtering in Apache Superset, replacing the legacy "filter box" visualization type. Native filters are defined in the dashboard's `json_metadata` under `native_filter_configuration` and offer superior performance, cascading dependencies via `cascadeParentIds`, and better integration with the dashboard layout. Filter boxes are deprecated visualizations that require adding a special chart to the dashboard and do not support the modern dependency system.

### How does Superset handle cascading filter queries on the backend?

When a dashboard loads or updates, the backend receives the current state of all native filters, including their dependencies. The SQL query generation layer uses the `cascadeParentIds` configuration to ensure that dependent filters only query data filtered by parent selections. The `Dashboard` model in [`superset/models/dashboard.py`](https://github.com/apache/superset/blob/main/superset/models/dashboard.py) validates that all `cascadeParentIds` reference existing filter IDs when the dashboard is saved, ensuring referential integrity between parent and child filters.

### Can a filter have multiple parent dependencies?

Yes, the `cascadeParentIds` property is an array that supports multiple parent filter IDs. A dependent filter will only become enabled when **all** specified parent filters have selected values. The `useFilterDependencies` hook in [`useFilterDependencies.ts`](https://github.com/apache/superset/blob/main/useFilterDependencies.ts) iterates through all parent IDs and checks that each has a non-empty `filterState.value` before allowing the child filter to activate. This design supports complex filtering scenarios where a selection depends on multiple upstream criteria.

### Where is the cascade configuration stored in the database?

The cascading relationship configuration is stored in the `json_metadata` column of the `dashboards` table in the Superset metadata database. Specifically, it resides within the `native_filter_configuration` array as the `cascadeParentIds` field on individual filter objects. When a dashboard is saved via the REST API (`PUT /api/v1/dashboard/<id>`), the `Dashboard` model in [`superset/models/dashboard.py`](https://github.com/apache/superset/blob/main/superset/models/dashboard.py) validates and persists this JSON structure, ensuring that `cascadeParentIds` reference valid filter IDs within the same configuration.