---
title: Connect Amazon Redshift
description: Set up the two credentials Redshift needs, an IAM key pair and a Secrets Manager ARN, and know what a Redshift data source can and cannot do yet.
updated: 2026-09-12
tier: pro
engines: [redshift]
---

Amazon Redshift, via the AWS Redshift Data API. Dashies signs each request with
SigV4 and never opens a database socket, so there is no host to enter and nothing
to allowlist.

:::warning{title="A refreshing dashboard cannot publish against Redshift yet"}
A Redshift data source connects, introspects, explores, and validates cube SQL.
What it cannot do yet is carry a dashboard: a publish that binds a Redshift data
source is refused, naming the warehouses that do work.

The reason is that a warehouse dashboard keeps its data with Dashies rather than
inside the published file, and Redshift is not yet one of the warehouses Dashies
can hold data from. The [connect hub](/guides/connect-warehouse) carries the
current roster, which is read out of the database as each publish is judged.

Use this page to get the connection and its credentials right: that work is
unaffected, and none of it has to be redone when Redshift is admitted.
:::

:::note{title="Newly lit"}
Redshift shipped built against AWS's documented Data API wire shapes rather than
against a Dashies test account, so the first real connections are what confirm
the last details of temporal formatting and error codes. Everything this page
describes about connecting and authoring is supported. If something behaves
differently from what you read here, that is worth reporting rather than working
around.
:::

## Redshift needs two separate credentials

This is the part that differs from every other engine, and it is worth being
clear about before you start.

| Credential | What it authenticates | Where it lives |
|---|---|---|
| An IAM access key pair | The API call itself, over SigV4 | Stored encrypted by Dashies |
| A database user and password | The query, inside Redshift | **AWS Secrets Manager**. Only its ARN reaches Dashies |

The database login never leaves AWS. Dashies holds a pointer to it and asks the
Data API to use it.

## Before you start

Do this in AWS:

:::steps

### 1. Have a workgroup or a cluster

Create a **Redshift Serverless** workgroup and namespace, or use a provisioned
cluster. For Serverless, a low base-RPU (minimum capacity) workgroup is the right
starting point. See the cost section below.

### 2. Create a read-only database user

Grant it `usage` on the reporting schema and `select` on its tables, and no write
privileges.

```sql
create user dashies_ro with password 'REPLACE_WITH_A_STRONG_PASSWORD';
grant usage on schema analytics to dashies_ro;
grant select on all tables in schema analytics to dashies_ro;
alter default privileges in schema analytics
  grant select on tables to dashies_ro;
```

### 3. Store that user in Secrets Manager

Create a secret holding that database user and password. Its ARN is what you
paste into Dashies.

### 4. Create an IAM identity for the API calls

Give it a least-privilege policy allowing only the Data API calls Dashies makes,
plus read on that one secret:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DashiesDataApi",
      "Effect": "Allow",
      "Action": [
        "redshift-data:ExecuteStatement",
        "redshift-data:DescribeStatement",
        "redshift-data:GetStatementResult",
        "redshift-data:CancelStatement",
        "redshift-data:ListDatabases"
      ],
      "Resource": "*"
    },
    {
      "Sid": "DashiesReadOneSecret",
      "Effect": "Allow",
      "Action": "secretsmanager:GetSecretValue",
      "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:dashies-ro-AbCdEf"
    }
  ]
}
```

Replace the secret ARN with your own. Tighten the first statement's `Resource`
from `*` to your workgroup's or cluster's ARN once you have it; the five actions
above are the complete set Dashies uses, so nothing else needs adding.

### 5. Mint its access key pair

You need the access key id and the secret access key.

:::

## Add the data source

Open [dashies.ai/app/connections](https://dashies.ai/app/connections), click to
add a data source, and pick **Amazon Redshift**.

| Field | Required | Example | Notes |
|---|---|---|---|
| Region | yes | `us-east-1` | Chosen from a grouped list of 29 commercial regions. |
| Deployment | yes | Serverless | Serverless uses a workgroup; provisioned uses a cluster. |
| Workgroup name | Serverless only | `my-workgroup` | Lower case, digits, hyphens; 3 to 64 characters. |
| Cluster identifier | provisioned only | `my-cluster` | Starts with a letter; up to 63 characters. |
| Database | yes | `dev` | Up to 128 characters. |
| Access key ID | yes | `AKIA...` | `AKIA` followed by 16 upper-case characters or digits. |
| Secret access key | yes | | Exactly 40 characters. |
| Secrets Manager ARN | yes | `arn:aws:secretsmanager:us-east-1:123456789012:secret:dashies-ro-AbCdEf` | |
| Display name | no | `Analytics warehouse` | Up to 120 characters. |

Exactly one of workgroup or cluster must be filled in. If both or neither are,
the form refuses before anything is sent:

```bash
A Redshift data source needs exactly one of a Serverless workgroup or a provisioned cluster.
```

ARNs from the `aws`, `aws-us-gov`, `aws-cn`, and `aws-iso` partitions are all
accepted.

## It verifies in one step

Redshift is a single-step connect. Creating the data source signs one
`ListDatabases` call and comes back **active** with the databases it found, or
**error** with a class. Up to 200 databases are stored. There is no Resync button
on Redshift.

If it fails:

| Message | Meaning |
|---|---|
| `Amazon Redshift denied access. Check the IAM access key and that its policy allows the Redshift Data API and reading the Secrets Manager secret, and that the secret holds the read-only database user and password.` | Any authorization failure across either credential. |
| `We couldn't reach Amazon Redshift. Check the region and try again.` | Network-level failure, usually a wrong region. |
| `We couldn't read that warehouse. Check the database and the workgroup or cluster, then try again.` | The call succeeded but the target was not usable. |

## Cost

:::warning{title="Serverless bills per RPU-second, with a minimum per query"}
Redshift Serverless charges **per RPU-second with a minimum of roughly 60 seconds
per query**, and it auto-pauses when idle. The first query after a pause also
pays a cold resume of roughly 30 to 60 seconds. That resume is why Dashies allows
60 seconds to connect here rather than the 20 it allows elsewhere.

To keep it predictable:

- Use a **low base-RPU (minimum-capacity) Serverless workgroup**.
- Keep authoring deliberate. Every introspect, explore, and validate call is a
  query, and one that lands on a paused workgroup pays the resume as well.

A **provisioned cluster** is a flat hourly cost instead, so how often you query
does not change the bill.
:::

Connecting is effectively free: the verification is a single `ListDatabases`
metadata call.

## Caps

The first bounds one result read through the adapter, which is the path the
authoring tools take, and it is the one you can meet today. The second is
engine-independent and applies to a published dashboard, which Redshift cannot
have yet.

| Limit | Value | What happens past it |
|---|---|---|
| Rows per dataset query | 100,000 | Refused before results are fetched, by reading Redshift's own reported row count. |
| Compiled dashboard body | 5,242,880 bytes | Publish is refused. |

Like the other three API-based engines, Redshift has **no byte gate at execution
time**: nothing on that path measures serialized size, so a single result is
bounded by its row count alone.

How these ceilings relate to each other, and which one binds first, is in
[sizes and ceilings](/concepts/dataset-modes#sizes-and-ceilings).

## Dialect notes

Cube SQL is Redshift SQL, which is a PostgreSQL dialect, so almost everything you
know from Postgres applies.

- Bucket a date with `date_trunc('month', ts)::date`, or produce a text bucket
  with `to_char(ts, 'YYYY-MM-DD')`.

  ```sql
  select date_trunc('month', ordered_at)::date as month,
         sum(amount) as revenue
  from analytics.orders
  group by 1
  order by 1
  ```

- Bucket in your business time zone in the SQL. A refresh runs with no session
  time zone, so a bare `date_trunc` buckets in UTC.
- **Alias letter-case depends on two cluster parameters, not on how you write
  it.** At the defaults, quoting an alias preserves nothing, because AWS folds
  delimited identifiers to lower case too. Two settings change that:
  `enable_case_sensitive_identifier = true` makes a quoted identifier keep its
  case, and `describe_field_name_in_uppercase = on` returns every column name in
  upper case regardless. Neither is exotic.

  Rather than guessing which way your cluster is set, ask your AI tool to run one
  validation and read the column names back:

  ```sql
  select 1 as MixedCase, 2 as "MixedQuoted"
  ```

  That answers both parameters in a single call. A case-only difference between
  your alias and your declared measure key is handled for you either way; two
  output columns differing only by case are refused, naming both.

## Rotating the key

Edit the data source and paste a new IAM secret access key under **Secret access
key**. Rotating the database user is done in Secrets Manager, and Dashies picks
it up without any change here, because it holds only the ARN.

## Check it worked

1. The data source reads **active** on
   [dashies.ai/app/connections](https://dashies.ai/app/connections), and lists
   the databases it discovered.
2. Ask your AI tool to introspect it and run one query:

   > Introspect my Redshift data source, then validate this cube SQL against it:
   > `select 1 as ok`

That is as far as a Redshift data source goes today. To publish a refreshing
dashboard now, connect one of the warehouses the
[connect hub](/guides/connect-warehouse) lists, then
[author a dashboard against it](/guides/author-a-dashboard).
