Skip to content

feat(langgraph-checkpoint-postgres): optional schema creation - #2561

Open
Alex Golubtsov (alex-golubtsov) wants to merge 15 commits into
langchain-ai:mainfrom
alex-golubtsov:feat/postgres-optional-schema-creation
Open

Alex Golubtsov (alex-golubtsov) wants to merge 15 commits into
langchain-ai:mainfrom
alex-golubtsov:feat/postgres-optional-schema-creation

Conversation

@alex-golubtsov

@alex-golubtsov Alex Golubtsov (alex-golubtsov) commented Jun 20, 2026

Copy link
Copy Markdown

Summary

Adds an opt-out createSchema option to the Postgres checkpointer and store. By default behavior is unchanged (setup() runs CREATE SCHEMA IF NOT EXISTS). When set to false, setup() instead verifies the
target schema already exists and throws a clear error if it doesn't — supporting least-privilege database roles that aren't permitted to create schemas. Table migrations run either way.

Motivation

In many production environments, the connecting role cannot create schemas; the schema is provisioned out-of-band by a DBA. The previous hardcoded CREATE SCHEMA IF NOT EXISTS either failed or required granting
elevated privileges. createSchema: false lets these deployments run setup()/migrations against a pre-existing schema.

Behavior

createSchema setup() behavior
true (default) CREATE SCHEMA IF NOT EXISTS — unchanged
false Verify schema exists; throw a descriptive error if missing

Error message when missing guides the user to either provision the schema out-of-band or set createSchema: true.

Usage

const checkpointer = PostgresSaver.fromConnString(connString, {
  schema: "custom_schema",
  createSchema: false, // verify the schema exists instead of creating it
});

@changeset-bot

changeset-bot Bot commented Jun 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: cc570c7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@langchain/langgraph-checkpoint-postgres Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@corridor-security corridor-security Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security Issues

  • SQL Injection
    The newly added schemaExistsSQL() helper directly interpolates the configurable schema value into a SQL string. If an attacker can influence this option in a deployment or tenant-provisioning flow, they can break out of the string literal and execute arbitrary SQL during setup() when createSchema: false is used.

Recommendations

  • Use parameterized queries for schema existence checks, e.g. WHERE schema_name = $1 with [schema] passed separately to client.query().
  • Avoid returning SQL strings that already contain user/config-controlled values embedded via template literals.

Comment thread libs/checkpoint-postgres/src/sql.ts Outdated
@pkg-pr-new

pkg-pr-new Bot commented Jun 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@langchain/langgraph-checkpoint

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint@2561

@langchain/langgraph-checkpoint-mongodb

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-mongodb@2561

@langchain/langgraph-checkpoint-postgres

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-postgres@2561

@langchain/langgraph-checkpoint-redis

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-redis@2561

@langchain/langgraph-checkpoint-sqlite

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-sqlite@2561

@langchain/langgraph-checkpoint-validation

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-checkpoint-validation@2561

create-langgraph

npm i https://pkg.pr.new/langchain-ai/langgraphjs/create-langgraph@2561

@langchain/langgraph-api

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-api@2561

@langchain/langgraph-cli

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-cli@2561

@langchain/langgraph

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph@2561

@langchain/langgraph-cua

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-cua@2561

@langchain/langgraph-supervisor

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-supervisor@2561

@langchain/langgraph-swarm

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-swarm@2561

@langchain/langgraph-ui

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-ui@2561

@langchain/langgraph-sdk

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/langgraph-sdk@2561

@langchain/angular

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/angular@2561

@langchain/react

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/react@2561

@langchain/svelte

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/svelte@2561

@langchain/vue

npm i https://pkg.pr.new/langchain-ai/langgraphjs/@langchain/vue@2561

commit: be94324

@alex-golubtsov Alex Golubtsov (alex-golubtsov) changed the title feat(postgres): optional schema creation feat(langgraph-checkpoint-postgres): optional schema creation Jun 20, 2026
@alex-golubtsov

Copy link
Copy Markdown
Author

Christian Bromann (@christian-bromann), when you have a moment, could you take a look at this PR? I’d really appreciate it

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, here is some feedback:

  • One consistency note: PostgresStore now has both ensureTables and createSchema, but PostgresSaver has neither ensureTables nor lazy auto-setup, so createSchema is the saver's first option of this kind. Can we stay consistent and keep the saver and store option surfaces aligned (e.g. eventually adding ensureTables to the saver too).
  • Small naming thought: ensureTables: false means "skip setup entirely," whereas createSchema: false means "still run setup/migrations, but verify the schema and throw if missing." A reader might expect createSchema: false to simply skip creation rather than assert. The throw-on-missing behavior is the right call, something like verifySchema/requireSchema would telegraph intent more clearly.
  • Two minor things: (a) PostgresStoreConfig.createSchema is optional but PostgresSaverOptions.createSchema is required-in-interface, both work given the different patterns, just noting the asymmetry. (b) Since this is a minor release, could you confirm whether Python langgraph's PostgresSaver/PostgresStore has an equivalent option, and match the name if so? Keeping the JS/Python APIs aligned would be ideal.

Comment thread .changeset/postgres-optional-schema-creation.md Outdated
@alex-golubtsov

Copy link
Copy Markdown
Author

Thanks for the PR, here is some feedback:

  • One consistency note: PostgresStore now has both ensureTables and createSchema, but PostgresSaver has neither ensureTables nor lazy auto-setup, so createSchema is the saver's first option of this kind. Can we stay consistent and keep the saver and store option surfaces aligned (e.g. eventually adding ensureTables to the saver too).
  • Small naming thought: ensureTables: false means "skip setup entirely," whereas createSchema: false means "still run setup/migrations, but verify the schema and throw if missing." A reader might expect createSchema: false to simply skip creation rather than assert. The throw-on-missing behavior is the right call, something like verifySchema/requireSchema would telegraph intent more clearly.
  • Two minor things: (a) PostgresStoreConfig.createSchema is optional but PostgresSaverOptions.createSchema is required-in-interface, both work given the different patterns, just noting the asymmetry. (b) Since this is a minor release, could you confirm whether Python langgraph's PostgresSaver/PostgresStore has an equivalent option, and match the name if so? Keeping the JS/Python APIs aligned would be ideal.

Pushed the changes.

Speaking of the Python implementation, I don’t think it has a similar option. I also don’t feel confident enough to contribute it myself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants