跳到正文
DEV Community· Shubhra Pokhariya·· 3 小時前AI 評分56

Hono 在 Prisma Postgres 與 Prisma Compute 上的實測:可行之處與問題

Hono on Prisma Postgres and Compute, What Worked and What Broke

AI 導讀

作者使用 Hono、Prisma Postgres 和 Prisma Compute 建置並部署書籤 API,透過 `npx prisma auth login`、`npm run build` 和 `npx prisma deploy module.ts` 三條命令完成部署。

正文

TL;DR

  • I deployed a Hono API on Prisma Postgres and Prisma Compute with three commands, auth login, build and deploy, and I never installed Bun.
  • One bug caught me. In this scaffold, if a route queries the database before the template's /users route does, /users returns a 500 and the log shows DRIVER.ALREADY_CONNECTED.
  • If you're sizing up the stack, Compute is GA, Composer (which declares and deploys Compute apps) is Early Access, and Prisma ORM 8 is still a release candidate at the time of writing. Pin your versions.

I wrote this article for Prisma, who commissioned it. The opinions are mine.

I built a small bookmarks API with Hono, put it on Prisma Postgres and deployed it to Prisma Compute. A coding agent, Gemini CLI, wrote most of the code from a prompt I wrote, and I kept a log of every error and every fix. The repo is public on GitHub, with the code, migrations, README and smoke test.

The app, a Hono bookmarks API with Prisma Postgres

I added six routes. GET /health, plus five for bookmarks (list, get one, create, update, delete). The scaffold adds GET / and GET /users, and /users matters later. A bookmark has an id, a unique URL, a title, optional notes and a createdAt.

I tested with Node 22.22.2, Gemini CLI 0.65.0 (with gemini-3.5-flash-lite selected), Prisma CLI 8.0.0-rc.21, @prisma/orm-postgres 8.0.0-rc.16 and @prisma/composer 0.28.0, in late October 2026. The Prisma packages have moved on since, so the findings apply to those versions. A re-run of the finished repo on Linux (Node and a local Postgres 16) is marked "on Linux" below.

A quick note on what you'd be building on. The Compute FAQ says Compute has been generally available since August 2026. Prisma's 28 August changelog and the Console both label Composer Early Access, and Prisma's docs call ORM 8 a release candidate at the time of writing.

I wrote the agent's rules in one prompt and made it stop after every phase. I ran every command that installed packages, used credentials or deployed to Prisma myself, and I never pasted my database URL into the agent.

Prisma Postgres with Hono, migrations and the direct vs pooled connection string

I created the database in the Console and it was ready in a few minutes. The connection dialog defaults to the pooled host (pooled.db.prisma.io) and tells you to put the string in .env. I came away with two things.

  • I used the direct host (db.prisma.io) for db:init, migrate and local dev. I didn't test the pooled string.
  • The scripts read DATABASE_URL from the shell, not from .env. On Linux, a valid .env file with no shell variable gave CONFIG.DB_CONNECTION_REQUIRED and created nothing. The Prisma Hono guide says the same.

The scaffold generates the first migration, and I generated the second with npm run migration:plan -- --name add-bookmarks. On my own database I ran db:init first (5 operations, the scaffold's tables) and migrate later, which applied the Bookmark migration. On Linux, migrate alone applied both migrations to an empty local database. The difference is that db:init builds tables straight from the contract, while migrate applies the migrations/ folder, which the Compute FAQ says a deploy applies for a Composer postgres() database. Both are safe to run twice (a second migrate says "Already up to date") and both mask credentials in their output. Every run also prints a pg warning that sslmode=require will change meaning in a future version.

Prisma ORM 8 unique constraint error and sqlState 23505

I put the rules in the prompt. Ids match ^[1-9][0-9]*$ and fit an int4, bodies over 10 KB get a 413 before parsing, URLs are stored as new URL(value).href, and the database's unique constraint decides duplicates. Gemini implemented them with a few early mistakes, including a wrong check order on PATCH, any types and a guessed duplicate check.

That guess is the interesting part. Gemini assumed a Postgres unique violation shows up as err.code === "23505". In ORM 8 the top-level code is undefined. I triggered a duplicate on purpose and logged the error. The useful fields, sqlState (23505) and constraint (Bookmark_url_key), sit on a SqlQueryError. The scaffold already ships the answer in .agents/skills/prisma-8/references/debug.md, which says driver errors "carry no dotted code" and to route on sqlState and the constraint metadata. My Phase 4 prompt named four skill files for Gemini to read and this wasn't one of them. I only read it while fact-checking this article.

Five simultaneous identical POSTs gave one 201 and four 409s.

Fixing DRIVER.ALREADY_CONNECTED in a Prisma ORM 8 Hono app

I had an 85-check smoke test ready before the API existed. The first run came back 84 passed, 2 failed. That adds up to 86 results from 85 checks because the script also records a failure for any 5xx response, so one broken route printed two FAIL lines. Both were GET /users, a route that ships with the scaffold.

{"error":"Could not query users yet. Run contract:emit and apply your schema first."}

The schema was fine, and the server log said something else.

Postgres client already connected
code: DRIVER.ALREADY_CONNECTED
fix: Call connect() at most once per client.

Here is what I worked out from the generated db.ts and the bundled dist/server.mjs. The ORM client connects in the background on its first query. The template's /users route goes through a helper that calls db.connect() explicitly. If one of my bookmark routes ran a query first, the background connect had already started and the explicit one threw. My routes queried db directly and never used the helper. This matches Prisma's runtime reference, which says to call connect() before any query or not at all, because a connect() after a query rejects with DRIVER.ALREADY_CONNECTED.

After a clean restart, GET /bookmarks followed by GET /users gave 500, and 500 again five seconds later. That also explains why smoke run 2 passed with no code change. I'd restarted the server, and the script requests /users before any bookmarks route, so the explicit connect ran first. On Linux the same unfixed code passed all 85 checks on a fresh process, and gave 84 passed, 2 failed once a bookmarks request came first.

Gemini's fixes were the weak part. The first matched the error message text and returned quietly, which hides the error. The second put await connectDatabase() at the top of every handler, before validation, so a bad body would need a database connection just to be rejected. I rejected both. The third calls the helper right before the first query in each handler, after validation, and leaves /health alone. After that /bookmarks, /users, /users returned 200, 200, 200 and a full smoke run gave 85 passed.

The Linux re-run also showed that the guide's own example triggers it. With the guide's POST /users route (step 4) added to a copy of the repo, a fresh process gave 201 for POST /users and then 500 twice for GET /users, with DRIVER.ALREADY_CONNECTED in the log. With GET /users first, the same three requests returned 200, 201 and 200. That was a local Postgres 16, not the deployed app, and the guide may have changed since.

The code compiled and my manual checks passed. Only a test run in the right order showed the problem. If you add a route to a Prisma scaffold, hit the template's own routes before and after yours, on a fresh process.

Deploy a Hono API to Prisma Compute

The Composer docs say local dev (prisma dev) isn't supported on Windows. I'm on Windows 10, so I never ran it, even though the scaffold's "next steps" box suggests it. These are the three commands I did run.

npx prisma auth login
npm run build
npx prisma deploy module.ts

All three worked. The Composer limitations page says deploys authenticate only with a service token, with "no browser flow", but the Composer deploying page documents auth login, and that's what I used. The two pages disagree and I couldn't tell which one is current.

I did three deploys.

  • The untouched scaffold took 3m 38s.
  • My bookmarks code took 3m 10s.
  • A redeploy of unchanged code took 50.4s.

Those are single runs from my machine, not a benchmark.

Prisma Compute deploy plan output for a Hono bookmarks API showing 1 created, 4 updated, 1 ran and 4 no change

deploy doesn't build, so you run npm run build first. tsdown bundles everything into one dist/server.mjs of about 2 MB. The scaffold defaults to the us-east-1 region, and since I'm in India I changed one line in prisma.config.ts to ap-southeast-1.

The deployed app got its own Prisma Postgres database, and the migrated tables were there without my local DATABASE_URL being set. The deploy plan showed database-migrate (PrismaOrm.Migration) as updated, with no migration name. The Compute FAQ and the Compute limitations page both say the deploy applies your migrations/ to a Composer postgres() database before the service starts. My tables showed up after the deploy, which fits that, but I only know it from the result and not from the deploy output.

Compute runs the app on Bun even though my code is Node-style (@hono/node-server, built with tsdown for Node 22). The service log says starting bun with entrypoint: bootstrap.js. I installed nothing for that. The Composer getting-started page lists Bun as a prerequisite, so keep it in mind if local Node and deployed Bun ever behave differently.

The same 85 checks against the live app ended with 85 passed, 0 failed, 0 skipped. I didn't save the output. My paste and a screenshot show 79 of the 85 PASS lines, no FAIL line, and the final Result line with the totals. I created a bookmark, redeployed unchanged code and fetched it again, and got the same row. The app keeps no data in memory, so that fits the data living in Postgres. I can't say whether the redeploy restarted the app, so I haven't tested that.

Terminal showing the live smoke test against a Hono API on Prisma Compute finishing with 85 passed, 0 failed, 0 skipped

prisma service logs app failed right after the deploy with PROJECT.SETUP_REQUIRED, saying the directory wasn't linked to a project. It needs --project bookmarks-api. The log held two lines and no request lines. The Console overview also said "no deploys yet" while the app was live. The CLI had told me it wasn't recording the deploy because the folder had no git commit, so that may be expected, but I didn't check.

Prisma Console overview of the bookmarks-api project with the Hono app on Prisma Compute marked LIVE next to its Prisma Postgres database

Prisma Compute latency from India

These numbers are my own network path to ap-southeast-1, not a benchmark, and the bookmarks table was empty. The idle test sent one request to /health and then one to /bookmarks from the same process, so the second request likely reused the first one's connection and skipped DNS and TLS. I didn't verify that. The 30 warm requests per endpoint came about 70 seconds later.

Test /health /bookmarks
First two requests after about 16 hours idle (estimated) 682.7 ms 363.5 ms
30 warm requests, median 120.8 ms 127.5 ms
30 warm requests, p95 745.7 ms 134.9 ms

Twenty-eight of the 30 warm /health requests took 116.5 to 130.8 ms. Request 1 took 745.7 ms, and with 30 values that is also the p95, so it says little about typical latency. Request 20 took 967.9 ms and I don't know why. Prisma says idle Compute instances resume in milliseconds, but I can't call my idle figure a cold start because DNS, TLS and any wake-up are mixed into it.

npm audit on a Prisma Compute project and its 14 vulnerabilities

npm ci reports 14 vulnerabilities (5 moderate, 9 high). On Linux they traced back to alchemy and an old nested @prisma/dev, plus lodash through a parser package. Also on Linux, a search of dist/server.mjs found no @prisma/dev or lodash, and its only alchemy mentions are three code comments. The app itself uses the top-level hono 4.13.13 and @hono/node-server 2.1.5, which the audit doesn't flag. A bundle search is not a security review. Don't run npm audit fix --force, because it proposes @prisma/composer and @prisma/composer-prisma-cloud 0.6.0 and prisma 7.10.1, a step back from ORM 8.

What worked, and what I'd tell the Prisma team

What worked well. Once I'd signed in with auth login, build and deploy ran without prompts, and the deployed app arrived with its own database. The doc comments in the installed types also say what update and delete return when nothing matches.

What I'd suggest to Prisma. Each of these comes from something I saw.

  • The template's /users error tells you to run contract:emit, but the server log showed DRIVER.ALREADY_CONNECTED. Logging or returning the underlying error would save someone an afternoon. The runtime reference and the scaffold's skill file describe the lazy connect, but the Hono guide I read doesn't, and the template's own helper calls connect() explicitly. The guide's own POST /users example queries db without connecting, so it runs into the same error.
  • The Composer limitations page says deploys use a service token with no browser flow, while the Composer deploying page documents auth login. A note on which is current would settle it.
  • The deploy plan could name the migration it ran.
  • prisma deploy found my project from the folder, but prisma service logs said the directory wasn't linked to one. Sharing that link between the two commands would save a step.
  • The ORM 8 query types live in @prisma/orm-family-sql, not in the package you install, so they took several searches to find.
  • Versions move fast. A couple of days after I scaffolded, the CLI was telling me 8.0.0-rc.27 existed.

Before you copy the repo

  • GET /users is a scaffold route, and it inserts three sample users on its first call.
  • createdAt comes back as Postgres text (2026-10-23 16:33:47.512805+00), not ISO 8601, because the contract uses the scaffold's TimestamptzString type.
  • There's no auth, so anyone with the URL can write to it. Prisma's pricing page gives the Prisma Postgres Free plan 200,000 operations a month, and the Compute FAQ says the Free plan has no backups. I'm not publishing my live URL.
  • A NUL character (\u0000) in title or notes returns 500 instead of 400. A lone surrogate or invalid UTF-8 is stored as the replacement character. These turned up when the repo was probed with odd input on Linux, and the 85 checks don't cover them. They're listed in the README and not fixed.

What I didn't test

I didn't test prisma dev (unsupported on Windows), the pooled connection string, the Prisma MCP server, Bash on Windows or macOS, or how Compute behaves when idle database connections drop. I tested one small API with an empty table, so I can't speak to load or larger projects. The docs changed several times while I worked, so re-check the linked pages before you rely on any of this.

My verdict

I'd use this stack again. Going from a scaffold to a live API with its own Prisma Postgres database took three commands. The one real bug I hit depended on the order my routes and the scaffold's /users route queried the database, and I could trace and fix it. At the time of writing, ORM 8 is still a release candidate and Composer is in Early Access, so before I ran production traffic on it I'd wait for those, and for the docs to agree on auth. The code, README and smoke test are in the repo.

來源:DEV Community · dev.to