-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add support for extra bindings (Hyperdrive) (#245)
- Loading branch information
Showing
15 changed files
with
497 additions
and
342 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
--- | ||
title: PostgreSQL Database | ||
navigation.title: PostgreSQL | ||
description: Learn how to use PostgreSQL in your Nuxt application deployed on Cloudflare Workers / Pages and how to speed up your queries using Hyperdrive. | ||
--- | ||
|
||
## Pre-requisites | ||
|
||
Cloudflare does not host PostgreSQL databases, you need to setup your own PostgreSQL database. | ||
|
||
::note{to="https://www.postgresql.org/support/professional_hosting/" target="_blank" icon="i-logos-postgresql"} | ||
See a list of professional PostgreSQL hosting providers. | ||
:: | ||
|
||
If you prefer to use Cloudflare services, you can use Cloudflare D1 which is built on SQLite, see our [Database](/docs/features/database) section. | ||
|
||
## Setup | ||
|
||
1. Make sure to use the `@nuxthub/core` module, see the [installation section](/docs/getting-started/installation#add-to-a-nuxt-project) for instructions. | ||
|
||
```ts [nuxt.config.ts] | ||
export default defineNuxtConfig({ | ||
modules: ['@nuxthub/core',], | ||
}); | ||
``` | ||
|
||
::note | ||
The module ensures that you can connect to your PostgreSQL database using [Cloudflare TCP Sockets](https://developers.cloudflare.com/workers/runtime-apis/tcp-sockets/.) | ||
:: | ||
|
||
2. Install the [`postgres`](https://www.npmjs.com/package/postgres) NPM package in your project. | ||
|
||
```bash | ||
npx nypm add postgres | ||
``` | ||
|
||
::tip{icon="i-ph-rocket-launch"} | ||
That's it, you can now use the `postgres` package to connect to your PostgreSQL database. | ||
:: | ||
|
||
::warning | ||
Please note that [`pg`](https://www.npmjs.com/package/pg) is not compatible at the moment. | ||
:: | ||
|
||
## Usage | ||
|
||
We can add our PostgreSQL database connection in our `.env` file. | ||
|
||
```bash [.env] | ||
NUXT_POSTGRES_URL=postgresql://user:password@localhost:5432/database | ||
``` | ||
|
||
Then, we can create a `usePostgres()` server util to connect to our database in our API route. | ||
|
||
```ts [server/utils/postgres.ts] | ||
import postgres from 'postgres' | ||
|
||
export function usePostgres () { | ||
if (!process.env.NUXT_POSTGRES_URL) { | ||
throw createError('Missing `NUXT_POSTGRES_URL` environment variable') | ||
} | ||
|
||
return postgres(process.env.NUXT_POSTGRES_URL as string, { | ||
ssl: 'require' | ||
}) | ||
} | ||
``` | ||
|
||
We can now use the `usePostgres()` function to connect to our database in our API route. | ||
|
||
```ts [server/api/db.ts] | ||
export default eventHandler(async (event) => { | ||
const sql = usePostgres() | ||
|
||
const products = await sql`SELECT * FROM products` | ||
|
||
// Ensure the database connection is closed after the request is processed | ||
event.waitUntil(sql.end()) | ||
return products | ||
}) | ||
``` | ||
|
||
::tip | ||
You may notice that we don't import `usePostgres()`. This is because Nuxt auto-imports the exported variables & functions from `server/utils/*.ts` when used. | ||
:: | ||
|
||
## Hyperdrive | ||
|
||
[Hyperdrive](https://developers.cloudflare.com/hyperdrive/) is a Cloudflare service that accelerates queries you make to existing databases, making it faster to access your data from across the globe. By maintaining a connection pool to your database within Cloudflare’s network, Hyperdrive reduces seven round-trips to your database before you can even send a query: the TCP handshake (1x), TLS negotiation (3x), and database authentication (3x). | ||
|
||
::important{to="https://developers.cloudflare.com/hyperdrive/platform/pricing/" target="_blank"} | ||
Hyperdrive is only available on the Workers Paid plan ($5/month), **learn more**. | ||
:: | ||
|
||
To use Hyperdrive in your Nuxt application: | ||
1. [Create a Hyperdrive configuration](https://dash.cloudflare.com/?to=/:account/workers/hyperdrive/create) | ||
2. Add your Hyperdrive ID in your `nuxt.config.ts` file | ||
|
||
```ts [nuxt.config.ts] | ||
export default defineNuxtConfig({ | ||
modules: ['@nuxthub/core'], | ||
hub: { | ||
bindings: { | ||
hyperdrive: { | ||
// <BINDING_NAME>: <HYPERDRIVE_ID> | ||
POSTGRES: 'your-hyperdrive-id' | ||
} | ||
} | ||
} | ||
}) | ||
``` | ||
|
||
3. Update our `usePostgres()` function to use the `POSTGRES` binding when available. | ||
|
||
```ts [server/utils/postgres.ts] | ||
import type { Hyperdrive } from '@cloudflare/workers-types' | ||
import postgres from 'postgres' | ||
|
||
export function usePostgres() { | ||
const hyperdrive = process.env.POSTGRES as Hyperdrive | undefined | ||
const dbUrl = hyperdrive?.connectionString || process.env.NUXT_POSTGRES_URL | ||
if (!dbUrl) { | ||
throw createError('Missing `POSTGRES` hyperdrive binding or `NUXT_POSTGRES_URL` env variable') | ||
} | ||
|
||
return postgres(dbUrl, { | ||
ssl: !hyperdrive ? 'require' : undefined | ||
}) | ||
} | ||
``` | ||
|
||
::warning | ||
Hyperdrive is currently not available in development mode at the moment. We are working on a solution to make it work in development mode and remote storage with an upcoming `hubHyperdrive()`. | ||
:: | ||
|
||
4. [Deploy your application](/docs/getting-started/deploy) with the NuxtHub CLI or Admin to make sure the Hyperdrive bindings are set. | ||
|
||
::tip{icon="i-ph-rocket-launch"} | ||
You can now access your PostgreSQL database from anywhere in the world at maximum speed. | ||
:: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--- | ||
title: Hyperdrive bindings | ||
description: "It is now possible to use PostgreSQL & Cloudflare Hyperdrive in your Nuxt application." | ||
date: 2024-08-28 | ||
image: '/images/changelog/hyperdrive-bindings.png' | ||
category: Admin | ||
authors: | ||
- name: Sebastien Chopin | ||
avatar: | ||
src: https://avatars.githubusercontent.com/u/904724?v=4 | ||
to: https://x.com/atinux | ||
username: atinux | ||
--- | ||
|
||
If you are not comfortable with Cloudflare D1 database (SQLite), you can now use your own PostgreSQL database. | ||
|
||
We wrote a recipe on [How to use a PostgreSQL database](/docs/recipes/postgres) with NuxtHub. | ||
|
||
This recipe explains how to connect to your PostgreSQL database and how to leverage Hyperdrive bindings in your Nuxt application to accelerate your database responses. | ||
|
||
::callout | ||
Right now, hyperdrive bindings are not available in development mode, we are working with the Cloudflare team to make them available in development mode as well with remote storage. | ||
:: | ||
|
||
::tip | ||
This feature is available on both [free and pro plans](/pricing) and in [`@nuxthub/core >= v0.7.6`](https://github.com/nuxt-hub/core/releases/tag/v0.7.6). | ||
:: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Used for /api/hyperdrive | ||
NUXT_POSTGRES_URL= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import type { Hyperdrive } from '@cloudflare/workers-types' | ||
import postgres from 'postgres' | ||
|
||
export default eventHandler(async (event) => { | ||
const hyperdrive = process.env.POSTGRES as Hyperdrive | undefined | ||
const dbURL = hyperdrive?.connectionString || process.env.NUXT_POSTGRES_URL | ||
|
||
if (!dbURL) { | ||
throw createError({ | ||
statusCode: 500, | ||
message: 'No process.env.NUXT_POSTGRES_URL or provess.env.HYPERDRIVE found' | ||
}) | ||
} | ||
const sql = postgres(dbURL, { | ||
ssl: import.meta.dev ? 'require' : false | ||
}) | ||
|
||
// Create products table | ||
// await db.query('CREATE TABLE IF NOT EXISTS products (id SERIAL PRIMARY KEY, name VARCHAR(255), price DECIMAL(10, 2))') | ||
// // Insert 10 products | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 1', 10.00]) | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 2', 20.00]) | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 3', 30.00]) | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 4', 40.00]) | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 5', 50.00]) | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 6', 60.00]) | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 7', 70.00]) | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 8', 80.00]) | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 9', 90.00]) | ||
// await db.query('INSERT INTO products (name, price) VALUES ($1, $2)', ['Product 10', 100.00]) | ||
|
||
console.log('query products') | ||
const products = await sql`SELECT * FROM products` | ||
|
||
event.waitUntil(sql.end()) | ||
return products | ||
}) |
Oops, something went wrong.