---
title: "Recipe: Aggregation Dashboard"
description: "Run aggregate SQL in teenybase actions, such as monthly signups, daily counts and totals, which the CRUD endpoints cannot do."
url: https://teenybase.com/docs/recipes/aggregation
last_updated: 2026-04-19
---

> Documentation index: https://teenybase.com/llms.txt lists every teenybase docs page with a link to its Markdown version. All docs in one file: https://teenybase.com/llms-full.txt

# Aggregation Dashboard

Use actions to run aggregate queries -- monthly signups, daily counts, totals. Actions can execute raw SQL that regular CRUD endpoints can't.

### Config

```typescript
actions: [
    {
        name: 'monthly_signups',
        description: 'Count new users grouped by month',
        requireAuth: true,
        applyTableRules: false,
        sql: {
            type: 'SELECT',
            table: 'users',
            selects: [
                { q: "strftime('%Y-%m', created)", as: 'month' },
                { q: 'COUNT(*)', as: 'count' },
            ],
            groupBy: ["strftime('%Y-%m', created)"],
            orderBy: 'month DESC',
            limit: 12,
        },
    },
    {
        name: 'table_stats',
        description: 'Record count per table',
        requireAuth: true,
        guard: 'auth.role ~ "%admin"',
        applyTableRules: false,
        sql: [
            { type: 'SELECT', table: 'users', selects: [{ q: 'COUNT(*)', as: 'count' }] },
            { type: 'SELECT', table: 'posts', selects: [{ q: 'COUNT(*)', as: 'count' }] },
            { type: 'SELECT', table: 'comments', selects: [{ q: 'COUNT(*)', as: 'count' }] },
        ],
    },
]
```

### API calls

```bash
# Monthly signups (requires auth)
curl -X POST http://localhost:8787/api/v1/action/monthly_signups \
  -H 'Authorization: Bearer <token>'
# → [[{"month": "2025-03", "count": 42}, {"month": "2025-02", "count": 38}, ...]]

# Table stats (requires admin)
curl -X POST http://localhost:8787/api/v1/action/table_stats \
  -H 'Authorization: Bearer <token>'
# → [[{"count": 150}], [{"count": 89}], [{"count": 312}]]
#     ^ users            ^ posts           ^ comments
```

**Multi-query responses:** When an action has multiple SQL queries (array), the response is an array of arrays -- one result set per query, in order. The `table_stats` example above returns `[[users count], [posts count], [comments count]]`.
