core icon indicating copy to clipboard operation
core copied to clipboard

Support multiple bindings (databases/kv)

Open RihanArfan opened this issue 1 year ago • 9 comments

Is your feature request related to a problem? Please describe. Right now NuxtHub adds a single binding for whatever feature is enabled in the config with a hardcoded binding name.

Describe the solution you'd like It would be nice if an array could be specified alongside the boolean to allow multiple bindings, and access them by specifying them within the hubX() util.

Old code example

export default defineNuxtConfig({
  hub: {
    kv: [
      {
        binding: "CONFIG",
        id: "abcdefg"
      },
      {
        binding: "ANOTHER",
        id: "foobar"
      }
    ],
    database: true
  },
})

const anotherKeys = await hubKV("ANOTHER").keys()
const keys = await hubKV().keys() // would use the default binding

Here's another more configurable potential option which covers everything from fully NuxtHub managed single binding, to fully custom user managed multiple bindings, and everything in between.

export default defineNuxtConfig({
  hub: {
    /**
     * Database
     */
    // default database that NuxtHub creates
    database: true,

    // default custom database across all environments
    // during local development and preview, NuxtHub use the same database
    database: 'your-database-id',

    // default custom database for production only
    // during local development and preview (omitted envs), NuxtHub creates a new database
    database: {
      default: { production: 'your-database-id' }
    },

    // multiple database bindings via different methods
    database: {
      default: { production: 'your-database-id' },
      db: true, // will error, can't have default and DB at the same time - they're the same

      prices: 'your-database-id' // binding added as PRICES, used via hubDatabase('prices')
    },

    /**
     * R2 & KV
     */
    // same concept as database

    /**
     * Vectorize
     */
    // user needs to create metadata indexes via cli
    // handling creation of (metadata) indexes etc. is far too complex for via config imo
    vectorize: {
      products: {
        production: 'your-vectorize-id',
        preview: 'your-vectorize-id',
        development: 'your-vectorize-id'
      },
      reviews: {
        production: 'your-vectorize-id',
        preview: 'your-vectorize-id',
        development: 'your-vectorize-id'
      }
    },

    /**
     * Other bindings
     */
    bindings: {
      hyperdrive: {
        // <BINDING_NAME>: <HYPERDRIVE_ID>
        POSTGRES: 'your-hyperdrive-id'
      }
    }
  }
})

RihanArfan avatar Jun 19 '24 16:06 RihanArfan

Hey @RihanArfan

We indeed imagined the ability to switch between bindings but I did not want to make it too complex to start with, it's very rare the need for multiple databases / KV / R2 and also it may also complexify the admin.

But if we have to work on it, I would see it this way:

export default defineNuxtConfig({
  hub: {
    database: {
      // alias: BINDING
      default: 'DB', // always added
      users: 'USERS'
    }
  },
})

Then you can do:

const db =  hubDatabase() // default
const usersDb = hubDatabase('users')

We should not have to specify any ID as NuxtHub should take care of this for us.

atinux avatar Jun 20 '24 05:06 atinux

Hey @Atinux,

Your proposal looks really good to me. I just wanted to add some notes because I think there are definitely use cases where it makes sense to have multiple D1 instances, for example. Since D1 has a maximum limit of 10 GB (see D1 Limit Documentation), it might be useful to split data into multiple databases. Another use case could be to use one database for each customer in an application.

nicogenz avatar Jun 21 '24 18:06 nicogenz

@nicogenz the main issue for having a use case as "one database for each user" is that you cannot add new database at runtime and you actually need to rebuild your website for the bindings to take effect.

atinux avatar Jun 25 '24 08:06 atinux

@atinux, Can we also explore multiple R2 buckets per project? For multi-tenant SaaS, isolating file uploads to separate R2 buckets per tenant is crucial for accurate cost mapping.

mendrinos avatar Sep 06 '24 11:09 mendrinos

Looks like dynamic bindings is coming to Vectorize in Q1 2025, and I guess other services may get this too image

RihanArfan avatar Sep 19 '24 17:09 RihanArfan

+1 for multiple db bindings. I'd like to keep my logs and other large debug/history tables in a seperate db to make sure I don't come up against the 10GB limit. So ideally I'd like to be able to decide at runtime which db to insert against. Thanks!

alexcroox avatar Oct 09 '24 15:10 alexcroox

+1 for multiple bindings, would be great to use this for having a local test database different from my local database - allowing me to have a db sandbox for e2e testing for endpoints

acidjazz avatar Jan 21 '25 03:01 acidjazz

+1 multiple bindings: https://github.com/nuxt-hub/core/issues/488 @atinux Use case: Nuxt 3 monorepo with different layers such as CMS, Ecommerce, Logs, etc. Not thousands per user that doesn't require creation in runtime, but still necessary to separate logic, especially in cases when the layers could be dynamically enabled/disabled for SaaS purposes.

serhii-chernenko avatar Mar 01 '25 13:03 serhii-chernenko

Is it possible to do the binding on the fly using the rest api's? First the create the d1 and then bind it to the worker?

This is really the only thing stopping me from using Nuxt Hub / Cloudflare.

shaunnbarron avatar Mar 24 '25 05:03 shaunnbarron