Article

Amazon Redshift Embedded Analytics for SaaS (2026 Guide)

Amazon Redshift embedded analytics for SaaS: QueryPanel now connects to Redshift for tenant-safe customer dashboards and natural-language-to-SQL in React.

QueryPanel Team
12 min read
embedded analyticsAmazon RedshiftAWSSaaScustomer-facing analyticsmulti-tenantReact SDKNode SDK
Amazon Redshift Embedded Analytics for SaaS (2026 Guide)

QueryPanel now supports Amazon Redshift embedded analytics. Connect a Redshift cluster or Redshift Serverless workgroup, and your customers can ask questions in plain English and get tenant-safe SQL and live charts inside your product. You don't need a second copy of the warehouse or an iframe BI portal. Redshift joins PostgreSQL, ClickHouse, BigQuery, and MySQL as a supported data source.


Short answer: If your SaaS product's customer data already lives in Amazon Redshift, you can put customer-facing analytics directly on top of it. Use QueryPanel's headful React SDK for the fastest launch: Notion-like dashboards and an AI assistant that each tenant can customize. Use the headless Node SDK if you want your own UI and want credentials and query results to stay on your servers. In both cases QueryPanel generates Redshift-specific SQL, not generic Postgres, and scopes every query to the signed-in tenant.

What makes this hard isn't connecting. Redshift speaks the Postgres wire protocol, so any pg client can open a connection. The hard part is that Redshift looks like Postgres but rejects a long list of Postgres features. A text-to-SQL layer that treats it as Postgres will generate queries that fail in front of your customers.

Key takeaways

  • Redshift support is live in QueryPanel for the hosted dashboard, the React SDK, and the Node SDK (attachRedshift, available in @querypanel/node-sdk).
  • Redshift is not Postgres for SQL generation. FILTER (WHERE …), DISTINCT ON, jsonb operators, arrays, and string_agg don't work. QueryPanel's generator has a Redshift dialect that avoids them.
  • Schema sync reads Redshift's svv_* catalog views, not information_schema constraint views, which are slow on large clusters.
  • Tenant isolation still belongs to you and QueryPanel together. QueryPanel injects and verifies the tenant filter. Redshift row-level security and a read-only user add defense in depth.
  • Redshift is shared compute. Put customer-facing queries in their own WLM queue (or a Serverless workgroup) with a statement_timeout so one large question can't slow down your internal ETL.

Why we added Redshift

Many B2B SaaS teams on AWS already have their product events, billing records, and usage data in Redshift, usually because a data team built it for internal reporting. When customers start asking for dashboards, the default plan is to copy a subset of that data back into Postgres or into a vendor's warehouse. That plan means a second pipeline, a second schema to keep in sync, and numbers that drift from what finance sees.

Connecting customer-facing analytics directly to the warehouse removes the copy. It also changes what you need to get right: dialect, tenant scoping, and workload isolation. The rest of this guide covers those three things.

Connect Redshift in the QueryPanel dashboard

For the headful React SDK, add the datasource in the QueryPanel dashboard:

  1. Go to Datasources → New and pick Amazon Redshift as the dialect.
  2. Paste the JDBC URL from the Redshift console (jdbc:redshift://<cluster>.<id>.<region>.redshift.amazonaws.com:5439/dev) or a postgresql:// URI. QueryPanel fills in host, port, database, user, and SSL mode from it. The default port is 5439, not 5432.
  3. Enter a database user and password. Credentials are stored in a vault, not in application code.
  4. Test the connection, then run schema sync.

One limitation to know: IAM authentication is currently Postgres-only in the hosted form. For Redshift, use a dedicated database user. Make that user read-only (more on this below).

Make sure the cluster or workgroup is reachable from QueryPanel. If the cluster is in a private subnet, either use the headless SDK (queries run from your backend, inside your VPC) or expose a restricted endpoint.

Connect Redshift with the Node SDK

If you'd rather keep execution in your own backend, attachRedshift takes the same client callback as attachPostgres. Under the hood it uses the Postgres adapter with Redshift introspection and SQL generation.

import { Pool } from "pg";
import { QueryPanelSdkAPI } from "@querypanel/node-sdk";

const qp = new QueryPanelSdkAPI(
  process.env.QUERYPANEL_URL!,
  process.env.PRIVATE_KEY!,
  process.env.QUERYPANEL_WORKSPACE_ID!,
);

// Redshift speaks the Postgres wire protocol, so node-postgres works.
const pool = new Pool({
  connectionString: process.env.REDSHIFT_URL, // postgresql://analytics_ro:…@…:5439/dev
  ssl: { rejectUnauthorized: true },
});

const redshiftClient = async (sql: string, params?: unknown[]) => {
  const result = await pool.query(sql, params);
  return {
    rows: result.rows,
    fields: result.fields.map((field) => ({ name: field.name })),
  };
};

qp.attachRedshift("warehouse", redshiftClient, {
  database: "dev",
  description: "Product usage and billing warehouse",
  tenantFieldName: "tenant_id",
  enforceTenantIsolation: true,
  allowedTables: ["analytics.events_daily", "analytics.invoices"],
});

Run schema sync once at setup and again after schema changes, like a migration:

// scripts/sync-schema.ts
await qp.syncSchema("warehouse", { tenantId: "tenant_123" });

Then ask questions from your API route. Derive the tenant ID from your server-side session, never from the request body:

const response = await qp.ask("Weekly active users for the last 90 days", {
  tenantId: session.tenantId,
  database: "warehouse",
});

// response.sql, response.params, response.rows, response.chart.vegaLiteSpec

allowedTables matters more on Redshift than on a typical app database. Warehouses collect staging tables, raw event dumps, and internal finance models. Limit the sync to the tables customers are supposed to see.

What changes when the SQL targets Redshift

Redshift is based on an old PostgreSQL fork, and AWS keeps a long list of unsupported PostgreSQL features. These are the ones that broke generated queries most often while we built the dialect, and what QueryPanel generates instead:

Postgres habitWhat happens on RedshiftWhat QueryPanel generates
COUNT(*) FILTER (WHERE status = 'paid')Syntax errorSUM(CASE WHEN status = 'paid' THEN 1 ELSE 0 END)
SELECT DISTINCT ON (account_id) …Not supportedROW_NUMBER() OVER (PARTITION BY account_id ORDER BY …)
payload->>'plan' on jsonbNo jsonb type or operatorsJSON_EXTRACT_PATH_TEXT(payload, 'plan')
string_agg(name, ',') / array_aggNot availableLISTAGG(name, ',')
generate_series joined to a tableFails (leader-node only)A date spine without generate_series
NOW() - INTERVAL '30 days'Works, but date helpers differDATEADD, DATEDIFF, DATE_TRUNC, GETDATE()

Identifiers are case-insensitive and lowercased, so generated SQL uses table names exactly as the schema sync reported them, schema-qualified (analytics.invoices, not invoices).

This is why we didn't just label Redshift "Postgres-compatible" and reuse the Postgres prompt. A query that works in local Postgres testing and fails on the customer's first dashboard is worse than no dashboard.

Schema sync on large clusters

The first version of introspection read information_schema, like it does for Postgres. On Redshift, the information_schema constraint views get very slow as the number of tables grows. QueryPanel now reads svv_tables and svv_columns for the current database. It skips pg_catalog, information_schema, pg_internal, pg_automv, and temp schemas, and keeps table and column comments (remarks) as descriptions.

Two practical consequences:

  • Primary keys are not reported. Redshift treats primary and foreign keys as informational only, so QueryPanel doesn't rely on them for joins. Write join hints and column descriptions in QueryPanel's knowledge base (gold SQL, annotations, glossary) instead.
  • Comments pay off. A COMMENT ON COLUMN analytics.invoices.amount_cents IS 'Invoice total in cents, excluding tax' becomes context the SQL generator uses. On warehouses with cryptic dbt model names, this is the cheapest accuracy improvement available.

Tenant isolation on a shared warehouse

Most SaaS warehouses are multi-tenant by row: one events table, with a tenant_id column on every row. Customer-facing queries need to be scoped every time, not most of the time.

QueryPanel handles this in layers:

  1. Your backend signs an RS256 JWT with the tenant ID (JWT setup), or passes tenantId from a verified session in the Node SDK.
  2. With tenantFieldName and enforceTenantIsolation, the generator adds a parameterized tenant filter, and the API checks the generated SQL before it runs. Queries that don't include the tenant predicate are rejected, not executed. Details are in tenant isolation.
  3. The tenant value is bound as a parameter ($1), never interpolated into the SQL string.

For defense in depth, add controls on the Redshift side as well:

  • A read-only database user with USAGE on the customer-facing schema and SELECT on the allowed tables only. No access to staging schemas.
  • Redshift row-level security if your design maps tenants to database roles or session context. It's optional on top of QueryPanel's filter, but it means a query that somehow skipped the filter still returns nothing outside the tenant.

The common mistake is relying on a dashboard filter alone. A filter a user can see is a UI choice, not a security boundary.

Keep customer queries away from your ETL

Redshift clusters are usually shared by ELT jobs, internal BI, and now customer-facing traffic. Customer traffic is spiky and can't be scheduled. A few settings keep it from competing with the nightly load:

  • A dedicated WLM queue for the QueryPanel user group, with its own concurrency and memory share.
  • Query monitoring rules that abort or log queries that scan too many rows or run too long.
  • statement_timeout on the read-only user (for example ALTER USER analytics_ro SET statement_timeout TO 15000;), so a customer never waits more than about 15 seconds before getting an error they can act on.
  • Concurrency scaling on provisioned clusters, or a separate Redshift Serverless workgroup with its own base capacity, if dashboard traffic peaks during business hours.

QueryPanel's per-client systemPrompt helps from the other direction. If a plan tier only includes 90 days of history, say so in the prompt, and generated queries will clamp their date range before they reach the warehouse.

A one-week Amazon Redshift embedded analytics POC

You can validate this in a week without touching production dashboards:

DayDo thisYou're done when
1Create analytics_ro, grant it one schema, set statement_timeoutA SELECT on a staging table fails with a permission error
2Connect in QueryPanel (or attachRedshift), sync 3–5 tablesSchema shows the expected tables and comments
3Ask 20 real questions from support tickets80%+ return correct SQL; fixes go into gold SQL and annotations
4Test two tenants with very different data volumesNeither tenant can see the other's rows; the large one stays under the timeout
5Embed the React SDK on one internal pageA product manager builds a dashboard without help

Write down the failures from day 3, not only the successes. They show you which column descriptions and gold queries to add before customers see the feature.

Where QueryPanel fits, and where it doesn't

QueryPanel is customer-facing, tenant-safe analytics for SaaS products. Its primary product is a headful React SDK with Notion-like dashboard management and an AI assistant that lets each tenant customize their own dashboards. It also offers a headless Node SDK for custom UIs with a zero-trust architecture, where credentials and query results stay on your servers.

QueryPanel is not a replacement for your internal BI tool, a data pipeline, or a Redshift performance tuning service. If your Redshift tables need re-sorting or your models are wrong, QueryPanel will query them faithfully and give you the same wrong answer faster.

If you are choosing a warehouse rather than connecting an existing one, read best database for embedded analytics. For event-heavy, real-time workloads, compare with ClickHouse embedded analytics. If each customer brings their own warehouse, see embedded analytics on customer-owned warehouses.

FAQ

Does QueryPanel support Amazon Redshift?

Yes. As of October 2026, QueryPanel supports Amazon Redshift (provisioned clusters and Redshift Serverless) in the hosted dashboard, the React SDK, and the Node SDK via attachRedshift. It generates Redshift-specific SQL and syncs schema from Redshift's svv_* catalog views.

Is Amazon Redshift good for customer-facing embedded analytics?

Yes, when your customer data is already modeled there and your dashboards aggregate over large histories. Redshift needs workload isolation (WLM queues or a dedicated Serverless workgroup) and query timeouts so spiky customer traffic doesn't compete with ETL. For sub-second, high-concurrency event exploration, ClickHouse is often the better fit.

Can I use a Postgres connector for Redshift?

You can connect with a Postgres driver, because Redshift uses the Postgres wire protocol. But SQL written for Postgres often fails on Redshift: FILTER, DISTINCT ON, jsonb operators, arrays, and string_agg aren't supported. Choose the Amazon Redshift dialect in QueryPanel so the generated SQL matches.

How does QueryPanel keep tenants separate in Redshift?

Every question is tied to a tenant from your signed JWT or verified server session. QueryPanel adds a parameterized tenant filter and checks the SQL before execution, rejecting queries without it. Use a read-only Redshift user, and optionally Redshift row-level security, as additional layers.

Do my Redshift credentials leave AWS?

With the headless Node SDK, no: queries run in your backend through a client you control, and QueryPanel receives schema metadata plus column names and types for chart generation. With the hosted dashboard, credentials are stored in a vault and QueryPanel connects to your cluster to run queries.

Does QueryPanel support IAM authentication for Redshift?

Not yet in the hosted dashboard. Use a dedicated read-only database user and password. With the Node SDK, you control the client, so you can use any authentication method your pg setup supports.

Should I use the headful or headless SDK with Redshift?

Start with the headful React SDK if you want customers building and customizing dashboards with an AI assistant inside your app quickly. Choose the headless Node SDK if your cluster sits in a private VPC, if you need a fully custom UI, or if query results must never leave your infrastructure.

Try it on your Redshift data

Connect your cluster in the QueryPanel dashboard, sync a few customer-facing tables, and ask the questions your customers send to support. If you want a walkthrough on your own schema, start building or read the React SDK docs.