Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 92 additions & 65 deletions src/content/docs/workers/tutorials/postgres/index.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
updated: 2024-08-23
updated: 2025-07-01
difficulty: Beginner
pcx_content_type: tutorial
title: Connect to a PostgreSQL database with Cloudflare Workers
Expand Down Expand Up @@ -63,11 +63,15 @@ cd postgres-tutorial

## 2. Add the PostgreSQL connection library

To connect to a PostgreSQL database, you will need the `postgres` library. In your Worker application directory, run the following command to install the library:
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:

<PackageManagers pkg="postgres" />
<PackageManagers pkg="pg" />

Make sure you are using `postgres` (`Postgres.js`) version `3.4.4` or higher. `Postgres.js` is compatible with both Pages and Workers.
Next, install the TypeScript types for the `pg` library to enable type checking and autocompletion in your TypeScript code:

<PackageManagers pkg="@types/pg" dev />

Make sure you are using `pg` (`node-postgres`) version `8.16.3` or higher.

## 3. Configure the connection to the PostgreSQL database

Expand Down Expand Up @@ -116,7 +120,7 @@ Configure each database parameter as an [environment variable](/workers/configur
DB_USERNAME = "postgres"
# Set your password by creating a secret so it is not stored as plain text
DB_HOST = "ep-aged-sound-175961.us-east-2.aws.neon.tech"
DB_PORT = "5432"
DB_PORT = 5432
DB_NAME = "productsdb"
```

Expand All @@ -139,27 +143,34 @@ npx wrangler secret put DB_PASSWORD
Open your Worker's main file (for example, `worker.ts`) and import the `Client` class from the `pg` library:

```typescript
import postgres from "postgres";
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.

### Use a connection string

```typescript
const sql = postgres(env.DB_URL);
// create a new Client instance using the connection string
const sql = new Client({ connectionString: env.DB_URL });
// connect to the PostgreSQL database
await sql.connect();
```

### Set explicit parameters

```typescript
const sql = postgres({
// create a new Client instance using explicit parameters
const 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 database
await sql.connect();
```

## 5. Interact with the products database
Expand All @@ -184,30 +195,33 @@ CREATE TABLE products (
Replace the existing code in your `worker.ts` file with the following code:

```typescript
import postgres from "postgres";
import { Client } from "pg";

export default {
async fetch(request, env, ctx): Promise<Response> {
const sql = postgres(env.DB_URL, {
// Workers limit the number of concurrent external connections, so be sure to limit
// the size of the local connection pool that postgres.js may establish.
max: 5,

// If you are using array types in your Postgres schema, it is necessary to fetch
// type information to correctly de/serialize them. However, if you are not using
// those, disabling this will save you an extra round-trip every time you connect.
fetch_types: false,
});

// Query the products table
const result = await sql`SELECT * FROM products;`;

// Return the result as JSON
const resp = new Response(JSON.stringify(result), {
headers: { "Content-Type": "application/json" },
// 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,
});

return resp;
try {
// 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",
},
});
} finally {
// Clean up the client connection
await sql.end();
}
},
} satisfies ExportedHandler<Env>;
```
Expand All @@ -234,47 +248,60 @@ Assume the `products` table has the following columns: `id`, `name`, `descriptio

Add the following code snippet inside the `fetch` event handler in your `worker.ts` file, before the existing query code:

```typescript {9-32}
import postgres from "postgres";
```typescript {15-39}
import { Client } from "pg";

export default {
async fetch(request, env, ctx): Promise<Response> {
const sql = postgres(env.DB_URL);

const url = new URL(request.url);
if (request.method === "POST" && url.pathname === "/products") {
// Parse the request's JSON payload
const productData = await request.json();

// Insert the new product into the database
const values = {
name: productData.name,
description: productData.description,
price: productData.price,
};
const insertResult = await sql`
INSERT INTO products ${sql(values)}
RETURNING *
`;

// Return the inserted row as JSON
const insertResp = new Response(JSON.stringify(insertResult), {
headers: { "Content-Type": "application/json" },
// 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,
});
try {
// 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",
},
});

// Clean up the client
return insertResp;
} finally {
// Clean up the client connection
await sql.end();
}

// Query the products table
const result = await sql`SELECT * FROM products;`;

// Return the result as JSON
const resp = new Response(JSON.stringify(result), {
headers: { "Content-Type": "application/json" },
});

return resp;
},
} satisfies ExportedHandler<Env>;
```
Expand Down Expand Up @@ -344,7 +371,7 @@ Replace your existing connection string in your Worker code with the Hyperdrive
```js {3-3}
export default {
async fetch(request, env, ctx): Promise<Response> {
const sql = postgres(env.HYPERDRIVE.connectionString)
const sql = new Client({connectionString: env.HYPERDRIVE.connectionString})

const url = new URL(request.url);

Expand Down