sql.raw(text)
ADVANCED - most users will not need this function.
This function invites SQL injection vulnerabilities. There's almost always a better way.
Used for embedding raw SQL text directly into a query.
Syntax
sql.raw(text: string): SQL
Parameters
text
- Raw SQL text to embed directly
Description
⚠️ EXTREME DANGER: YOU ARE INVITING SQL INJECTION
Embeds raw SQL with zero safety checks. This bypasses all SQL injection protections.
This is an escape hatch only. The number of valid use cases for this function are vanishingly small. In 99.9% of cases, there is a safer alternative using other pg-sql2 functions.
Safer alternatives
Use sql`...`
, sql.identifier()
, sql.value()
, sql.literal()
or any of
the other sql.*
methods instead.
// ❌ sql.raw(userInput) -> SQL injection!
// ✅ sql`ASC` for SQL text
// ✅ sql.identifier(tableName) for table/column names
// ✅ sql.value(userInput) for values
// ✅ sql.literal(50) for constants
Instead of reaching for sql.raw()
, consider using composition: break complex
SQL into small safe fragments that can be composed.
const COLUMNS = {
__proto__: null,
name: sql.identifier("users", "name"),
email: sql.identifier("users", "email"),
created_at: sql.identifier("users", "created_at"),
};
const DIRECTIONS = {
__proto__: null,
asc: sql.literal("ASC"),
desc: sql.literal("DESC"),
};
// Usage
const column = COLUMNS[userInputColumn] || COLUMNS["created_at"];
const direction = DIRECTIONS[userInputDirection] || DIRECTIONS["asc"];
const query = sql`SELECT * FROM users ORDER BY ${column} ${direction}`;
This approach ensures that only predefined, safe values are used.
When using maps, be sure to use a null
prototype so built-in properties can't
be exploited.
Return value
Returns a SQL
fragment containing the raw text that will be inserted verbatim into the compiled query.
When you might need this
Very rare cases where sql.raw()
might be necessary:
- Working with SQL that's generated by other trusted tools
Security checklist
Before using sql.raw()
, verify ALL of these:
- The text is deterministic
- The text is only generated from expressions you control
- User input will never be included in the text
- The text is valid SQL that won't break the query
- You understand the SQL injection risks
- The text has been reviewed by a security-aware developer
- You've considered and ruled out all safer alternatives
- You've considered and ruled out all safer alternatives again, because it's really unlikely that you can't solve this a better way
- You've worked with a colleague to consider safer alternatives and still ruled them all out
- You've consulted with the Graphile Discord, and still no-one can suggest a safer alternative