{"id":43585,"library":"pg-sql2","title":"pg-sql2","description":"Generate safe Postgres-compliant SQL using ES6 tagged template literals. Current stable version is 5.0.1, requiring Node >=22. It prevents SQL injection by forcing all values through allowed APIs like sql.value() and sql.identifier(). Built by the Graphile team, it is fast, ships TypeScript types, and is designed for highly dynamic query building. Unlike pg-promise or knex, it uses template literals for composable, compile-time safe SQL construction.","status":"active","version":"5.0.1","language":"javascript","source_language":"en","source_url":"https://github.com/graphile/crystal","tags":["javascript","sql","injection","pg","postgres","postgresql","tagged","template","literal","typescript"],"install":[{"cmd":"npm install pg-sql2","lang":"bash","label":"npm"},{"cmd":"yarn add pg-sql2","lang":"bash","label":"yarn"},{"cmd":"pnpm add pg-sql2","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"ESM-only since v5; CJS require still works but using default with require() requires .default or use import syntax","wrong":"const sql = require('pg-sql2')","symbol":"default","correct":"import sql from 'pg-sql2'"},{"note":"compile is not a named export; it's a method on the default export","wrong":"import { compile } from 'pg-sql2'","symbol":"sql.compile","correct":"import sql from 'pg-sql2'; sql.compile(...)"},{"note":"value is a method on the default export, not a named export","wrong":"import { value } from 'pg-sql2'","symbol":"sql.value","correct":"import sql from 'pg-sql2'; sql.value(42)"},{"note":"identifier is a method on the default export","wrong":"import { identifier } from 'pg-sql2'","symbol":"sql.identifier","correct":"import sql from 'pg-sql2'; sql.identifier('table', 'column')"}],"quickstart":{"code":"import sql from 'pg-sql2';\n\nconst tableName = 'user';\nconst fields = ['name', 'age', 'height'];\n\nconst sqlFields = sql.join(\n  fields.map((fieldName) => sql.identifier(tableName, fieldName)),\n  ', ',\n);\n\nconst sqlConditions = sql`created_at > NOW() - interval '3 years' and age > ${sql.value(22)}`;\n\nconst innerQuery = sql`select ${sqlFields} from ${sql.identifier(tableName)} where ${sqlConditions}`;\n\nconst sqlAlias = sql.identifier(Symbol());\n\nconst query = sql`\n  with ${sqlAlias} as (${innerQuery})\n  select\n    (select json_agg(row_to_json(${sqlAlias})) from ${sqlAlias}) as all_data,\n    (select max(age) from ${sqlAlias}) as max_age\n`;\n\nconst { text, values } = sql.compile(query);\nconsole.log(text);\nconsole.log(values); // [22]","lang":"typescript","description":"Shows safe dynamic SQL construction with tagged templates, identifiers, values, join, and compile."},"warnings":[{"fix":"Upgrade to Node >=22 and use import syntax; if CJS required, use dynamic import or stick with v4.","message":"In v5, the package is ESM-only; Node <22 is no longer supported.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Use sql.literal with trusted strings instead of sql.raw; for JSON, use sql.value with JSON.stringify.","message":"sql.json and sql.raw are deprecated and will be removed in a future version.","severity":"deprecated","affected_versions":">=4.0.0"},{"fix":"Always use sql.value for untrusted or sensitive data; only use sql.literal with trusted constants.","message":"sql.literal does not escape values; using it with untrusted data can lead to SQL injection.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Update imports: import sql from 'pg-sql2' and use sql`...` as before, but now call sql.compile(query).","message":"Versions prior to v4 exported a default tagged template function; now the default export is an object with methods like compile, value, etc.","severity":"breaking","affected_versions":"<4.0.0"},{"fix":"Always wrap raw values with sql.value() and identifiers with sql.identifier().","message":"Using a plain value inside a template literal (e.g., sql`select ${42}`) throws an error; all non-sql fragments must be wrapped with sql.value or sql.identifier.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Use sql.join for lists of fragments separated by commas, AND, OR, etc. For SQL JOINs, build manually.","message":"sql.join is for joining SQL fragments with a separator, not for SQL JOIN operations; the name is misleading.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"search_vec":"'22':22 '5.0.1':19 'allow':32 'api':33 'build':56 'built':38 'compil':70 'compile-tim':69 'compliant':8 'compos':68 'construct':74 'current':15 'design':51 'dynam':54 'es6':11 'fast':45 'forc':28 'generat':4 'graphil':41 'high':53 'inject':26,77 'javascript':75 'knex':62 'like':34 'liter':14,66,83 'node':21 'pg':2,59,78 'pg-promis':58 'pg-sql2':1 'postgr':7,79 'postgres-compli':6 'postgresql':80 'prevent':24 'promis':60 'queri':55 'requir':20 'safe':5,72 'ship':46 'sql':9,25,73,76 'sql.identifier':37 'sql.value':35 'sql2':3 'stabl':16 'tag':12,81 'team':42 'templat':13,65,82 'time':71 'type':48 'typescript':47,84 'unlik':57 'use':10,64 'valu':30 'version':17","created_at":"2026-06-05T17:00:30.012527+00:00","updated_at":"2026-06-05T17:00:30.012527+00:00","problems":[{"fix":"Use import sql from 'pg-sql2' (ESM) or const { default: sql } = require('pg-sql2') (CJS).","cause":"Using default import but package imported incorrectly (e.g., import { sql } from 'pg-sql2' or const sql = require('pg-sql2') without .default).","error":"TypeError: sql is not a function"},{"fix":"Wrap the value: sql`... ${sql.value(42)} ...`","cause":"Passing a raw JavaScript value directly inside sql`` without wrapping in sql.value().","error":"Error: sql`...` can only contain sql fragments, got: number"},{"fix":"sql.identifier expects string or Symbol arguments; for multiple parts, pass as separate args: sql.identifier('schema', 'table').","cause":"Passing an object (e.g., an array) to sql.identifier().","error":"Error: identifier must be a string or Symbol, found object"},{"fix":"npm install pg-sql2; ensure tsconfig.json includes 'node' resolution and skipLibCheck is false if needed.","cause":"Package not installed or TypeScript cannot resolve types.","error":"Cannot find module 'pg-sql2' or its corresponding type declarations."},{"fix":"Upgrade to v4+ and use import sql from 'pg-sql2', then sql.compile(query).","cause":"Using an older version (v3 or earlier) where compile was not a method; also possible if default import is wrong.","error":"TypeError: sql.compile is not a function"}],"ecosystem":"npm","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":null,"cli_name":null,"cli_version":null,"type":"library","homepage":"https://github.com/graphile/crystal/tree/main/utils/pg-sql2","github":"https://github.com/graphile/crystal","docs":null,"changelog":null,"pypi":null,"npm":"pg-sql2","openapi_spec":null,"status_page":null,"smithery":null,"categories":["database"],"base_url":null,"auth_type":null,"provenance":{"verified_status":null,"verified_at":null,"last_verified":"2026-06-05","next_check":"2026-09-03","install_tag":null}}