> ## Documentation Index
> Fetch the complete documentation index at: https://www.osohq.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# List filtering

> Generate filtered lists of authorized resources

List filtering retrieves only the resources a user can access in a single operation, instead of checking each resource individually.

Use it when displaying lists like repositories, issues, or documents, and you need to return only what the current user is allowed to see.

## Approaches

Oso Cloud provides two complementary approaches to list filtering, each optimized for different scales and use cases. Both use the same Polar policies and facts, so you can migrate between them or use both for different resource types.

### Centralized List Filtering

Uses Oso Cloud's `list` API to retrieve authorized resource IDs, which you then use to query your database. All authorization logic and data lives in Oso Cloud.

**How it works:**

1. Request authorized resource IDs from Oso Cloud.
2. Query your database for those IDs.
3. Return the filtered results to your user.

```javascript theme={null}
async function authorizedRepositories(oso: Oso, currentUser: User): Promise<Repository[]> {
  const repositoryIds = await oso.list(
    {type: "User", id: currentUser.id.toString()},
    "view",
    "Repository"
  );
  return getRepositoriesByIds(repositoryIds);
}
```

### Local List Filtering

Uses Oso Cloud's `list_local` API to combine centralized fact evaluation with database-level filtering. Oso Cloud returns SQL `WHERE` clauses you can apply directly to queries.

**How it works:**

1. Oso Cloud evaluates centralized facts (e.g., user roles).
2. Generates a SQL `WHERE` clause for local relationships (e.g., resource ownership).
3. Your database applies both in a single query.

Check out the [local authorization](/reference/api/local-check-api/post-list_query) API for more details.

## When to Use Each Approach

### Use Centralized Filtering when:

* Users typically access hundreds to thousands of resources.
* All authorization facts live in Oso Cloud.
* Simple implementation is preferred.
* Network latency between your app and Oso Cloud is minimal.

### Use Local Filtering when:

* Users access millions of resources.
* You need complex database queries with joins, aggregations, or advanced filtering.
* Network latency between your app and Oso Cloud matters.
* You want to keep resource relationships in your database.
* You need database-level pagination, sorting, or other operations.

## Implementation Requirements

### Centralized List Filtering Setup

Centralized filtering works with your existing Oso Cloud configuration. No additional setup is required beyond your standard client initialization and fact synchronization.

<Note>
  For large result sets, use the [`listPaginated`](/reference/sdks/authorization-checks#list-resources-paginated) method to retrieve results in pages. This gives you control over page size and lets you process results incrementally rather than loading all authorized resource IDs at once.
</Note>

### Local List Filtering Setup

Local filtering requires additional configuration:

1. **Data Bindings Configuration**: Map your local database schema to Oso Cloud resources and relationships.
2. **Client Configuration**: Configure the Oso Cloud client to use local data bindings.
3. **Database Schema Alignment**: Ensure your local database schema matches the relationships defined in your data bindings.

## Performance Characteristics

### Centralized Filtering

* **Optimal Range**: Up to \~10,000 authorized resources per user.
* **Network Overhead**: One API call to Oso Cloud per list operation.
* **Database Impact**: Simple ID-based queries in your database.
* **Memory Usage**: Resource IDs stored in app memory.

### Local Filtering

* **Optimal Range**: Millions of resources per user.
* **Network Overhead**: Minimal - only authorization rules evaluation.
* **Database Impact**: Single query with complex `WHERE` clauses.
* **Memory Usage**: Minimal - filtering happens at database level.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Variables must be constrained to a domain">
    When using the `list` API, all variables in your rule must be constrained to a searchable domain of facts. Oso Cloud only stores facts, not a complete list of all possible actor or resource IDs.

    **Problem**: A rule like this will fail for `list()` queries if `other_user` is unconstrained:

    ```polar theme={null}
    has_permission(user: User, permission: String, other_user: User) if
      has_role(user, "root") and
      permission in ["read", "write"] and
      user != other_user;
    ```

    The `user` and `permission` arguments are constrained (via `has_role` and `in`), but `other_user` has no constraint telling Oso which users to search through.

    You may see an error like:

    ```
    Invalid comparison User{"user_123"} != var2
    ```

    This error indicates that one side of the `!=` comparison is a concrete value (the authenticated user), but the other side (`var2`) is an unconstrained variable with no domain to search.

    **Solution**: Constrain all variables to a domain of facts:

    ```polar theme={null}
    has_permission(user: User, permission: String, other_user: User) if
      has_role(user, "root") and
      permission in ["read", "write"] and
      is_active(other_user) and  # Constrains other_user to a searchable domain
      user != other_user;
    ```

    This works because `is_active(other_user)` gives Oso a set of facts to search through.

    <Note>
      This constraint is only required for `list()` queries. An `authorize()` query with a concrete third argument (e.g., `authorize(User:alice, "read", User:bob)`) will succeed because the value is already known.
    </Note>
  </Accordion>

  <Accordion title="Empty results from `list` API">
    * Verify facts exist using `get_facts()`.
    * Check policy syntax with `query()`.
    * Confirm resource type matches your policy exactly.
    * Validate user permissions are configured.
  </Accordion>

  <Accordion title="Malformed SQL from `list_local`">
    * Validate your local authorization configuration file.
    * Ensure column names match the database schema exactly.
    * Confirm relationships are defined in data bindings.
    * Verify database connection and permissions.
  </Accordion>

  <Accordion title="Performance Issues">
    * Review database indexes on columns used in authorization filters.
    * Monitor query execution plans for optimizations.
    * Apply database-specific optimizations for complex `WHERE` clauses.
  </Accordion>
</AccordionGroup>

## Next Steps

* [Set up Local Authorization](/develop/facts/local-authorization) for `list_local` implementation.
* [Explore API documentation](/reference/api/check-api/post-list) for detailed parameters and options.
* [Review enforcement strategies](/develop/enforce/enforcement-strategies) for broader authorization patterns.

***

Need help implementing list filtering in your application? [Schedule a call with an Oso engineer](https://www.osohq.com/meet-eng?utm_source=cloud-docs\&utm_content=list-filtering).
