diff --git a/content/200-orm/200-prisma-client/500-deployment/301-edge/550-deploy-to-deno-deploy.mdx b/content/200-orm/200-prisma-client/500-deployment/301-edge/550-deploy-to-deno-deploy.mdx index 88c15dfb4c..b5abc7c3dd 100644 --- a/content/200-orm/200-prisma-client/500-deployment/301-edge/550-deploy-to-deno-deploy.mdx +++ b/content/200-orm/200-prisma-client/500-deployment/301-edge/550-deploy-to-deno-deploy.mdx @@ -1,305 +1,363 @@ --- title: 'Deploy to Deno Deploy' metaTitle: 'Deploy to Deno Deploy' -metaDescription: 'Learn how to deploy a TypeScript application to Deno Deploy.' +metaDescription: 'Learn how to deploy a TypeScript application using Prisma ORM to Deno Deploy.' --- +With this guide, you can learn how to build and deploy a REST API to [Deno Deploy](https://deno.com/deploy). The application uses Prisma ORM to manage tasks in a [Prisma Postgres](/postgres) database. - -With this guide, you can learn how to build and deploy a simple application to [Deno Deploy](https://deno.com/deploy). The application uses Prisma ORM to save a log of each request to a [Prisma Postgres](/postgres) database. - -This guide covers the use of Prisma CLI with Deno CLI, Deno Deploy, Prisma Client, and Prisma Postgres. +This guide covers Deno CLI, Deno Deploy, Prisma Client with the Postgres adapter, and Prisma Postgres. :::tip Use Prisma ORM without Rust binaries -If Prisma ORM's Rust engine binaries cause large bundle sizes, slow builds, or deployment issues (for example, in serverless or edge environments), you can use it without them using this configuration of your `generator` block: - -```prisma -generator client { - provider = "prisma-client-js" // or "prisma-client" - engineType = "client" -} -``` - -Prisma ORM without Rust binaries has been [Generally Available](/orm/more/releases#generally-available-ga) since [v6.16.0](https://pris.ly/release/6.16.0). - -Note that you need to use a [driver adapter](/orm/overview/databases/database-drivers#driver-adapters) in this case. - -When using this architecture: +This guide uses Prisma ORM with the Postgres adapter, which runs entirely in TypeScript without Rust engine binaries. This architecture is ideal for Deno and edge runtimes: -- No Rust query engine binary is downloaded or shipped. -- The database connection pool is maintained by the native JS database driver you install (e.g., `@prisma/adapter-pg` for PostgreSQL). +- No Rust query engine binary is downloaded or shipped +- Smaller bundle sizes and faster cold starts +- The database connection pool is managed by the native driver -This setup can simplify deployments in serverless or edge runtimes. Learn more in the [docs here](/orm/prisma-client/setup-and-configuration/no-rust-engine). - -Curious why we moved away from the Rust engine? Take a look at why we transitioned from Rust binary engines to an all-TypeScript approach for a faster, lighter Prisma ORM in this [blog post](https://www.prisma.io/blog/prisma-orm-without-rust-latest-performance-benchmarks). +Learn more in the [Prisma without Rust engine docs](/orm/prisma-client/setup-and-configuration/no-rust-engine). ::: - ## Prerequisites -- a free [Prisma Data Platform](https://console.prisma.io/login) account -- a free [Deno Deploy](https://deno.com/deploy) account -- Node.js & npm installed -- Deno v1.29.4 or later installed. [Learn more](https://docs.deno.com/runtime/#install-deno). -- (Recommended) Latest version of Prisma ORM. -- (Recommended) Deno extension for VS Code. [Learn more](https://docs.deno.com/runtime/reference/vscode/). +- A free [Prisma Data Platform](https://console.prisma.io/login) account +- A free [Deno Deploy](https://deno.com/deploy) account +- [Deno](https://docs.deno.com/runtime/#install-deno) v2.0 or later installed +- (Recommended) [Deno extension for VS Code](https://docs.deno.com/runtime/reference/vscode/) -## 1. Set up your application and database +## 1. Set up your application -To start, you create a directory for your project, and then use `deno run` to initialize your application with `prisma init` as an [npm package with npm specifiers](https://docs.deno.com/runtime/fundamentals/node/). - -To set up your application, open your terminal and navigate to a location of your choice. Then, run the following commands to set up your application: +Create a new directory and initialize your Prisma project: ```terminal mkdir prisma-deno-deploy cd prisma-deno-deploy -npx prisma@latest init --db +deno run -A npm:prisma@latest init --db ``` Enter a name for your project and choose a database region. This command: +- Connects to the [Prisma Data Platform](https://console.prisma.io) (opens browser for authentication) +- Creates a `prisma/schema.prisma` file for your database models +- Creates a `.env` file with your `DATABASE_URL` +- Creates a `prisma.config.ts` configuration file -- Connects your CLI to your [Prisma Data Platform](https://console.prisma.io) account. If you're not logged in or don't have an account, your browser will open to guide you through creating a new account or signing into your existing one. -- Creates a `prisma` directory containing a `schema.prisma` file for your database models. -- Creates a `.env` file with your `DATABASE_URL` (e.g., `DATABASE_URL="postgresql://user:password@host:5432/database"`). +## 2. Configure Deno -Edit the `prisma/schema.prisma` file to define a `Log` model, add a custom `output` path and [the `prisma-client` generator](/orm/prisma-schema/overview/generators#prisma-client) with `deno` as the `runtime`: +Create a `deno.json` file with the following configuration: -```prisma file=schema.prisma highlight=3-4,12-23;add showLineNumbers -generator client { - // delete-start - provider = "prisma-client-js" - // delete-end - //add-start - provider = "prisma-client" - output = "../generated/prisma" - runtime = "deno" - //add-end +```json file=deno.json +{ + "nodeModulesDir": "auto", + "compilerOptions": { + "lib": ["deno.window"], + "types": ["node"] + }, + "imports": { + "@prisma/adapter-pg": "npm:@prisma/adapter-pg@^7.0.0", + "@prisma/client": "npm:@prisma/client@^7.0.0", + "prisma": "npm:prisma@^7.0.0" + }, + "tasks": { + "dev": "deno run -A --env=.env --watch index.ts", + "db:generate": "deno run -A --env=.env npm:prisma generate", + "db:push": "deno run -A --env=.env npm:prisma db push", + "db:migrate": "deno run -A --env=.env npm:prisma migrate dev", + "db:studio": "deno run -A --env=.env npm:prisma studio" + } } +``` -datasource db { - provider = "postgresql" -} +:::note +The `nodeModulesDir: "auto"` setting is required for Prisma to work correctly with Deno. The `compilerOptions` ensure TypeScript understands Deno globals and npm packages. The import map allows you to use clean import paths like `@prisma/adapter-pg` instead of `npm:@prisma/adapter-pg`. +::: -//add-start -model Log { - id Int @id @default(autoincrement()) - level Level - message String - meta Json -} +Install the dependencies: -enum Level { - Info - Warn - Error -} -//add-end +```terminal +deno install +deno install --allow-scripts ``` -Then, install Prisma Client and the Postgres adapter: +## 3. Define your data model -```terminal -deno install npm:@prisma/client -deno install npm:@prisma/adapter-pg -``` +Edit `prisma/schema.prisma` to add the Deno runtime and a `Task` model: -Prisma Client does not read `.env` files by default on Deno, so you must also install `dotenv-cli` locally: +```prisma file=prisma/schema.prisma highlight=4;add +generator client { + provider = "prisma-client" + output = "../generated/prisma" + runtime = "deno" +} -```terminal -deno install npm:dotenv-cli +datasource db { + provider = "postgresql" +} + +model Task { + id Int @id @default(autoincrement()) + title String + description String? + completed Boolean @default(false) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} ``` -## 2. Create the database schema +## 4. Push the schema to your database -With the data model in place and your database connection configured, you can now apply the data model to your database. +Apply the schema to your database and generate Prisma Client: ```terminal -deno run -A npm:prisma migrate dev --name init +deno task db:push ``` -The command does two things: - -1. It creates a new SQL migration file for this migration -1. It runs the SQL migration file against the database +This command: +1. Creates the `Task` table in your Prisma Postgres database +2. Generates the Prisma Client with full type safety -At this point, the command has an additional side effects. The command installs Prisma Client and creates the `package.json` file for the project. +:::info +If you see TypeScript errors in your IDE after generating, restart the Deno language server (`Cmd/Ctrl + Shift + P` → "Deno: Restart Language Server") to refresh the types. +::: -## 3. Create your application +## 5. Create your application -You can now create a local Deno application. Create `index.ts` in the root folder of your project and add the content below: +Create `index.ts` with a REST API for managing tasks: ```ts file=index.ts -import { serve } from "https://deno.land/std@0.140.0/http/server.ts"; -import { PrismaPg } from "npm:@prisma/adapter-pg"; -import { PrismaClient } from "../generated/prisma/client.ts"; +import { PrismaPg } from "@prisma/adapter-pg"; +import { PrismaClient } from "./generated/prisma/client.ts"; -const connectionString = `${Deno.env.get("DATABASE_URL")}`; +// Initialize Prisma Client with the Postgres adapter +const connectionString = Deno.env.get("DATABASE_URL")!; const adapter = new PrismaPg({ connectionString }); const prisma = new PrismaClient({ adapter }); -async function handler(request: Request) { - // Ignore /favicon.ico requests: +// Helper to create JSON responses +function json(data: unknown, status = 200): Response { + return new Response(JSON.stringify(data, null, 2), { + status, + headers: { "Content-Type": "application/json" }, + }); +} + +// Request handler +async function handler(request: Request): Promise { const url = new URL(request.url); - if (url.pathname === "/favicon.ico") { - return new Response(null, { status: 204 }); + const path = url.pathname; + const method = request.method; + + try { + // GET /tasks - List all tasks + if (method === "GET" && path === "/tasks") { + const tasks = await prisma.task.findMany({ + orderBy: { createdAt: "desc" }, + }); + return json(tasks); + } + + // POST /tasks - Create a new task + if (method === "POST" && path === "/tasks") { + const body = await request.json(); + const task = await prisma.task.create({ + data: { + title: body.title, + description: body.description, + }, + }); + return json(task, 201); + } + + // GET /tasks/:id - Get a specific task + const taskMatch = path.match(/^\/tasks\/(\d+)$/); + if (taskMatch) { + const id = parseInt(taskMatch[1]); + + if (method === "GET") { + const task = await prisma.task.findUnique({ where: { id } }); + if (!task) return json({ error: "Task not found" }, 404); + return json(task); + } + + // PATCH /tasks/:id - Update a task + if (method === "PATCH") { + const body = await request.json(); + const task = await prisma.task.update({ + where: { id }, + data: body, + }); + return json(task); + } + + // DELETE /tasks/:id - Delete a task + if (method === "DELETE") { + await prisma.task.delete({ where: { id } }); + return json({ message: "Task deleted" }); + } + } + + // GET / - API info + if (method === "GET" && path === "/") { + return json({ + name: "Prisma + Deno Task API", + version: "1.0.0", + endpoints: { + "GET /tasks": "List all tasks", + "POST /tasks": "Create a task", + "GET /tasks/:id": "Get a task", + "PATCH /tasks/:id": "Update a task", + "DELETE /tasks/:id": "Delete a task", + }, + }); + } + + return json({ error: "Not found" }, 404); + } catch (error) { + console.error(error); + return json({ error: "Internal server error" }, 500); } - - const log = await prisma.log.create({ - data: { - level: "Info", - message: `${request.method} ${request.url}`, - meta: { - headers: JSON.stringify(request.headers), - }, - }, - }); - const body = JSON.stringify(log, null, 2); - return new Response(body, { - headers: { "content-type": "application/json; charset=utf-8" }, - }); } -serve(handler); +// Start the server +Deno.serve({ port: 8000 }, handler); ``` -:::info +This creates a full CRUD API with the following endpoints: -**VS Code error: `An import path cannot end with a '.ts' extension`**

+| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/` | API info | +| GET | `/tasks` | List all tasks | +| POST | `/tasks` | Create a new task | +| GET | `/tasks/:id` | Get a specific task | +| PATCH | `/tasks/:id` | Update a task | +| DELETE | `/tasks/:id` | Delete a task | -If you use VS Code and see the error `An import path cannot end with a '.ts' extension` for the `import` statements at the beginning of `index.ts`, you need to install the [Deno extension for VS Code](https://docs.deno.com/runtime/reference/vscode/), select **View** > **Command Palette** and run the command **Deno: Initialize Workspace Configuration**. This tells VS Code that the TypeScript files in the current project need to run with Deno, which then triggers the correct validations. +## 6. Test your application locally -::: +Start the development server: -## 4. Test your application locally +```terminal +deno task dev +``` -You can now start your application locally and test the creation of log entries. +Test the API with curl: ```terminal -npx dotenv -- deno run -A ./index.ts -``` +# Get API info +curl http://localhost:8000/ -In a web browser, open [http://localhost:8000/](http://localhost:8000/). This page writes your request to the database. +# Create a task +curl -X POST http://localhost:8000/tasks \ + -H "Content-Type: application/json" \ + -d '{"title": "Learn Prisma", "description": "Complete the Deno guide"}' -``` -{ - "id": 1, - "level": "Info", - "message": "GET http://localhost:8000/", - "meta": { - "headers": "{}" - } -} -``` +# List all tasks +curl http://localhost:8000/tasks -Reload the page a few times.

Every time you reload, the script generates a new log entry and the `id` of the current log entry increments. +# Update a task (mark as completed) +curl -X PATCH http://localhost:8000/tasks/1 \ + -H "Content-Type: application/json" \ + -d '{"completed": true}' -This confirms that your application works when you run it from your local environment. +# Delete a task +curl -X DELETE http://localhost:8000/tasks/1 +``` -## 5. Create a repository and push to GitHub +You should see JSON responses for each request. The task ID will increment with each new task created. -You need a GitHub repository to add your project to Deno Deploy and enable automated deployments whenever you push changes. +## 7. Create a GitHub repository -To set up a GitHub repository: +You need a GitHub repository to deploy to Deno Deploy. -1. [Create a private GitHub repository](https://github.com/new). +Create a `.gitignore` file: -2. Initialize your repository locally and push your changes to GitHub, with the following commands: +```text file=.gitignore +.env +node_modules/ +generated/ +deno.lock +``` - ```terminal - git init -b main - git remote add origin https://github.com//prisma-deno-deploy - git add . - git commit -m "initial commit" - git push -u origin main - ``` +Initialize and push your repository: -## 6. Deploy to Deno Deploy +```terminal +git init -b main +git remote add origin https://github.com//prisma-deno-deploy +git add . +git commit -m "Initial commit" +git push -u origin main +``` -Use the GitHub repository to add your application to Deno Deploy: +## 8. Deploy to Deno Deploy -1. Go to [https://dash.deno.com/](https://dash.deno.com/). -1. Select a GitHub organization or user and then select a repository. -1. Select a production branch and select **Fresh (Automatic)** mode so that Deno Deploy can deploy every time you push a change to the repository. -1. In the **Build Step** add `deno run -A npm:prisma generate` to generate the Prisma Client. -1. Select `index.ts` as the entry point to your project. -1. Click `Create & Deploy`. +1. Go to [https://dash.deno.com/](https://dash.deno.com/) +2. Click **New Project** and select your GitHub repository +3. Configure the deployment: + - **Framework preset**: No Preset + - **Install command**: `deno install` + - **Build command**: `deno run -A npm:prisma generate` + - **Entrypoint**: `index.ts` +4. Click **Create & Deploy** -The deployment should fail as you have to add the `DATABASE_URL` environment variable. +The first deployment will fail because you need to add the database connection string. -Locate and navigate to the settings for the project. +### Add environment variables -1. To define the database connection string, click **Add Variable** in the **Environment Variables** section. - 1. For **KEY**, enter `DATABASE_URL`. - 1. For **VALUE**, paste the database connection string. -1. Click **Save**.
- -You have to add some code and create another commit to trigger a re-dployment. +1. Go to your project's **Settings** > **Environment Variables** +2. Add a new variable: + - **Key**: `DATABASE_URL` + - **Value**: Your Prisma Postgres connection string (copy from your `.env` file) +3. Click **Save** -Add the following code in your `index.ts` file: +Trigger a new deployment by clicking **Redeploy** or pushing a new commit. -```ts file=index.ts -import { serve } from "https://deno.land/std@0.140.0/http/server.ts"; -import { PrismaPg } from "npm:@prisma/adapter-pg"; -import { PrismaClient } from "../generated/prisma/client.ts"; +## 9. Test your deployed API -const connectionString = `${Deno.env.get("DATABASE_URL")}`; -const adapter = new PrismaPg({ connectionString }); -const prisma = new PrismaClient({ adapter }); +Once deployed, test your API at your Deno Deploy URL: -async function handler(request: Request) { - // Ignore /favicon.ico requests: - const url = new URL(request.url); - if (url.pathname === "/favicon.ico") { - return new Response(null, { status: 204 }); - } +```terminal +# Replace with your actual Deno Deploy URL +curl https://your-project.deno.dev/ - //add-start - console.log("Request received.") - //add-end - - const log = await prisma.log.create({ - data: { - level: "Info", - message: `${request.method} ${request.url}`, - meta: { - headers: JSON.stringify(request.headers), - }, - }, - }); - const body = JSON.stringify(log, null, 2); - return new Response(body, { - headers: { "content-type": "application/json; charset=utf-8" }, - }); -} +# Create a task +curl -X POST https://your-project.deno.dev/tasks \ + -H "Content-Type: application/json" \ + -d '{"title": "Deploy to production"}' -serve(handler); +# List tasks +curl https://your-project.deno.dev/tasks ``` -Commit the new changes: +## Summary -```terminal -git add . -git commit -m "add log" -git push origin main -``` +You successfully deployed a REST API to Deno Deploy using: -This rebuilds the deployment, which now works because the environment variable has been added. After it completes, follow the URL in the deployment output. The application should show the same result as before, with a new, incremented log record ID: +- **Deno** as the runtime with native TypeScript support +- **Prisma ORM** with the Postgres adapter for type-safe database access +- **Prisma Postgres** as the managed database + +Your project structure should look like this: -```text -{ - "id": 5, - "level": "Info", - "message": "GET https://prisma-deno-deploy.deno.dev/", - "meta": { - "headers": "{}" - } -} +``` +prisma-deno-deploy/ +├── deno.json +├── index.ts +├── prisma/ +│ └── schema.prisma +├── prisma.config.ts +├── generated/ +│ └── prisma/ +│ └── ... +└── .env ``` -## Summary +### Next steps -You successfully deployed a Deno application that you created in TypeScript, which uses Prisma Client with the Postgres adapter to connect to a Postgres database. +- Add authentication using [Deno KV](https://deno.com/kv) for sessions +- Add request validation with [Zod](https://zod.dev/) +- Explore [Prisma Client extensions](/orm/prisma-client/client-extensions) for custom functionality +- Set up [Prisma Migrate](/orm/prisma-migrate) for schema versioning in production diff --git a/content/800-guides/400-deno-integration.mdx b/content/800-guides/400-deno-integration.mdx index 86f9773d23..8d27677db8 100644 --- a/content/800-guides/400-deno-integration.mdx +++ b/content/800-guides/400-deno-integration.mdx @@ -15,7 +15,7 @@ By the end of this guide, you will have a deployed Deno app that writes to and r ## Prerequisites - A [Deno Deploy](https://deno.com/deploy) account -- Deno runtime installed ([installation guide](https://docs.deno.com/runtime/#install-deno)) +- Deno v2.0 or later installed ([installation guide](https://docs.deno.com/runtime/#install-deno)) - [Deno extension for VS Code](https://docs.deno.com/runtime/reference/vscode/) ## 1. Create and set up a new Deno project @@ -39,7 +39,7 @@ Install the [Deno extension for VS Code](https://docs.deno.com/runtime/reference Update the `main.ts` file to create a simple HTTP server that responds with "Hello, World!", establishing the foundation for your application before adding database functionality. -```tsx file=main.ts +```ts file=main.ts function handler(_req: Request): Response { return new Response("Hello, World!"); } @@ -50,7 +50,7 @@ Deno.serve(handler); You can test the server locally by running: ```terminal -deno run dev +deno task dev ``` Visit `localhost:8000` in your browser to see the application running. @@ -87,46 +87,58 @@ DATABASE_URL="postgresql://:@db.prisma.io:5432/ { const url = new URL(request.url); if (url.pathname === "/favicon.ico") { return new Response(null, { status: 204 }); @@ -191,9 +201,9 @@ async function handler(request: Request) { }, }, }); - const body = JSON.stringify(log, null, 2); - return new Response(body, { - headers: { "content-type": "application/json; charset=utf-8" }, + + return new Response(JSON.stringify(log, null, 2), { + headers: { "Content-Type": "application/json" }, }); } @@ -203,15 +213,9 @@ Deno.serve(handler); Test the application locally by running: ```terminal -deno run dev +deno task dev ``` -:::note - -It may ask you for access to your environment variables. Select **Allow** to grant access. - -::: - Visit `localhost:8000` in your browser to see the application running. You should see a JSON response containing the log entry: ```json @@ -229,10 +233,12 @@ Visit `localhost:8000` in your browser to see the application running. You shoul The build command must generate the Prisma Client code to ensure it is available in production. -### 6.1 Update build command in Deno Deploy +### 6.1 Update build configuration in Deno Deploy 1. Go to the application in Deno Deploy and click **Settings** -2. Under **Build configuration**, hit **Edit** and add `deno run -A npm:prisma generate` to the build command +2. Under **Build configuration**, click **Edit** and configure: + - **Install command**: `deno install` + - **Pre-deploy command**: `deno run -A npm:prisma generate` 3. Click **Save** ### 6.2 Push changes to GitHub @@ -271,6 +277,7 @@ Now that you have a working Deno app connected to a Prisma Postgres database, yo - **Enhance your data model** - Add relationships, validations, and indexes to your Prisma schema - **Secure your API** - Implement authentication, rate limiting, and proper error handling - **Improve deployment** - Set up CI/CD, monitoring, and database backups for production +- **Deploy to Deno Deploy** - Check out the full [Deploy to Deno Deploy guide](/orm/prisma-client/deployment/edge/deploy-to-deno-deploy) for a more comprehensive example ## More info