# Deploying with Alchemy (/docs/guides/cloudflare-alchemy)



## Overview [#overview]

[Alchemy](https://alchemy.run) is the infrastructure-as-code layer generated when you choose **Cloudflare** or **Prisma** as a deployment target. The CLI writes a `packages/infra` workspace containing:

* one `alchemy.run.ts` for applications, managed databases, and migrations
* exact selected Alchemy and latest Effect beta versions
* root `dev`, `deploy`, and `destroy` commands

The CLI calls the deployment choice **Prisma**. In the generated TypeScript, that target uses Alchemy's `Prisma.Compute` resource.

## Supported deployment shapes [#supported-deployment-shapes]

Cloudflare supports a separate Hono server on the Workers runtime and supported web frameworks. Full-stack `backend: self` projects deploy as one web application.

Prisma supports:

* web: Next.js, Nuxt, Astro, React Router, TanStack Start, SvelteKit, and Solid
* server: Hono, Express, Fastify, and Elysia on Bun or Node
* mixed stacks, such as Cloudflare web + Prisma server or Prisma web + Cloudflare server

The CLI rejects unsupported framework/runtime combinations before writing files.

Alchemy's automatic framework builds handle Next.js, Nuxt, Astro, and TanStack Start. The generated
stack supplies explicit production artifacts for the remaining frameworks: Solid's Nitro
server, React Router's documented custom Express server, and SvelteKit's official `adapter-node`
server. TanStack Router is rejected for Prisma deployment because it emits static SPA assets while
`Prisma.Compute` requires an executable server artifact; the generator does not synthesize a static
file server or use Vite's development-oriented preview command.

Cloudflare web deployment uses Alchemy's released framework resources where they match the
generated stable framework: `Website.Nuxt` for Nuxt, `Website.Astro` for Astro, and `Website.Vite`
for React Router, TanStack Router, TanStack Start, and Solid. Next.js and stable SvelteKit keep
their qualified `StaticSite` paths until the released first-class resources accept the latest
OpenNext and stable SvelteKit versions.

Prisma with a generic `node-postgres` connection, including PlanetScale Postgres and Supabase, is
temporarily unavailable with Next.js on Cloudflare until OpenNext preserves `pg-cloudflare`'s
workerd runtime files.

Next.js with Neon or Prisma Postgres remains supported on Cloudflare. The same PlanetScale
Postgres Prisma setup remains supported with the other Cloudflare SSR frontends or with Prisma,
Docker, or Vercel deployment.

```bash
# Full-stack Solid on Prisma with PlanetScale MySQL
bunx create-better-t-stack@latest my-app \
  --frontend solid \
  --backend self \
  --database mysql \
  --orm prisma \
  --db-setup planetscale \
  --web-deploy prisma

# Next.js on Cloudflare and a Hono/Bun server on Prisma
bunx create-better-t-stack@latest my-app \
  --frontend next \
  --backend hono \
  --runtime bun \
  --database postgres \
  --orm prisma \
  --db-setup neon \
  --web-deploy cloudflare \
  --server-deploy prisma
```

## Provider login [#provider-login]

Install dependencies, then let Alchemy configure every provider used by the stack:

```bash
bun install
cd packages/infra
bunx alchemy login --configure
```

Alchemy stores selected provider profiles under `~/.alchemy`. A generated managed-database stack does not run the Neon, PlanetScale, or Prisma CLI separately and does not ask you to copy a hosted `DATABASE_URL` into the application.

## Managed databases [#managed-databases]

Alchemy manages Neon, PlanetScale, or Prisma Postgres only when the application plane that consumes the database is also deployed through Alchemy:

* `backend: self`: the web deployment owns the database
* separate backend: the server deployment owns the database

This distinction matters in mixed stacks. A Prisma web app with a Vercel server, for example, keeps the server database external because the Vercel server is the database consumer.

| Setup                | Generated behavior                                                                                                |
| -------------------- | ----------------------------------------------------------------------------------------------------------------- |
| Neon                 | Creates a Neon project, uses the pooled URL at runtime, and the direct URL for migrations                         |
| PlanetScale Postgres | Creates a `PS_DEV` database and a least-privilege runtime role; Prisma gets a short-lived migration role          |
| PlanetScale MySQL    | Creates a `PS_DEV` database and a read/write runtime password; Prisma gets a short-lived admin migration password |
| Prisma Postgres      | Creates the project, database, and connection and injects its pooled application URL                              |
| Cloudflare D1        | Creates a native D1 binding and applies the generated migration directory                                         |

<Callout type="warn">
  PlanetScale can charge for `PS_DEV` databases. Review `clusterSize` in
  `packages/infra/alchemy.run.ts` before deploying.
</Callout>

## Migration workflow [#migration-workflow]

Database schemas remain source controlled. Generate and review migrations during development:

```bash
# Drizzle: generate SQL from the current schema
bun run db:generate

# Prisma: create a migration, then regenerate the client
bun run db:migrate
bun run db:generate
```

Managed Prisma projects include an initial checked-in migration when the scaffold generates Better Auth or Todo models. On deployment, Alchemy runs `db:migrate:deploy` with a migration credential and memoizes it against the checked-in schema and migration files. Drizzle's Neon and PlanetScale resources apply the checked-in Drizzle migration directory directly; Prisma Postgres uses `drizzle-kit migrate` through the same deploy-time command resource.

## Develop and deploy [#develop-and-deploy]

Run these commands from the project root:

```bash
bun run dev
bun run deploy
bun run destroy
```

`bun run dev` starts Alchemy development alongside the generated applications. Application packages expose `dev:bare` internally so the root command does not recursively start Alchemy again.

For Nuxt and Astro on Cloudflare, Alchemy owns the deployment build and injects its Cloudflare
integration in memory. Nuxt keeps its ordinary framework `build` command for local verification;
Astro's Cloudflare scaffold relies on the Alchemy lifecycle because a standalone server build would
need a competing checked-in adapter.

<Callout type="info">
  Generated projects pin `alchemy@2.0.0-beta.72` with Effect rc.108 exactly. The framework source
  package is installed in the web workspace that Alchemy loads it from, so Bun, npm, and pnpm can
  resolve compatible graphs without overrides or hoisting assumptions.
</Callout>

Deployments are staged. For an explicit production stage:

```bash
cd packages/infra
bunx alchemy deploy --stage production
```

Use the same stage when destroying it:

```bash
bunx alchemy destroy --stage production
```

## Environment variables and secrets [#environment-variables-and-secrets]

The stack loads `packages/infra/.env` plus the relevant app `.env` files. Public configuration uses `Config.string`; secrets use `Config.redacted`. Alchemy Outputs, such as a deployed server URL or database credential, are passed directly so resource dependency ordering is preserved.

For Cloudflare, generated `Cloudflare.InferEnv` types flow into `packages/env/env.d.ts`. Managed database bindings are individual Effect inputs, which keeps each runtime property precisely typed.

## Generated infrastructure [#generated-infrastructure]

A managed Prisma Postgres project is conceptually structured like this:

```ts
const project = Prisma.Project("project", {
  createDatabase: false,
  region: "us-east-1",
});

const database = yield * Prisma.Postgres("database", { project });
const connection = yield * Prisma.Connection("database-connection", { database });

yield *
  Command.Exec("database-migrations", {
    command: "bun run db:migrate:deploy",
    cwd: "../../packages/db",
    env: { DATABASE_URL: migrationUrl },
    memo: { include: ["prisma/migrations/**", "prisma/schema/**"] },
  });
```

The generated file is normal TypeScript. You can add resources or adjust regions and sizes while preserving the root lifecycle commands.

For Nuxt + Prisma on Cloudflare, server-side oRPC calls use Nitro's in-process `event.fetch` against
the generated `/rpc` route. This keeps the database client in Nitro's server graph only, avoids a
second Prisma WASM copy in the page graph, and keeps the generated Worker below Cloudflare's 3 MB
compressed free-plan limit.

## Version policy [#version-policy]

Alchemy v2 is still a beta. Better-T-Stack pins one exact Alchemy version together with the selected
Effect release candidate, currently `4.0.0-rc.108`, because open prerelease ranges can select
unintended publications. A pinned set is not called compatible until the CLI starts and the complete
generated-project and live gates pass. Upgrade these packages as one verified set rather than
changing one dependency independently.
