prisma: Prisma Client Edge: environment variables are not working with the "new" Module Worker syntax for Cloudflare Workers

Problem

According to the recent changes in Cloudflare Workers (https://developers.cloudflare.com/workers/runtime-apis/fetch-event/) & Wrangler CLI, Environment Variables access Model, environment variables aren’t globally available anymore & in the generated edge client a Database Url is accessed through process.env.DATABASE_URL (which workers on Vercel Edge Functions) or using global. I think the Prisma Client should accept Database Url when it’s instantiated, because Different Edge Platform have their own way of accessing environment variables for example, in Netlify Edge Functions, it’s like

const db_url = Deno.env.get("DATABASE_URL");

and in Cloudflare Workers, it’s like

export default {  
  fetch(request, env, context) {
    const db_url = env.DATABASE_URL;
  },
};

or in fastly compute edge using dictionaries, it’s like

  const tokens = new Dictionary("tokens");
  const db_url = tokens.get("DATABASE_URL");

Suggested solution

I think Prisma Client should accept a datebase url when it’s instantiated like

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient({
  url: "" // Pass Database Url
});

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 31 (15 by maintainers)

Most upvoted comments

@janpio Would a viable option for cloudflare be requiring the datasource to be setup manually?

// For new module syntax
export default {
  async fetch(request, env) {
    const prisma = new PrismaClient({
      datasources: {
        db: {
          url: env.DATABASE_URL, // DATABASE_URL is placed in env in module syntax.
        },
      },
    });
    const users = await prisma.user.findMany();
    return Response.json(users);
  },
}

// For service worker syntax
const prisma = new PrismaClient({
  datasources: {
    db: {
      url: DATABASE_URL, // DATABASE_URL is placed in global scope for service worker syntax.
    },
  },
});
addEventListener('fetch', (event) => {
  const users = await prisma.user.findMany();
  event.respondWith(Response.json(users);
});

If so, this would be as simple as removing these lines from the generator.

Indeed, there is now a new syntax from Cloudflare since 16/11/2021 https://blog.cloudflare.com/workers-javascript-modules/

Both are supported.

Old syntax = Service Worker

When a Worker is deployed using the Service Worker syntax, any bindings will be made available as global runtime variables.

addEventListener('fetch', event => {
  event.respondWith(new Response('Hello'));
});

New Syntax = Module Worker

When deploying a Module Worker, any bindings will not be available as global runtime variables. Instead, they are passed to the handler as a parameter – refer to env in Parameters.

export default {
  fetch(request, env, context) {
    return new Response('Hello');
  },
};

Benefits from https://developers.cloudflare.com/workers/learning/migrating-to-module-workers/

  • Durable Objects require the module syntax.
  • Module Workers do not rely on any global bindings, which means the Workers runtime does not need to set up fresh execution contexts, making Module Workers safer and faster to run.
  • Module Workers are ES Modules, which allows them to be shared and published to npm, for example. Module Workers can be imported by and composed within other Module Workers.

I have been using Cloudflare Workers & the new Workers Module Syntax exposes environment variables with env arguments passed to the fetch function & accessing environment variables globally is going to fail.

export default {  
  fetch(request, env, context) { 
    console.log(DATABASE_URL) // is going to fail
    console.log(env.DATABASE_URL) // works
  },
};

so, globalThis[“DATABASE_URL”] is going to fail, can you improve it, please. Thanks.

I have tried this with two reproductions and can confirm this is no longer an issue on recent wrangler versions. As for the confusing error messages regarding the environment variables, we have just improved it.

This seems to still be an issue today with the latest version of Prisma.

In my case, I have a monorepo with a db package that creates the Prisma client (using '@prisma/client/edge'). Another package in the same repo imports the client, and when starting up the Cloudflare Worker server via Wrangler, I get this error: InvalidDatasourceError: Datasource "db" references an environment variable

@janpio what’s the recommended solution?

Just came across this one… I ended up using a CF system environment variable in my schema file, and then overriding the constructor options:

datasource db {
  provider = "mongodb"
  url      = env("CLOUDFLARE_ACCOUNT_ID")
}
let db: PrismaClient;

declare global {
  var __db: PrismaClient | undefined;
}

export function getDb(args: DataFunctionArgs) {
  const options = {
    datasources: {
      db: {
        url: args.context.DATABASE_URL as string,
      }
    }
  };

  if (process.env.NODE_ENV === "production") {
    if (!db) db = new PrismaClient(options);
  } else {
    if (!global.__db) {
      global.__db = new PrismaClient(options);
    }
    db = global.__db!;
  }

  return db;
}

Seems to be working - it’s not moaning since CLOUDFLARE_ACCOUNT_ID is known to Wrangler I guess.

Somewhat related, I tried following the steps for setting this up on Vercel Edge Functions (https://www.prisma.io/blog/database-access-on-the-edge-8F0t1s1BqOJE) but I’m getting the same issue, my environment variables aren’t being set at all during runtime. Setting it with process.env.DATABASE_URL in the constructor isn’t working either.

Totally understandable. This is nasty. We’ll try to figure it out, step by step. Thanks for your inforamtion anyway.

Oh man I can’t remember anymore, I ended up just creating a completely separate API layer that my remix + cloudflare application was using. I know I couldn’t fully get it working for all the scenarios I cared about, and moved away from the solution.

Note: we could do a reproduction in prisma/ecosystem-tests Based on https://github.com/prisma/ecosystem-tests/tree/dev/dataproxy/cloudflare-workers But using wrangler v2 with Module syntax

I think someone who’s starting a new Cloudflare Workers Project with Wrangler CLI version 2 will use the Module Syntax, because wrangler 2 generates a project with a Module Syntax by default, people will see many applications crashes, so please update the environment variables default accessing method. Thanks.