Skip to content
Back to skills

Cube

ASecurity

Cube is an open-source semantic layer that sits between a data warehouse and analytics applications and serves governed metrics over REST, GraphQL and SQL APIs. Use when a user asks to define cubes, measures and dimensions, add pre-aggregations, build a metrics API or embedded analytics, set up multi-tenant row-level security, or query Cube from React or the REST API.

  • 142 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 27, 2026
developmentjavascripttypescriptrustgojavabashsqlreactnodedocker

Works with

  • terminal
  • cli
  • api

Security analysis

A96/100
  • mediumUses curl or wget to download content

Pro scans all 2 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add TerminalSkills/skills --skill cube --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Cube?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Cube
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/terminalskills-cube/badge)](https://www.skillsdirectory.com/skills/terminalskills-cube)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cube
description: >-
  Cube is an open-source semantic layer that sits between a data warehouse and analytics applications and serves governed metrics over REST, GraphQL and SQL APIs. Use when a user asks to define cubes, measures and dimensions, add pre-aggregations, build a metrics API or embedded analytics, set up multi-tenant row-level security, or query Cube from React or the REST API.
license: Apache-2.0
compatibility: Docker (cubejs/cube image) or Node.js; a SQL data source such as Postgres, BigQuery or Snowflake
metadata:
  author: terminal-skills
  version: "1.1.0"
  repository: https://github.com/cube-js/cube
  category: data-ai
  tags:
  - semantic-layer
  - analytics
  - api
  - sql
  - metrics
---

# Cube — Semantic Layer for Analytics


## Overview
Cube (Cube Core is the self-hosted open-source part; Cube Cloud is the hosted platform) is a semantic layer: you define metrics once as code (cubes, measures, dimensions, joins, pre-aggregations), and Cube serves them to apps over a REST (JSON) API, GraphQL API and a Postgres-compatible SQL API, with caching and access control. Current release is 1.7.x (October 2026). Docs: https://docs.cube.dev.


## Instructions

### Data Modeling

Data model files live in `model/cubes/` and `model/views/` (inside the project folder mounted at `/cube/conf`). YAML is the format the docs recommend; JavaScript works too and is used below. Reference members of the same cube as `CUBE.measure` in `pre_aggregations`.

```javascript
// model/cubes/Orders.js — Orders cube with measures and dimensions
cube(`Orders`, {
  sql_table: `public.orders`,

  // Pre-aggregation: materialized rollup kept in Cube Store
  pre_aggregations: {
    daily_revenue: {
      measures: [CUBE.revenue, CUBE.count],
      dimensions: [CUBE.status],
      time_dimension: CUBE.created_at,
      granularity: `day`,
      refresh_key: { every: `1 hour` },
    },
  },

  joins: {
    Users: { relationship: `many_to_one`, sql: `${CUBE}.user_id = ${Users}.id` },
  },

  measures: {
    count: { type: `count` },
    revenue: { type: `sum`, sql: `amount`, format: `currency` },
    revenue_per_user: { type: `number`, sql: `${revenue} / NULLIF(${Users.count}, 0)`, format: `currency` },
    // Rolling window: trailing 7-day sum (used with a time dimension)
    revenue_7d: { type: `sum`, sql: `amount`, rolling_window: { trailing: `7 day` } },
  },

  dimensions: {
    id: { type: `number`, sql: `id`, primary_key: true },
    status: { type: `string`, sql: `status` },
    tenant_id: { type: `string`, sql: `tenant_id` },
    created_at: { type: `time`, sql: `created_at` },
  },

  // Segments are named, reusable filters (queried as "Orders.completed")
  segments: {
    completed: { sql: `${CUBE}.status = 'completed'` },
  },
});
```

```javascript
// model/cubes/Users.js — Users cube (condensed)
cube(`Users`, {
  sql_table: `public.users`,
  measures: {
    count: { type: `count` },
    active_count: { type: `count`, filters: [{ sql: `${CUBE}.last_login_at > NOW() - INTERVAL '30 days'` }] },
  },
  dimensions: {
    id: { type: `number`, sql: `id`, primary_key: true },
    plan: { type: `string`, sql: `plan` },
    country: { type: `string`, sql: `country` },
    created_at: { type: `time`, sql: `created_at` },
  },
});
```

### REST API

Cube Core serves the REST API under `/cubejs-api` (configurable with `base_path`). Send a JWT signed with `CUBEJS_API_SECRET` in the `Authorization` header (the token carries the security context). Endpoints: `/cubejs-api/v1/load` (query), `/v1/meta` (model metadata), `/v1/sql` (generated SQL).

```typescript
// src/analytics/cube-client.ts — Query the Cube REST API
const CUBE_API_URL = process.env.CUBE_API_URL!;
const CUBE_API_TOKEN = process.env.CUBE_API_TOKEN!;

type CubeQuery = Record<string, unknown>; // measures, dimensions, timeDimensions, filters, order, limit

async function cubeQuery(query: CubeQuery) {
  const response = await fetch(`${CUBE_API_URL}/cubejs-api/v1/load`, {   // CUBE_API_URL=http://localhost:4000
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: CUBE_API_TOKEN,   // JWT; "Bearer <jwt>" is also accepted
    },
    body: JSON.stringify({ query }),
  });

  const result = await response.json();
  // Long queries answer {"error": "Continue wait"}: repeat the request until data arrives
  if (result.error === "Continue wait") return cubeQuery(query);
  if (result.error) throw new Error(result.error);
  return result.data;
}

// Example: Get monthly revenue by order status
const monthlyRevenue = await cubeQuery({
  measures: ["Orders.revenue", "Orders.count"],
  dimensions: ["Orders.status"],
  timeDimensions: [{
    dimension: "Orders.created_at",
    granularity: "month",
    dateRange: "Last 6 months",
  }],
  order: { "Orders.revenue": "desc" },
  limit: 100,
});

// Example: active users by plan
const activeByPlan = await cubeQuery({
  measures: ["Users.active_count"],
  dimensions: ["Users.plan"],
  filters: [{ member: "Users.plan", operator: "equals", values: ["pro", "enterprise"] }],
});
```

### JavaScript SDK (React)

Build analytics UIs with `@cubejs-client/core` and `@cubejs-client/react` (both 1.7.x). Wrap the app in `CubeProvider`:

```tsx
// src/main.tsx
import cube from "@cubejs-client/core";
import { CubeProvider } from "@cubejs-client/react";
const cubeApi = cube(process.env.CUBE_TOKEN!, { apiUrl: "http://localhost:4000/cubejs-api/v1" });
// <CubeProvider cubeApi={cubeApi}><App /></CubeProvider>
```

```tsx
// src/components/RevenueChart.tsx — React component using Cube
import { useCubeQuery } from "@cubejs-client/react";
import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer } from "recharts";

export function RevenueChart({ dateRange = "Last 6 months" }) {
  const { resultSet, isLoading, error } = useCubeQuery({
    measures: ["Orders.revenue"],
    timeDimensions: [{
      dimension: "Orders.created_at",
      granularity: "month",
      dateRange,
    }],
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  const data = resultSet?.chartPivot() ?? [];

  return (
    <ResponsiveContainer width="100%" height={300}>
      <LineChart data={data}>
        <XAxis dataKey="x" />
        <YAxis />
        <Tooltip formatter={(value: number) => `$${value.toLocaleString()}`} />
        <Line type="monotone" dataKey="Orders.revenue" stroke="#6366f1" strokeWidth={2} />
      </LineChart>
    </ResponsiveContainer>
  );
}
```

### Access Control

Verified JWT claims become the `securityContext`. For multi-tenancy, scope queries and compiled models per tenant in `cube.js` (or `cube.py`):

```javascript
// cube.js — security context configuration
module.exports = {
  // One compiled data model + cache per tenant
  contextToAppId: ({ securityContext }) => `CUBE_APP_${securityContext.tenant_id}`,

  // Called on every request: add a row-level filter
  queryRewrite: (query, { securityContext }) => {
    if (!securityContext.tenant_id) {
      throw new Error("tenant_id is required in the security context");
    }
    query.filters = query.filters || [];
    query.filters.push({
      member: "Orders.tenant_id",
      operator: "equals",
      values: [securityContext.tenant_id],
    });
    return query;
  },
};
```

Cube also supports declarative `access_policy` blocks on cubes and views (group-scoped `member_level` and `row_level` rules, plus masking); when policies exist for some groups, every other group is denied:

```yaml
# model/cubes/orders.yml (excerpt)
    access_policy:
      - group: finance
        member_level:
          includes: "*"
      - group: support
        member_level:
          includes: [count, status]
        row_level:
          filters:
            - member: status
              operator: equals
              values: [completed]
```

If you use `securityContext` in `contextToAppId`, also set `scheduledRefreshContexts` so pre-aggregations refresh for each tenant.

## Installation

The documented way to start is Docker Compose in an empty project folder:

```yaml
# docker-compose.yml
services:
  cube:
    image: cubejs/cube:latest        # pin e.g. cubejs/cube:v1.7.50 in production
    ports:
      - 4000:4000                    # REST/GraphQL APIs and Playground
      - 15432:15432                  # Postgres-compatible SQL API
    environment:
      - CUBEJS_DEV_MODE=true         # local only, see warning below
    volumes:
      - .:/cube/conf
```

```bash
docker compose up -d
# Open http://localhost:4000, pick your database in the wizard (it writes .env), then "Generate Data Model" (YAML or JavaScript)
```

Database settings go in `.env`: `CUBEJS_DB_TYPE=postgres`, `CUBEJS_DB_HOST`, `CUBEJS_DB_NAME`, `CUBEJS_DB_USER`, `CUBEJS_DB_PASS`, and `CUBEJS_API_SECRET` (random string used to sign and verify API JWTs). The `npx cubejs-cli create` scaffold still exists but the docs no longer lead with it. For production, run an API instance, a refresh worker and Cube Store (router plus workers) as in https://docs.cube.dev/cube-core/deployment.

**`CUBEJS_DEV_MODE=true` turns off authentication** on the REST and GraphQL APIs and exposes Playground with ready-made tokens. Use it only on your own machine; set `CUBEJS_DEV_MODE=false` anywhere else.

## Examples


### Example 1: Add a metrics API on top of an orders table

**User request:**

```
We have orders and users tables in Postgres. Give our frontend an API for monthly revenue by order status, with a daily rollup so it's fast.
```

The agent creates `model/cubes/Orders.js` and `Users.js` as above (primary keys, a `many_to_one` join, `revenue` and `count` measures, a `daily_revenue` pre-aggregation), starts Cube with `docker compose up -d`, and checks the model in Playground. It then verifies the endpoint with a signed token:

```bash
curl -G http://localhost:4000/cubejs-api/v1/load \
  -H "Authorization: $CUBE_API_TOKEN" \
  --data-urlencode 'query={"measures":["Orders.revenue"],"dimensions":["Orders.status"],"timeDimensions":[{"dimension":"Orders.created_at","granularity":"month","dateRange":"last 6 months"}]}'
```

The response is `{"data":[{"Orders.status":"completed","Orders.created_at.month":"2026-04-01T00:00:00.000","Orders.revenue":"18420.50"}, ...]}`. Measure values come back as strings.

### Example 2: Make the API multi-tenant

**User request:**

```
Each customer must only ever see their own orders in the dashboard. Tokens already carry a tenant_id claim.
```

The agent writes `queryRewrite` and `contextToAppId` in `cube.js` as shown in Access Control, signs two test JWTs with different `tenant_id` values using `CUBEJS_API_SECRET`, and confirms the same query returns different rows for each. It also sets `CUBEJS_DEV_MODE=false` so the check is not bypassed.

## Guidelines

1. **Semantic layer = single source of truth** — Define metrics once in Cube; all apps query the same definitions
2. **Pre-aggregations for performance** — Materialize common queries; Cube auto-selects the best pre-aggregation
3. **Use the Playground for exploration** — Build queries visually in Cube Playground before coding them into your app
4. **Security context for multi-tenancy** — Use `queryRewrite` (or `access_policy`) to filter queries by tenant/group; never trust filters sent by the client
5. **Measures over raw SQL** — Define `revenue_per_user` as a Cube measure, not as raw SQL in your app
6. **Time dimensions for trends** — Use `timeDimensions` with `granularity` for consistent time-series queries
7. **Mind refresh keys** — pre-aggregations refresh hourly by default; set `refresh_key` to match how often the source data changes, and run a separate refresh worker in production
8. **Version your models** — Cube models are code; store in Git, review changes, deploy via CI/CD

Files in this skill

  • SKILL.md9 KB
  • _scores.json1.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…