Skip to content

Conversation

sorenbs
Copy link

@sorenbs sorenbs commented Oct 2, 2025

No description provided.

/**
* Minimal client for the Prisma Postgres Management API
*/
export class PrismaPostgresApi {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've been trying to move away from hand-coding the API clients.

Does Prisma have a generated TypeScript SDK for its control plane?

@john-royal has been standardizing our API generation with hey-api. @john-royal, maybe you can take a look at their API spec and see how well it generates.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have TypeScript SDK. hey-api looks really interesting.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be an option to use the hand-coded API client initially, and switch to a prisma provided SDK later?

@sam-goodwin sam-goodwin changed the title Add prisma postgres feat(prisma): prisma postgres Oct 2, 2025
@sam-goodwin sam-goodwin changed the title feat(prisma): prisma postgres feat(prisma): prisma postgres resources Oct 2, 2025
Copy link

pkg-pr-new bot commented Oct 2, 2025

Open in StackBlitz

npm i https://pkg.pr.new/alchemy-run/alchemy@1053

commit: 750e9b9

@sam-goodwin
Copy link
Collaborator

This is very exciting @sorenbs. Great job.

Does Prisma Postgres support branching? I found this doc which indicates it does: https://www.prisma.io/blog/introducing-platform-environments

One feature to make sure we nail here would be CI/CD (see https://alchemy.run/guides/ci/).

The ideal workflow is to have each PR deploy a branched copy of the infrastructure. It's not always possible depending on the service, but Planetscale and Neon each have branching capability exposed as Alchemy Resources that slot in nicely to Alchemy's CI/CD.

@sorenbs
Copy link
Author

sorenbs commented Oct 2, 2025

This is very exciting @sorenbs. Great job.

Does Prisma Postgres support branching? I found this doc which indicates it does: https://www.prisma.io/blog/introducing-platform-environments

One feature to make sure we nail here would be CI/CD (see https://alchemy.run/guides/ci/).

The ideal workflow is to have each PR deploy a branched copy of the infrastructure. It's not always possible depending on the service, but Planetscale and Neon each have branching capability exposed as Alchemy Resources that slot in nicely to Alchemy's CI/CD.

We don't support Branching natively yet, but we have the ability to create a database from a snapshot. Currently a snapshot can only be created from the Console UI - I will speak to the team about getting it enabled in the API. I believe that should enable a complete CI/CD workflow as you describe.

@sam-goodwin
Copy link
Collaborator

I believe that should enable a complete CI/CD workflow as you describe.

That's similar to what we do for D1.

Downside of this approach is cost, I'm assuming? Since it is a total copy?

Copy link
Collaborator

@Mkassabov Mkassabov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

haven't looked at the code but read through the docs written here.
Its a good start, but some of the default behavior seems to differ from what we do for alchemy usually.

We'd prefer if we could align here but if there are good reasons for it we're open to discussion

Comment on lines +39 to +49
const project = await Project("project", {
name: "prisma-app",
region: "us-east-1",
createDatabase: false,
});

const database = await Database("database", {
project,
name: "primary",
region: "us-east-1",
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it possible to make the region on database optional and just do project.region?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way the region selection works is this:

  • projects do not have a concept of region
  • when you create a project and specify createDatabase: true, then you need to specify the region. You will then get a database in that region
  • When you create a database in a project, you need to specify the region

To simplify things, what we could do in Alchemy is hide the ability to automatically create a database with the project. That would eliminate the region and createDatabase flags from Project creation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To simplify things, what we could do in Alchemy is hide the ability to automatically create a database with the project. That would eliminate the region and createDatabase flags from Project creation.

This seems like the right approach. Centralize database config on the Database resource rather than conflate them.

Comment on lines +21 to +30
## Rotate If Missing

If the underlying connection is deleted, rerunning the resource automatically creates a replacement with a fresh secret:

```ts
await DatabaseConnection("application", {
database,
name: "application",
});
```
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like this would work better as a tip on the create a connection section since you're explaining how the resource works not showing any unique configuration.

CC @JacobMGEvans

import { Database } from "alchemy/prisma/postgres";

const database = await Database("primary", {
project,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does project come from. its a bit ambiguous what project is here. Can we give an example with the simplest possible project?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch - thank you!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that Planetscale refers to orgs and databases by id instead of objects. Is that the preferred approach?

const devBranch = await Branch("feature-123", {
  name: "feature-123",
  organizationId: "my-org",
  databaseName: "my-database",
  parentBranch: "main",
  isProduction: false,
});

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that Planetscale refers to orgs and databases by id instead of objects. Is that the preferred approach?

No, but great question.

The preferred approach is to drop the Id suffix and use a union type. For example: organization: string | Organization.

The planetscale should be:

const devBranch = await Branch("feature-123", {
  name: "feature-123",
  organization: "my-org" | MyOrg,
  database: "my-database" | MyDatabase,
  parentBranch: "main",
  isProduction: false,
});

@Mkassabov we should make these changes in a separate PR.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sorenbs
better example is our new clickhouse provider:

const organizationId =
typeof props.organization === "string"
? await OrganizationRef(props.organization)
.then((organization) => organization.id!)
.catch(() => props.organization as string)
: props.organization.id!;

Comment on lines +13 to +16
const connection = await DatabaseConnection("application", {
database,
name: "application",
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does database come from. its a bit ambiguous what project is here. Can we give an example with the simplest possible database?

Comment on lines +27 to +32
const database = await Database("isolated", {
project,
name: "isolated",
region: "eu-central-1",
adopt: false,
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we generally have adopt: false and you have to specify it manually or run with the --adopt flag. can we keep that behavior consistent with the rest of alchemy here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I was unsure what to do, so thanks for calling it out.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inside a resource you need to check props.adopt ?? this.scope.adopt.

this.scope.adopt is how we apply blanket adopt across an app or scope.


## Promote to Default Database

Set `isDefault` to true to promote the database when the workspace allows it:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this makes me hesitant since it could be isDefault on multiple databases but only one of them promotes. It dilutes alchemy as being the sense of truth.

could we do something like canPromoteToDefault or at least an output property to show if something is the default?

name: "fresh-project",
region: "eu-central-1",
createDatabase: false,
adopt: false,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adopt should be false by default

@sorenbs
Copy link
Author

sorenbs commented Oct 4, 2025

I believe that should enable a complete CI/CD workflow as you describe.

That's similar to what we do for D1.

Downside of this approach is cost, I'm assuming? Since it is a total copy?

Yes, storage costs double. In you experience, is it a common use case to create a branch with the full production data? We haven't heard much request for this.

@sam-goodwin
Copy link
Collaborator

Yes, storage costs double. In you experience, is it a common use case to create a branch with the full production data? We haven't heard much request for this.

I don't see many people branch Prod, especially for a PR. But what we do care about is the cost per PR in terms of $$$ or quota consumption.

Prisma's free plan only allows 5 databases, which can be hit quite easily. So while a DB might be low $$$ cost when it contains less data, a PR still has a high, fixed "quota" cost.

image

@sorenbs
Copy link
Author

sorenbs commented Oct 4, 2025

I don't see many people branch Prod, especially for a PR.

👍

Prisma's free plan only allows 5 databases, which can be hit quite easily. So while a DB might be low $$$ cost when it contains less data, a PR still has a high, fixed "quota" cost.

We are currently fixing this by 10x-ing the db limits. So Free will give you 50 databases, and the $10 plan will include 100 dbs. As soon as a PR is closed, the database can be deleted and freed up for the next PR.

@sam-goodwin
Copy link
Collaborator

We are currently fixing this by 10x-ing the db limits. So Free will give you 50 databases, and the $10 plan will include 100 dbs. As soon as a PR is closed, the database can be deleted and freed up for the next PR.

Nice, sounds good. 100 databases is high enough to not worry about it.

Comment on lines +20 to +23
export const connection = await DatabaseConnection("connection", {
database,
name: "application",
});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also use hyperdrive ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hyperdrive and bind to a Worker would be killer demo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants