Dynamic table identifiers
The SQL query must select from a table whose name is chosen from a trusted, allow-listed set.
Prisma · Module
$queryRawUnsafe executes raw SQL and returns query records. Use it only with trusted SQL structure or correctly parameterized values, because user-controlled interpolation can enable SQL injection.
$queryRawUnsafe sends a raw SQL string or template string to the database and returns the records produced by the query. It is useful when SQL structure, such as a table name, must be dynamic, but interpolating untrusted input can enable SQL injection, so $queryRaw is preferred whenever possible.
prisma.$queryRawUnsafe(query: string, ...values: unknown[]): PrismaPromise<T>| Name | Type | Description |
|---|---|---|
query | string or template string | Raw SQL text or a template string to execute; parameter values may be supplied using the database provider's placeholder syntax. |
values | provider-specific parameter values | Values corresponding to SQL placeholders, such as ? for MySQL or $1, $2, and later positions for PostgreSQL. |
A promise resolving to the records returned by the SQL query.
SELECT.$queryRaw; this is a case where the unsafe method may be required.$queryRaw API when it can express the query safely.import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
const table = "User";
const users = await prisma.$queryRawUnsafe<Array<{ id: number }>>(
`SELECT id FROM ${table}`
);
console.log(users);
}
main().finally(() => prisma.$disconnect());Reads records from a dynamically selected table; the table name must come from a trusted source.
The SQL query must select from a table whose name is chosen from a trusted, allow-listed set.
A provider-specific SQL feature or optimized statement is needed and Prisma’s query API cannot express it.
A read query must return rows rather than merely report affected-row counts.
$queryRawUnsafe do, and when is it useful?It executes a raw SQL string or template string and returns records, such as rows from a SELECT query. Unlike the safer tagged-template API, its SQL text can contain dynamically constructed structure.
Follow-up: How would you avoid injection when a value is dynamic? Use database-specific placeholders and pass values separately, or use $queryRaw with interpolation for supported value expressions.
$queryRawUnsafe over $queryRaw?It is useful when SQL identifiers such as table names must be dynamic, because $queryRaw cannot interpolate table names. The dynamic identifier must nevertheless be trusted or safely allow-listed.
Follow-up: Why can’t a normal value placeholder solve this? Database placeholders represent values, not SQL identifiers, so a table name cannot generally be bound as a parameter.
$queryRawUnsafe still be used more safely?It supports standard parameterized queries using provider-specific placeholders: ? for MySQL and $1, $2, and later positions for PostgreSQL. Parameterization is safer than concatenating untrusted values into SQL.
Follow-up: What is the preferred alternative when the query does not require a dynamic identifier? Use $queryRaw with a tagged template, because the documentation describes it as significantly safer when used correctly.
$queryRaw$executeRaw$executeRawUnsaferaw queriesparameterized queries