> ## Documentation Index
> Fetch the complete documentation index at: https://cubed3-feat-druid-driver-streaming.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration options

> Following configuration options can be defined either using Python, in a cube.py file, or using JavaScript, in a cube.js file.

<Info>
  Note that configuration options follow the [snake case][link-snake-case]
  convention in Python (`base_path`) and the [camel case][link-camel-case] convention in
  JavaScript (`basePath`).
</Info>

Every configuration option that is a function (e.g., `query_rewrite`)
can be defined as either synchronous or asynchronous. Cube will await for
the completion of asynchronous functions.

It's wise to make functions that are called on each request as fast as
possible to minimize the performance hit. Consider using caching when
applicable and performing calculations outside of these functions.

## Data model

### `schema_path`

Path to data model files.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.schema_path = 'my-data-model'
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    schemaPath: 'my-data-model'
  }
  ```
</CodeGroup>

This configuration option can also be set using the [`CUBEJS_SCHEMA_PATH`](/reference/configuration/environment-variables#cubejs_schema_path)
environment variable. The default value is `model`.

Use [`repositoryFactory`][self-repofactory] for [multitenancy][ref-multitenancy]
or when a more flexible setup is needed.

### `context_to_app_id`

It's a [multitenancy][ref-multitenancy] option.

`context_to_app_id` is a function to determine an app id which is used as
caching key for various in-memory structures like data model compilation
results, etc.

Called on each request.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('context_to_app_id')
  def context_to_app_id(ctx: dict) -> str:
    return f"CUBE_APP_{ctx['securityContext']['tenant_id']}"
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    contextToAppId: ({ securityContext }) => {
      return `CUBE_APP_${securityContext.tenant_id}`
    }
  }
  ```
</CodeGroup>

### `repository_factory`

This option allows to customize the repository for Cube data model files.
It is a function, which accepts a context object and can dynamically provide
data model files. Learn more about it in [multitenancy][ref-multitenancy].

Called only once per [`app_id`][self-opts-ctx-to-appid].

You can use convenient `file_repository` implementation to read files
from a specified path:

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config, file_repository

  @config('repository_factory')
  def repository_factory(ctx: dict) -> list[dict]:
    return file_repository(f"model/{ctx['securityContext']['tenant_id']}")


  ```

  ```javascript title="JavaScript" theme={null}
  const { FileRepository } = require("@cubejs-backend/server-core")

  module.exports = {
    repositoryFactory: ({ securityContext }) => {
      return new FileRepository(`model/${securityContext.tenant_id}`)
    }
  }
  ```
</CodeGroup>

You can also provide file contents directly, e.g., after fetching them
from a remote storage or via an API:

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config, file_repository

  @config('repository_factory')
  def repository_factory(ctx: dict) -> list[dict]:
    context = ctx['securityContext']

    return [
      {
        'fileName': 'file.js',
        'content': 'contents of file'
      }
    ]

  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    repositoryFactory: ({ securityContext }) => {
      return {
        dataSchemaFiles: async () =>
          await Promise.resolve([
            {
              fileName: 'file.js',
              content: 'contents of file'
            }
          ])
      }
    }
  }
  ```
</CodeGroup>

### `schema_version`

`schema_version` can be used to tell Cube that the data model should be recompiled
in case it depends on dynamic definitions fetched from some external database or
API.

This method is called on each request however `RequestContext` parameter is
reused per application ID as determined by
[`context_to_app_id`][self-opts-ctx-to-appid]. If the returned string is different,
the data model will be recompiled. It can be used in both multi-tenant and
single tenant environments.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config
  import random

  @config('schema_version')
  def schema_version(ctx: dict) -> str:
    # Don't do this!
    # Data model would be recompiled on each request
    context = ctx['securityContext']

    return random.random()
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    schemaVersion: ({ securityContext }) => {
      // Don't do this!
      // Data model would be recompiled on each request
      return Math.random()
    }
  }



  ```
</CodeGroup>

### `compiler_cache_size`

Maximum number of compiled data models to persist with in-memory cache. Defaults
to 250, but optimum value will depend on deployed environment. When the max is
reached, will start dropping the least recently used data models from the cache.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.compiler_cache_size = 100
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    compilerCacheSize: 100
  }
  ```
</CodeGroup>

### `max_compiler_cache_keep_alive`

Maximum length of time in ms to keep compiled data models in memory. Default
keeps data models in memory indefinitely.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.max_compiler_cache_keep_alive = 10000
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    maxCompilerCacheKeepAlive: 10000
  }
  ```
</CodeGroup>

### `update_compiler_cache_keep_alive`

Setting `update_compiler_cache_keep_alive` to `True` keeps frequently used data models
in memory by reseting their `max_compiler_cache_keep_alive` every time they are
accessed.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.update_compiler_cache_keep_alive = True
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    updateCompilerCacheKeepAlive: true
  }
  ```
</CodeGroup>

### `allow_js_duplicate_props_in_schema`

Boolean to enable or disable a check duplicate property names in all objects of
a data model. The default value is `false`, and it is means the compiler would
use the additional transpiler for check duplicates.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.allow_js_duplicate_props_in_schema = True
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    allowJsDuplicatePropsInSchema: true
  }
  ```
</CodeGroup>

## Query cache & queue

### `cache_and_queue_driver`

The cache and queue driver to use for the Cube deployment. Defaults to
`memory` in development, `cubestore` in production.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.cache_and_queue_driver = 'cubestore'
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    cacheAndQueueDriver: 'cubestore'
  }
  ```
</CodeGroup>

This configuration option can also be set using the [`CUBEJS_CACHE_AND_QUEUE_DRIVER`](/reference/configuration/environment-variables#cubejs_cache_and_queue_driver)
environment variable.

### `context_to_orchestrator_id`

<Warning>
  In versions of Cube prior to v0.29, each tenant would have an individual
  instance of the query orchestrator.
</Warning>

`context_to_orchestrator_id` is a function used to determine a caching key for the
query orchestrator instance. The query orchestrator holds database connections,
execution queues, pre-aggregation table caches. By default, the same instance is
used for **all** tenants; override this property in situations where each tenant
requires their own Query Orchestrator.

<Warning>
  Please remember to override
  [`pre_aggregations_schema`][self-pre-aggregations-schema] if you override
  `context_to_orchestrator_id`. Otherwise, you end up with table name clashes for
  your pre-aggregations.
</Warning>

Called on each request.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('context_to_app_id')
  def context_to_app_id(ctx: dict) -> str:
    return f"CUBE_APP_{ctx['securityContext']['tenant_id']}"

  @config('context_to_orchestrator_id')
  def context_to_orchestrator_id(ctx: dict) -> str:
    return f"CUBE_APP_{ctx['securityContext']['tenant_id']}"
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    contextToAppId: ({ securityContext }) => {
      return `CUBE_APP_${securityContext.tenant_id}`
    },

    contextToOrchestratorId: ({ securityContext }) => {
      return `CUBE_APP_${securityContext.tenant_id}`
    }
  }
  ```
</CodeGroup>

### `context_to_cube_store_router_id`

`context_to_cube_store_router_id` is a function used to determine which Cube Store
router a request is routed to. It returns a string id that is used as a routing
key: requests that resolve to the same id share the same Cube Store router, while
distinct ids are routed to separate routers.

This is only relevant for deployments running multiple Cube Store routers (for
example, when [tenants][ref-multitenancy] are partitioned across routers to
isolate their pre-aggregation storage and query load). By default this function
is not set, and all requests use the same Cube Store router.

<Warning>
  `context_to_cube_store_router_id` requires
  [`context_to_orchestrator_id`][self-orchestrator-id] to also be defined.
</Warning>

Called on each request.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('context_to_cube_store_router_id')
  def context_to_cube_store_router_id(ctx: dict) -> str:
    return f"CUBE_ROUTER_{ctx['securityContext']['tenant_id']}"
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    contextToCubeStoreRouterId: ({ securityContext }) => {
      return `CUBE_ROUTER_${securityContext.tenant_id}`
    }
  }
  ```
</CodeGroup>

### `driver_factory`

A function to provide a custom configuration for the data source driver.

Called once per [`data_source`][ref-schema-ref-datasource] for every
[orchestrator id][self-orchestrator-id].

Should be used to configure data source connections **dynamically** in
[multitenancy][ref-multitenancy].

Not recommended to be used when [multiple data sources][ref-multiple-data-sources]
can be configured **statically**. Use [`CUBEJS_DATASOURCES`](/reference/configuration/environment-variables#cubejs_datasources) and decorated environment
variables in that case.

In Python, should return a dictionary; in JavaScript, should return an object.
It should contain the `type` element corresponding to data source type and other
options that will be passed to a data source driver. You can lookup supported options
in the drivers' [source code][link-github-cube-drivers].

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('driver_factory')
  def driver_factory(ctx: dict) -> None:
    context = ctx['securityContext']
    data_source = ctx['dataSource']
   
    return {
      'type': 'postgres',
      'host': 'demo-db-examples.cube.dev',
      'user': 'cube',
      'password': '12345',
      'database': data_source
    }
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    driverFactory: ({ securityContext, dataSource }) => {
      return {
        type: 'postgres',
        host: 'demo-db-examples.cube.dev',
        user: 'cube',
        password: '12345',
        database: dataSource
      }
    }
  }



  ```
</CodeGroup>

In JavaScript, custom driver implementations can also be loaded:

```javascript theme={null}
const VeryCustomDriver = require('cube-custom-driver')

module.exports = {
  driverFactory: ({ securityContext, dataSource }) => {
    return new VeryCustomDriver({
      /* options */
    })
  }
}
```

### `orchestrator_options`

<Warning>
  We **strongly** recommend leaving these options set to the defaults. Changing
  these values can result in application instability and/or downtime.
</Warning>

You can pass this object to set advanced options for the query orchestrator.

| Option                                         | Description                                                                                                                                                                                                                                                                                                                                                                                       | Default Value           |
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
| `continueWaitTimeout`                          | Long polling interval in seconds, maximum is 90                                                                                                                                                                                                                                                                                                                                                   | `5`                     |
| `rollupOnlyMode`                               | When enabled, an error will be thrown if a query can't be served from a pre-aggregation (rollup)                                                                                                                                                                                                                                                                                                  | `false`                 |
| `queryCacheOptions`                            | Query cache options for DB queries                                                                                                                                                                                                                                                                                                                                                                | `{}`                    |
| `queryCacheOptions.refreshKeyRenewalThreshold` | Time in seconds to cache the result of [`refresh_key`][ref-schema-cube-ref-refresh-key] check                                                                                                                                                                                                                                                                                                     | `defined by DB dialect` |
| `queryCacheOptions.backgroundRenew`            | Controls whether to wait in foreground for refreshed query data if `refresh_key` value has been changed. Refresh key queries or pre-aggregations are never awaited in foreground and always processed in background unless cache is empty. If `true` it immediately returns values from cache if available without [`refresh_key`][ref-schema-cube-ref-refresh-key] check to renew in foreground. | `false`                 |
| `queryCacheOptions.queueOptions`               | Query queue options for DB queries                                                                                                                                                                                                                                                                                                                                                                | `{}`                    |
| `preAggregationsOptions`                       | Query cache options for pre-aggregations                                                                                                                                                                                                                                                                                                                                                          | `{}`                    |
| `preAggregationsOptions.maxPartitions`         | The maximum number of partitions each pre-aggregation in a cube can use.                                                                                                                                                                                                                                                                                                                          | `10000`                 |
| `preAggregationsOptions.queueOptions`          | Query queue options for pre-aggregations                                                                                                                                                                                                                                                                                                                                                          | `{}`                    |
| `preAggregationsOptions.externalRefresh`       | When running a separate instance of Cube to refresh pre-aggregations in the background, this option can be set on the API instance to prevent it from trying to check for rollup data being current - it won't try to create or refresh them when this option is `true`                                                                                                                           | `false`                 |

`queryCacheOptions` are used while querying database tables, while
`preAggregationsOptions` settings are used to query pre-aggregated tables.

<Warning>
  Setting these options is highly discouraged as these are considered to be
  system-level settings. Please use [`CUBEJS_ROLLUP_ONLY`](/reference/configuration/environment-variables#cubejs_rollup_only), [`CUBEJS_DB_QUERY_TIMEOUT`](/reference/configuration/environment-variables#cubejs_db_query_timeout), and
  [`CUBEJS_CONCURRENCY`](/reference/configuration/environment-variables#cubejs_concurrency) [environment variables][ref-environment-variables] instead.
</Warning>

Timeout and interval options' values are in seconds.

| Option              | Description                                                                                                                                                                                                                                                                                             | Default Value |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `concurrency`       | Maximum number of queries to be processed simultaneosly. For drivers with connection pool [`CUBEJS_DB_MAX_POOL`](/reference/configuration/environment-variables#cubejs_db_max_pool) should be adjusted accordingly. Typically pool size should be at least twice of total concurrency among all queues. | `2`           |
| `executionTimeout`  | Total timeout of single query                                                                                                                                                                                                                                                                           | `600`         |
| `orphanedTimeout`   | Query will be marked for cancellation if not requested during this period.                                                                                                                                                                                                                              | `120`         |
| `heartBeatInterval` | Worker heartbeat interval. If `4*heartBeatInterval` time passes without reporting, the query gets cancelled.                                                                                                                                                                                            | `30`          |

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.orchestrator_options = {
    'continueWaitTimeout': 10,
    'rollupOnlyMode': False,
    'queryCacheOptions': {
      'refreshKeyRenewalThreshold': 30,
      'backgroundRenew': True,
      'queueOptions': {
        'concurrency': 3,
        'executionTimeout': 1000,
        'orphanedTimeout': 1000,
        'heartBeatInterval': 1000
      }
    },
    'preAggregationsOptions': {
      'externalRefresh': False,
      'maxPartitions': 100,
      'queueOptions': {
        'concurrency': 3,
        'executionTimeout': 1000,
        'orphanedTimeout': 1000,
        'heartBeatInterval': 1000
      }
    }
  }
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    orchestratorOptions: {
      continueWaitTimeout: 10,
      rollupOnlyMode: false,
      queryCacheOptions: {
        refreshKeyRenewalThreshold: 30,
        backgroundRenew: true,
        queueOptions: {
          concurrency: 3,
          executionTimeout: 1000,
          orphanedTimeout: 1000,
          heartBeatInterval: 1000
        }
      },
      preAggregationsOptions: {
        externalRefresh: false,
        maxPartitions: 100,
        queueOptions: {
          concurrency: 3,
          executionTimeout: 1000,
          orphanedTimeout: 1000,
          heartBeatInterval: 1000
        }
      }
    }
  }
  ```
</CodeGroup>

## Pre-aggregations

### `pre_aggregations_schema`

Database schema name to use for storing pre-aggregations.

Either string or function can be passed. Providing a function allows to set
the schema name dynamically depending on the security context.

Defaults to `dev_pre_aggregations` in [development mode][ref-development-mode]
and `prod_pre_aggregations` in production.

<Info>
  In Cube Cloud, all [environments][ref-environments] share the same pre-aggregations schema name by default.
  This allows reusing pre-aggregations across environments, saving both time and cost.
</Info>

This configuration option can also be set using the [`CUBEJS_PRE_AGGREGATIONS_SCHEMA`](/reference/configuration/environment-variables#cubejs_pre_aggregations_schema)
environment variable.

<Warning>
  It's **strongly** recommended to use different pre-aggregation schemas in
  development and production environments to avoid pre-aggregation table clashes.
</Warning>

<Warning>
  Cube will wipe out the contents of this database schema before use. It shall
  be used exclusively by Cube and shall not be shared with any application.
</Warning>

Called once per [`app_id`][self-opts-ctx-to-appid].

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('pre_aggregations_schema')
  def pre_aggregations_schema(ctx: dict) -> str:
    return f"pre_aggregations_{ctx['securityContext']['tenant_id']}"
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    preAggregationsSchema: ({ securityContext }) => {
      return `pre_aggregations_${securityContext.tenant_id}`
    }
  }
  ```
</CodeGroup>

### `scheduled_refresh_timer`

<Warning>
  This is merely a refresh worker's heartbeat. It doesn't affect the freshness of
  pre-aggregations or refresh keys, nor how frequently Cube accesses the database.
  Setting this value to `30s` doesn't mean pre-aggregations or in-memory cache
  would be refreshed every 30 seconds but instead refresh key is checked for
  freshness every 30 seconds in the background. Please consult the [cube
  `refresh_key` documentation][ref-schema-cube-ref-refresh-key] and
  [pre-aggregation `refresh_key` documentation][ref-pre-aggregations-refresh-key]
  on how to set data refresh intervals.
</Warning>

<Warning>
  Setting this variable enables refresh worker mode, which means it shouldn't
  usually be set to any constant number but depend on your cluster environment.
  Setting it to the constant value in the cluster environment will lead to the
  instantiation of Refresh Worker on every Cube instance of your cluster,
  including API ones. This will usually lead to refreshing race conditions and to
  out of memory errors.
</Warning>

Cube enables background refresh by default using the [`CUBEJS_REFRESH_WORKER`](/reference/configuration/environment-variables#cubejs_refresh_worker)
environment variable.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.scheduled_refresh_timer = 60
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    scheduledRefreshTimer: 60
  }
  ```
</CodeGroup>

Best practice is to run `scheduled_refresh_timer` in a separate worker Cube
instance.

You may also need to configure
[`scheduledRefreshTimeZones`](#scheduled_refresh_time_zones) and
[`scheduledRefreshContexts`](#scheduled_refresh_contexts).

### `scheduled_refresh_time_zones`

This option specifies a list of time zones that pre-aggregations will be built
for. It has impact on [pre-aggregation matching][ref-matching-preaggs].

Either an array or function returning an array can be passed. Providing a function
allows to set the time zones dynamically depending on the security context.

Time zones should be specified in the [TZ Database Name][link-wiki-tz] format,
e.g., `America/Los_Angeles`.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  # An array of time zones
  config.scheduled_refresh_time_zones = [
    'America/Vancouver',
    'America/Toronto'
  ]

  # Alternatively, a function returning an array of time zones
  @config('scheduled_refresh_time_zones')
  def scheduled_refresh_time_zones(ctx: dict) -> list[str]:
    time_zones = {
      'tenant_1': ['America/New_York'],
      'tenant_2': ['America/Chicago'],
      'tenant_3': ['America/Los_Angeles']
    }
    default_time_zones = ['UTC']
    tenant_id = ctx['securityContext']['tenant_id']
    return time_zones.get(tenant_id, default_time_zones)
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    // An array of time zones
    scheduledRefreshTimeZones: [
      'America/Vancouver',
      'America/Toronto'
    ],

    // Alternatively, a function returning an array of time zones
    scheduledRefreshTimeZones: ({ securityContext }) => {
      let time_zones = {
        'tenant_1': ['America/New_York'],
        'tenant_2': ['America/Chicago'],
        'tenant_3': ['America/Los_Angeles']
      }
      let default_time_zones = ['UTC']  
      let tenant_id = securityContext.tenant_id
      return time_zones[tenant_id] || default_time_zones
    }
  }
  ```
</CodeGroup>

The default value is a list of a single time zone: `UTC`.

This configuration option can also be set using the
[`CUBEJS_SCHEDULED_REFRESH_TIMEZONES`](/reference/configuration/environment-variables#cubejs_scheduled_refresh_timezones) environment variable.

### `scheduled_refresh_contexts`

When trying to configure scheduled refreshes for pre-aggregations that use the
`securityContext` inside `context_to_app_id` or `context_to_orchestrator_id`, you must
also set up `scheduled_refresh_contexts`. This will allow Cube to generate the
necessary security contexts prior to running the scheduled refreshes.

<Warning>
  Leaving `scheduled_refresh_contexts` unconfigured will lead to issues where the
  security context will be `undefined`. This is because there is no way for Cube
  to know how to generate a context without the required input.
</Warning>

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('scheduled_refresh_contexts')
  def scheduled_refresh_contexts() -> list[object]:
    return [
      {
        'securityContext': {
          'tenant_id': 123,
          'bucket': 'demo'
        }
      },
      {
        'securityContext': {
          'tenant_id': 456,
          'bucket': 'demo_2'
        }
      }
    ]
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    scheduledRefreshContexts: () => [
      {
        securityContext: {
          tenant_id: 123,
          bucket: 'demo'
        }
      },
      {
        securityContext: {
          tenant_id: 456,
          bucket: 'demo_2'
        }
      }
    ]
  }


  ```
</CodeGroup>

## Querying

### `query_rewrite`

This is a security hook to check your query just before it gets processed. You
can use this very generic API to implement any type of custom security checks
your app needs and rewrite input query accordingly.

Called on each request.

For example, you can use `query_rewrite` to add row-level security filter, if
needed:

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('query_rewrite')
  def query_rewrite(query: dict, ctx: dict) -> dict:
    context = ctx['securityContext']

    if 'filter_by_region' in context:
      query['filters'].append({
        'member': 'regions.id',
        'operator': 'equals',
        'values': [context['region_id']],
      })

    return query
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    queryRewrite: (query, { securityContext }) => {
      if (securityContext.filter_by_region) {
        query.filters.push({
          member: 'regions.id',
          operator: 'equals',
          values: [securityContext.region_id]
        })
      }
      return query
    }
  }


  ```
</CodeGroup>

Raising an exception would prevent a query from running:

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('query_rewrite')
  def query_rewrite(query: dict, ctx: dict) -> dict:
    raise Exception('You shall not pass! 🧙')
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    queryRewrite: (query, { securityContext }) => {
      throw new Error('You shall not pass! 🧙')
    }
  }
  ```
</CodeGroup>

<Note>
  Currently, there's no built-in way to access the data model metadata in
  `query_rewrite`. Please [track this issue](https://github.com/cube-js/cube/issues/4118)
  and read about a [workaround](https://github.com/cube-js/cube/issues/4118#issuecomment-2317925444).
</Note>

### `allow_ungrouped_without_primary_key`

Setting `allow_ungrouped_without_primary_key` to `True` disables the primary
key inclusion check for [ungrouped queries][ref-ungrouped-query].

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.allow_ungrouped_without_primary_key = True
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    allowUngroupedWithoutPrimaryKey: true
  }
  ```
</CodeGroup>

This configuration option can also be set using the
[`CUBEJS_ALLOW_UNGROUPED_WITHOUT_PRIMARY_KEY`](/reference/configuration/environment-variables#cubejs_allow_ungrouped_without_primary_key) environment variable.

<Info>
  When query pushdown in the SQL API is enabled via the `CUBESQL_SQL_PUSH_DOWN`
  environment variable, this option is enabled as well for the best user experience.
</Info>

## APIs

### `base_path`

The base path for the [REST (JSON) API](/reference/core-data-apis/rest-api/reference).

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.base_path = '/cube-api'
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    basePath: '/cube-api'
  }
  ```
</CodeGroup>

The default value is `/cubejs-api`.

### `http.cors`

CORS settings for the Cube REST (JSON) API can be configured by providing an object
with options [from here][link-express-cors-opts]:

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.http = {
    'cors': {
      'origin': '*',
      'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
      'preflightContinue': False,
      'optionsSuccessStatus': 204,
      'maxAge': 86400,
      'credentials': True
    }
  }
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    http: {
      cors: {
        origin: '*',
        methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
        preflightContinue: false,
        optionsSuccessStatus: 204,
        maxAge: 86400,
        credentials: true
      }
    }
  }
  ```
</CodeGroup>

### `web_sockets_base_path`

The base path for the [WebSocket server][ref-websockets].

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.web_sockets_base_path = '/websocket'
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    webSocketsBasePath: '/websocket'
  }
  ```
</CodeGroup>

The default value is `/` (the root path).

### `process_subscriptions_interval`

This property controls how often WebSocket client subscriptions are refreshed.
Defaults to `5000`.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.process_subscriptions_interval = 1000
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    processSubscriptionsInterval: true
  }
  ```
</CodeGroup>

### `context_to_api_scopes`

This function is used to select accessible [API scopes][ref-rest-scopes]
and effectively allow or disallow access to REST (JSON) API endpoints, based on
the [security context][ref-sec-ctx].

Security context is provided as the first argument. An array of scopes that
was set via [`CUBEJS_DEFAULT_API_SCOPES`](/reference/configuration/environment-variables#cubejs_default_api_scopes) is provided as the second argument.

Called on each request.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('context_to_api_scopes')
  def context_to_api_scopes(context: dict, default_scopes: list[str]) -> list[str]:
    return ['meta', 'data', 'graphql', 'sql']
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    contextToApiScopes: (securityContext, defaultScopes) => {
      return ['meta', 'data', 'graphql', 'sql']
    }
  }
  ```
</CodeGroup>

### `extend_context`

This function is used to extend the security context with additional data.

Called on each request.

It should return an object which gets appended to the *request context*,
an object that contains `securityContext` and that is passed as an argument to
other functions like `context_to_app_id` or `repository_factory`.

<Info>
  When using `extend_context`, you should also define [`context_to_app_id`][self-opts-ctx-to-appid]
  so that all possible values of the extended context are reflected in the app id.
</Info>

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config
   
  @config('extend_context')
  def extend_context(req: dict) -> dict:
    req.setdefault('securityContext', {}).update({'active_organization': 123})
    # req.setdefault('securityContext', {}).update({'active_organization': req['headers']['active_organization']})
    return req
   
  @config('context_to_app_id')
  def context_to_app_id(ctx: dict) -> dict:
    return f"CUBE_APP_{ctx['securityContext']['active_organization']}"
   
   
   

  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    extendContext: (req) => {
      return {
        securityContext: {
          ...req.securityContext,
          active_organization: 123
          // active_organization: req.headers.active_organization
        }
      }
    },

    contextToAppId: ({ securityContext }) => {
      return `CUBE_APP_${securityContext.active_organization}`
    }
  }
  ```
</CodeGroup>

You can use the custom value from extend context in your data model like this:

<CodeGroup>
  ```yaml title="YAML" theme={null}
  {% set securityContext = COMPILE_CONTEXT['securityContext'] %}

  cubes:
    - name: users
      sql: |
        SELECT *
        FROM users
        WHERE organization_id={{ securityContext['active_organization'] }}

  ```

  ```javascript title="JavaScript" theme={null}
  const { securityContext } = COMPILE_CONTEXT

  cube(`users`, {
    sql: `
      SELECT *
      FROM users
      WHERE organization_id=${securityContext.active_organization}
    `
  })
  ```
</CodeGroup>

<Info>
  `extend_context` is applied only to requests that go through APIs. It isn't
  applied to refresh worker execution. If you're looking for a way to provide
  global environment variables for your data model, please see the [execution
  environment documentation][ref-exec-environment-globals].
</Info>

### `check_auth`

Used in the [REST (JSON) API][ref-rest-api]. Default implementation parses the [JSON
Web Token][link-jwt] in the `Authorization` header, verifies it, and sets its
payload to the `securityContext`. [Read more][ref-sec-ctx] about JWT generation.

Called on each request.

You can return an object with the `security_context` field if you want to
customize [`SECURITY_CONTEXT`][ref-schema-cube-ref-ctx-sec-ctx].

You can use empty `check_auth` function to disable built-in security or
raise an exception to fail the authentication check.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('check_auth')
  def check_auth(ctx: dict, token: str) -> None:
    if token == 'my_secret_token':
      return {
        'security_context': {
          'user_id': 42
        }
      }

    raise Exception('Access denied')
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    checkAuth: (ctx, token) => {
      if (token === 'my_secret_token') {
        return {
          security_context: {
            user_id: 42
          }
        }
      }

      throw new Error('Access denied')
    }
  }

  ```
</CodeGroup>

<Note>
  Currently, raising an exception would result in an HTTP response with the
  status code 500 for Cube Core and 403 for Cube Cloud.
  Please [track this issue](https://github.com/cube-js/cube/issues/8136).
</Note>

### `jwt`

```typescript theme={null}
  jwt: {
    jwkUrl?: ((payload: any) => string) | string;
    key?: string;
    algorithms?: string[];
    issuer?: string[];
    audience?: string;
    subject?: string;
    claimsNamespace?: string;
  };
```

| Option            | Description                                                                                                                                         | Environment variable                                                                                                              |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `jwkUrl`          | URL from which JSON Web Key Sets (JWKS) can be retrieved                                                                                            | Can also be set using [`CUBEJS_JWK_URL`](/reference/configuration/environment-variables#cubejs_jwk_url)                           |
| `key`             | JSON string that represents a cryptographic key. Similar to [`CUBEJS_API_SECRET`](/reference/configuration/environment-variables#cubejs_api_secret) | Can also be set using [`CUBEJS_JWT_KEY`](/reference/configuration/environment-variables#cubejs_jwt_key)                           |
| `algorithms`      | [Any supported algorithm for decoding JWTs][gh-jsonwebtoken-algs]                                                                                   | Can also be set using [`CUBEJS_JWT_ALGS`](/reference/configuration/environment-variables#cubejs_jwt_algs)                         |
| `issuer`          | Issuer value which will be used to enforce the [`iss` claim from inbound JWTs][link-jwt-ref-iss]                                                    | Can also be set using [`CUBEJS_JWT_ISSUER`](/reference/configuration/environment-variables#cubejs_jwt_issuer)                     |
| `audience`        | Audience value which will be used to enforce the [`aud` claim from inbound JWTs][link-jwt-ref-aud]                                                  | Can also be set using [`CUBEJS_JWT_AUDIENCE`](/reference/configuration/environment-variables#cubejs_jwt_audience)                 |
| `subject`         | Subject value which will be used to enforce the [`sub` claim from inbound JWTs][link-jwt-ref-sub]                                                   | Can also be set using [`CUBEJS_JWT_SUBJECT`](/reference/configuration/environment-variables#cubejs_jwt_subject)                   |
| `claimsNamespace` | Namespace within the decoded JWT under which any custom claims can be found                                                                         | Can also be set using [`CUBEJS_JWT_CLAIMS_NAMESPACE`](/reference/configuration/environment-variables#cubejs_jwt_claims_namespace) |

### `check_sql_auth`

Used in the [SQL API][ref-sql-api]. Default
implementation verifies user name and password from environment variables:
[`CUBEJS_SQL_USER`](/reference/configuration/environment-variables#cubejs_sql_user), [`CUBEJS_SQL_PASSWORD`](/reference/configuration/environment-variables#cubejs_sql_password), but in [development
mode][ref-development-mode] it ignores validation.

Called on each new connection to Cube SQL API, on change user by `SET USER` or `__user` field, every `CUBESQL_AUTH_EXPIRE_SECS`.

For example, you can use `check_sql_auth` to validate username and password.
`password` argument is provided only when new connections are established.
`check_sql_auth` implementation should gracefully handle missing `password` field to handle change user and re-authentication flows.
`check_sql_auth` should always return `password` as it used for validation of password provided by user.
If clear text password can't be obtained, best practice is to return `password` provided as an argument after password validation.
Only security context is used for change user and re-authentication flows so returned `password` isn't checked in this case.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('check_sql_auth')
  def check_sql_auth(req: dict, user_name: str, password: str) -> dict:
    if user_name == 'my_user':
      if password and password != 'my_password':
        raise Exception('Access denied')
      return {
        'password': password,
        'securityContext': {
          'some': 'data'
        }
      }

    raise Exception('Access denied')

  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    checkSqlAuth: (req, user_name, password) => {
      if (user_name === 'my_user') {
        if (password && password !== 'my_password') {
          throw new Error('Access denied')
        }
        return {
          password,
          securityContext: {
            some: 'data'
          }
        }
      }

      throw new Error('Access denied')
    }
  }
  ```
</CodeGroup>

You can also check for the protocol and the authentication method as follows. This can
be useful for handling the [NTLM][ref-ntlm] authentication in the [DAX API][ref-dax-api]:

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config
  import os

  @config('check_sql_auth')
  def check_sql_auth(req: dict, user_name: str, password: str) -> dict:
    # Handle NTLM authentication:
    # - for Power BI `runas` command
    # - for Power BI gateway
    if req['protocol'] == 'xmla' and req['method'] == 'ntlm':
      if (user_name == os.environ.get('CUBEJS_SQL_USER')):
        return {
          'password': os.environ.get('CUBEJS_SQL_PASSWORD'),
          'securityContext': {}
        }
      
      return {
        'password': os.environ.get('CUBEJS_SQL_PASSWORD'),
        'securityContext': {}
      }

    raise Exception('Access denied')
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    checkSqlAuth: (req, user_name, password) => {
      // handle ntlm auth scenarios (PBI "runas" command + PBI gateway auth)
      if (req.protocol === 'xmla' && req.method === 'ntlm') {
        if (user_name === process.env.CUBEJS_SQL_USER) {
          return {
            password: process.env.CUBEJS_SQL_PASSWORD,
            securityContext: {}
          }
        }
        
        return {
          password: process.env.CUBEJS_SQL_PASSWORD,
          securityContext: {}
        }
      }

      throw new Error('Access denied')
    }
  }
  ```
</CodeGroup>

### `can_switch_sql_user`

Used in the [SQL API][ref-sql-api]. Default implementation depends on
[`CUBEJS_SQL_SUPER_USER`](/reference/configuration/environment-variables#cubejs_sql_super_user) and returns `true` when it's equal to session's user.

Called on each change request from Cube SQL API.

For example, you can use `can_switch_sql_user` to define your custom logic:

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('can_switch_sql_user')
  def can_switch_sql_user(current_user: str, new_user: str) -> dict:
    if current_user == 'admin':
      return True

    if current_user == 'service':
      return new_user != 'admin'

    return False


  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    canSwitchSqlUser: (current_user, new_user) => {
      if (current_user === "admin") {
        return true
      }

      if (current_user === "service") {
        return new_user !== "admin"
      }

      return false
    }
  }
  ```
</CodeGroup>

### `context_to_groups`

Used by [access policies][ref-dap]. This option is used to derive a list of groups that
the user belongs to from the [security context][ref-sec-ctx]. These groups can then be
used to match [access policies][ref-dap-roles].

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('context_to_groups')
  def context_to_groups(ctx: dict) -> list[str]:
    return ctx['securityContext'].get('groups', ['default'])
  ```

  ```javascript title="JavaScript" theme={null}

  module.exports = {
    contextToGroups: ({ securityContext }) => {
      return securityContext.groups || ['default']
    }
  }
  ```
</CodeGroup>

## Utility

### `logger`

A function to define a custom logger.

Accepts the following arguments:

* `message`: the message to be logged
* `params`: additional parameters

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('logger')
  def logger(message: str, params: dict) -> None:
    print(f"{message}: {params}")
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    logger: (message, params) => {
      console.log(`${message}: ${JSON.stringify(params)}`)
    }
  }
  ```
</CodeGroup>

See also the [`CUBEJS_LOG_LEVEL`](/reference/configuration/environment-variables#cubejs_log_level) environment variable.

### `telemetry`

Cube collects high-level anonymous usage statistics for servers started in
development mode. It doesn't track any credentials, data model contents or
queries issued. This statistics is used solely for the purpose of constant
cube.js improvement.

You can opt out of it any time by setting `telemetry` option to `False` or,
alternatively, by setting [`CUBEJS_TELEMETRY`](/reference/configuration/environment-variables#cubejs_telemetry) environment variable to `false`.

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  config.telemetry = True
  ```

  ```javascript title="JavaScript" theme={null}
  module.exports = {
    telemetry: false
  }
  ```
</CodeGroup>

## Deprecated

### `dbType`

<Warning>
  `dbType` is deprecated and will be removed in a future release.
  Use [`driverFactory`][self-driver-factory] instead.
</Warning>

Data source type. Called only once per [`appId`][self-opts-ctx-to-appid].

```javascript theme={null}
module.exports = {
  // string
  dbType: 'snowflake',

  // function
  dbType: ({ securityContext }) => 'databricks'
}
```

Either `string` or `function` could be passed. Providing a `Function` allows
to dynamically select a database type depending on the security context.
Usually used for [multitenancy][ref-multitenancy].

If not defined, Cube will lookup for environment variable
[`CUBEJS_DB_TYPE`](/reference/configuration/environment-variables#cubejs_db_type) to resolve the data source type.

### `context_to_roles`

<Warning>
  `context_to_roles` is deprecated and will be removed in a future release.
  Use [`context_to_groups`](#context_to_groups) instead.
</Warning>

Used by [access policies][ref-dap]. This option is used to derive a list of
[data access roles][ref-dap-roles] from the [security context][ref-sec-ctx].

<CodeGroup>
  ```python title="Python" theme={null}
  from cube import config

  @config('context_to_roles')
  def context_to_roles(ctx: dict) -> list[str]:
    return ctx['securityContext'].get('roles', ['default'])
  ```

  ```javascript title="JavaScript" theme={null}

  module.exports = {
    contextToRoles: ({ securityContext }) => {
      return securityContext.roles || ['default']
    }
  }
  ```
</CodeGroup>

[gh-jsonwebtoken-algs]: https://github.com/auth0/node-jsonwebtoken#algorithms-supported

[link-express-cors-opts]: https://expressjs.com/en/resources/middleware/cors.html#configuration-options

[link-jwt]: https://jwt.io/

[link-jwt-ref-iss]: https://tools.ietf.org/html/rfc7519#section-4.1.1

[link-jwt-ref-sub]: https://tools.ietf.org/html/rfc7519#section-4.1.2

[link-jwt-ref-aud]: https://tools.ietf.org/html/rfc7519#section-4.1.3

[link-wiki-tz]: https://en.wikipedia.org/wiki/Tz_database

[ref-development-mode]: /docs/data-modeling/dev-mode

[ref-multitenancy]: /embedding/multitenancy

[ref-rest-api]: /reference/core-data-apis/rest-api

[ref-sql-api]: /reference/core-data-apis/sql-api

[ref-pre-aggregations-refresh-key]: /reference/data-modeling/pre-aggregations#refresh_key

[ref-schema-cube-ref-refresh-key]: /reference/data-modeling/cube#refresh_key

[ref-schema-cube-ref-ctx-sec-ctx]: /reference/data-modeling/context-variables#security_context

[ref-sec-ctx]: /docs/data-modeling/access-control/context

[self-pre-aggregations-schema]: #pre_aggregations_schema

[self-opts-ctx-to-appid]: #context_to_app_id

[self-driver-factory]: #driver_factory

[ref-schema-ref-datasource]: /reference/data-modeling/cube#data_source

[self-repofactory]: #repository_factory

[ref-exec-environment-globals]: /docs/data-modeling/dynamic/schema-execution-environment#nodejs-globals-processenv-consolelog-and-others

[ref-environment-variables]: /reference/configuration/environment-variables

[ref-rest-scopes]: /reference/core-data-apis/rest-api#api-scopes

[ref-config-options]: /admin/connect-to-data#configuration-options

[self-orchestrator-id]: #context_to_orchestrator_id

[ref-multiple-data-sources]: /admin/connect-to-data/multiple-data-sources

[ref-websockets]: /reference/core-data-apis/rest-api/real-time-data-fetch

[ref-matching-preaggs]: /docs/pre-aggregations/matching-pre-aggregations

[link-snake-case]: https://en.wikipedia.org/wiki/Snake_case

[link-camel-case]: https://en.wikipedia.org/wiki/Camel_case

[link-github-cube-drivers]: https://github.com/cube-js/cube/tree/master/packages

[ref-ungrouped-query]: /reference/core-data-apis/queries#ungrouped-query

[ref-dap]: /docs/data-modeling/data-access-policies

[ref-dap-roles]: /docs/data-modeling/data-access-policies#data-access-roles

[ref-auth-integration]: /docs/data-modeling/access-control#authentication-integration

[ref-dax-api]: /reference/dax-api

[ref-ntlm]: /docs/integrations/power-bi/ntlm

[ref-environments]: /admin/deployment/environments
