Connect to a PostgreSQL database with Cloudflare Workers
In this tutorial, you will learn how to create a Cloudflare Workers application and connect it to a PostgreSQL database using TCP Sockets and Hyperdrive. The Workers application you create in this tutorial will interact with a product database inside of PostgreSQL.
To continue:
- Sign up for a Cloudflare account ↗ if you have not already.
- Install
npm↗. - Install
Node.js↗. Use a Node version manager like Volta ↗ or nvm ↗ to avoid permission issues and change Node.js versions. Wrangler requires a Node version of16.17.0or later. - Make sure you have access to a PostgreSQL database.
First, use the create-cloudflare CLI ↗ to create a new Worker application. To do this, open a terminal window and run the following command:
npm create cloudflare@latest -- postgres-tutorialyarn create cloudflare postgres-tutorialpnpm create cloudflare@latest postgres-tutorialThis will prompt you to install the create-cloudflare ↗ package and lead you through a setup wizard.
For setup, select the following options:
- For What would you like to start with?, choose
Hello World example. - For Which template would you like to use?, choose
Worker only. - For Which language do you want to use?, choose
TypeScript. - For Do you want to use git for version control?, choose
Yes. - For Do you want to deploy your application?, choose
No(we will be making some changes before deploying).
If you choose to deploy, you will be asked to authenticate (if not logged in already), and your project will be deployed. If you deploy, you can still modify your Worker code and deploy again at the end of this tutorial.
Now, move into the newly created directory:
cd postgres-tutorialNode.js compatibility is required for database drivers, including Postgres.js, and needs to be configured for your Workers project.
To enable both built-in runtime APIs and polyfills for your Worker or Pages project, add the nodejs_compat compatibility flag to your Wrangler configuration file, and set your compatibility date to September 23rd, 2024 or later. This will enable Node.js compatibility for your Workers project.
{ "compatibility_flags": [ "nodejs_compat" ], "compatibility_date": "2024-09-23"}compatibility_flags = [ "nodejs_compat" ]compatibility_date = "2024-09-23"To connect to a PostgreSQL database, you will need the pg library. In your Worker application directory, run the following command to install the library:
npm i pgyarn add pgpnpm add pgNext, install the TypeScript types for the pg library to enable type checking and autocompletion in your TypeScript code:
npm i -D @types/pgyarn add -D @types/pgpnpm add -D @types/pgChoose one of the two methods to connect to your PostgreSQL database:
A connection string contains all the information needed to connect to a database. It is a URL that contains the following information:
postgresql://username:password@host:port/databaseReplace username, password, host, port, and database with the appropriate values for your PostgreSQL database.
Set your connection string as a secret so that it is not stored as plain text. Use wrangler secret put with the example variable name DB_URL:
npx wrangler secret put DB_URL➜ wrangler secret put DB_URL-------------------------------------------------------? Enter a secret value: › ********************✨ Success! Uploaded secret DB_URLSet your DB_URL secret locally in a .dev.vars file as documented in Local Development with Secrets.
DB_URL="<ENTER YOUR POSTGRESQL CONNECTION STRING>"Configure each database parameter as an environment variable via the Cloudflare dashboard or in your Wrangler file. Refer to an example of aWrangler file configuration:
{ "vars": { "DB_USERNAME": "postgres", "DB_HOST": "ep-aged-sound-175961.us-east-2.aws.neon.tech", "DB_PORT": 5432, "DB_NAME": "productsdb" }}[vars]DB_USERNAME = "postgres"# Set your password by creating a secret so it is not stored as plain textDB_HOST = "ep-aged-sound-175961.us-east-2.aws.neon.tech"DB_PORT = 5432DB_NAME = "productsdb"To set your password as a secret so that it is not stored as plain text, use wrangler secret put. DB_PASSWORD is an example variable name for this secret to be accessed in your Worker:
npx wrangler secret put DB_PASSWORD-------------------------------------------------------? Enter a secret value: › ********************✨ Success! Uploaded secret DB_PASSWORDOpen your Worker's main file (for example, worker.ts) and import the Client class from the pg library:
import { Client } from "pg";In the fetch event handler, connect to the PostgreSQL database using your chosen method, either the connection string or the explicit parameters.
// create a new Client instance using the connection stringconst sql = new Client({ connectionString: env.DB_URL });// connect to the PostgreSQL databaseawait sql.connect();// create a new Client instance using explicit parametersconst sql = new Client({ username: env.DB_USERNAME, password: env.DB_PASSWORD, host: env.DB_HOST, port: env.DB_PORT, database: env.DB_NAME, ssl: true, // Enable SSL for secure connections});// connect to the PostgreSQL databaseawait sql.connect();To demonstrate how to interact with the products database, you will fetch data from the products table by querying the table when a request is received.
Replace the existing code in your worker.ts file with the following code:
import { Client } from "pg";
export default { async fetch(request, env, ctx): Promise<Response> { // Create a new Client instance using the connection string // or explicit parameters as shown in the previous steps. // Here, we are using the connection string method. const sql = new Client({ connectionString: env.DB_URL, }); // Connect to the PostgreSQL database await sql.connect();
// Query the products table const result = await sql.query("SELECT * FROM products");
// Return the result as JSON return new Response(JSON.stringify(result.rows), { headers: { "Content-Type": "application/json", }, }); },} satisfies ExportedHandler<Env>;This code establishes a connection to the PostgreSQL database within your Worker application and queries the products table, returning the results as a JSON response.
Run the following command to deploy your Worker:
npx wrangler deployYour application is now live and accessible at <YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev.
After deploying, you can interact with your PostgreSQL products database using your Cloudflare Worker. Whenever a request is made to your Worker's URL, it will fetch data from the products table and return it as a JSON response. You can modify the query as needed to retrieve the desired data from your products database.
To insert a new row into the products table, create a new API endpoint in your Worker that handles a POST request. When a POST request is received with a JSON payload, the Worker will insert a new row into the products table with the provided data.
Assume the products table has the following columns: id, name, description, and price.
Add the following code snippet inside the fetch event handler in your worker.ts file, before the existing query code:
import { Client } from "pg";
export default { async fetch(request, env, ctx): Promise<Response> { // Create a new Client instance using the connection string // or explicit parameters as shown in the previous steps. // Here, we are using the connection string method. const sql = new Client({ connectionString: env.DB_URL, }); // Connect to the PostgreSQL database await sql.connect();
const url = new URL(request.url); if (request.method === "POST" && url.pathname === "/products") { // Parse the request's JSON payload const productData = (await request.json()) as { name: string; description: string; price: number; };
const name = productData.name, description = productData.description, price = productData.price;
// Insert the new product into the products table const insertResult = await sql.query( `INSERT INTO products(name, description, price) VALUES($1, $2, $3) RETURNING *`, [name, description, price], );
// Return the inserted row as JSON return new Response(JSON.stringify(insertResult.rows), { headers: { "Content-Type": "application/json" }, }); }
// Query the products table const result = await sql.query("SELECT * FROM products");
// Return the result as JSON return new Response(JSON.stringify(result.rows), { headers: { "Content-Type": "application/json", }, }); },} satisfies ExportedHandler<Env>;This code snippet does the following:
- Checks if the request is a
POSTrequest and the URL path is/products. - Parses the JSON payload from the request.
- Constructs an
INSERTSQL query using the provided product data. - Executes the query, inserting the new row into the
productstable. - Returns the inserted row as a JSON response.
Now, when you send a POST request to your Worker's URL with the /products path and a JSON payload, the Worker will insert a new row into the products table with the provided data. When a request to / is made, the Worker will return all products in the database.
After making these changes, deploy the Worker again by running:
npx wrangler deployYou can now use your Cloudflare Worker to insert new rows into the products table. To test this functionality, send a POST request to your Worker's URL with the /products path, along with a JSON payload containing the new product data:
{ "name": "Sample Product", "description": "This is a sample product", "price": 19.99}You have successfully created a Cloudflare Worker that connects to a PostgreSQL database and handles fetching data and inserting new rows into a products table.
Create a Hyperdrive configuration using the connection string for your PostgreSQL database.
npx wrangler hyperdrive create <NAME_OF_HYPERDRIVE_CONFIG> --connection-string="postgres://user:password@HOSTNAME_OR_IP_ADDRESS:PORT/database_name" --caching-disabledThis command outputs the Hyperdrive configuration id that will be used for your Hyperdrive binding. Set up your binding by specifying the id in the Wrangler file.
{ "name": "hyperdrive-example", "main": "src/index.ts", "compatibility_date": "2024-08-21", "compatibility_flags": [ "nodejs_compat" ], "hyperdrive": [ { "binding": "HYPERDRIVE", "id": "<ID OF THE CREATED HYPERDRIVE CONFIGURATION>" } ]}name = "hyperdrive-example"main = "src/index.ts"compatibility_date = "2024-08-21"compatibility_flags = ["nodejs_compat"]
# Pasted from the output of `wrangler hyperdrive create <NAME_OF_HYPERDRIVE_CONFIG> --connection-string=[...]` above.[[hyperdrive]]binding = "HYPERDRIVE"id = "<ID OF THE CREATED HYPERDRIVE CONFIGURATION>"Create the types for your Hyperdrive binding using the following command:
npx wrangler typesReplace your existing connection string in your Worker code with the Hyperdrive connection string.
export default { async fetch(request, env, ctx): Promise<Response> { const sql = new Client({connectionString: env.HYPERDRIVE.connectionString})
const url = new URL(request.url);
//rest of the routes and database queries },} satisfies ExportedHandler<Env>;Run the following command to deploy your Worker:
npx wrangler deployYour Worker application is now live and accessible at <YOUR_WORKER>.<YOUR_SUBDOMAIN>.workers.dev, using Hyperdrive. Hyperdrive accelerates database queries by pooling your connections and caching your requests across the globe.
To build more with databases and Workers, refer to Tutorials and explore the Databases documentation.
If you have any questions, need assistance, or would like to share your project, join the Cloudflare Developer community on Discord ↗ to connect with fellow developers and the Cloudflare team.
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2025 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark