{"slug": "vercel-and-tidb-cloud-starter-the-full-stack-playbook-for-ai-apps", "title": "Vercel and TiDB Cloud Starter: The Full-Stack Playbook for AI Apps", "summary": "TiDB Cloud Starter connects to Vercel serverless and edge functions over HTTPS via the TiDB Cloud serverless driver, eliminating the TCP connection pool that breaks traditional MySQL and Postgres databases under bursty serverless traffic. The playbook details swapping a v0.dev or Lovable starter database for TiDB Cloud Starter through a connection string change, keeping embeddings beside rows with a native VECTOR type instead of a separate vector store, and deploying through the Vercel Marketplace integration that writes connection environment variables automatically. The setup targets Vercel serverless functions on the Node.js runtime, Vercel Edge Functions, and Cloudflare Workers, where raw TCP sockets are not permitted.", "body_md": "## Key Takeaways\n\n- Edge runtimes break TCP pools. TiDB Cloud Starter connects over HTTPS instead.\n- Swapping a v0.dev starter database for TiDB is a connection string change.\n- A native\n`VECTOR` type keeps embeddings beside your rows, with no store to sync.- The Vercel Marketplace integration writes the connection variables for you.\n\nYou have an AI app running on Vercel, or a prototype that v0.dev generated in a few minutes, and now it needs a real database. The choice is harder than it looks, because serverless functions and edge runtimes break the assumptions traditional databases are built on: long-lived TCP connections, a bounded pool, and a process that stays warm between requests.\n\nThis playbook covers the full path. Pick a Vercel database that survives serverless and edge runtimes, model the data an AI app actually stores, put embeddings next to that data instead of in a separate vector store, connect from Vercel Edge Functions and Cloudflare Workers, and deploy through the Vercel Marketplace integration that wires the environment variables for you.\n\n[TiDB](https://www.pingcap.com/what-is-tidb/) is an open source distributed SQL database with transactional and analytical processing in one engine. TiDB Cloud Starter is its fully managed, auto-scaling deployment option, MySQL compatible and provisioned in about a second. [Vercel](https://vercel.com/home) is the creator of Next.js and the platform most AI apps deploy to. The two fit together well, and the rest of this post shows exactly how.\n\n## Why a Vercel App Needs a Serverless Database Built for the Edge\n\nVercel runs your backend as serverless and edge functions rather than a long-running server, and that changes what a database has to support. A serverless function executes on demand, scales automatically, and terminates when the request finishes. A traditional API keeps a process alive behind a request-response interface, holds its connection pool open, and reuses connections across requests.\n\nThree differences matter when you pick a database:\n\n- **Lifecycle.** A serverless function runs a specific piece of code in response to an event and exits. A traditional API stays resident and manages its own infrastructure.\n- **Portability.** Serverless functions bind to a platform runtime. A traditional API runs anywhere you can host a process.\n- **Deployment speed.** Serverless functions ship in shorter cycles because there is no infrastructure to provision, which is why AI apps iterate on them.\n\n### Connection Pooling Is the Problem Serverless Exposes\n\nEach function invocation opens its own database connection. Under bursty traffic, a few hundred concurrent invocations become a few hundred connections, and a traditional MySQL or Postgres instance starts refusing them. Teams usually respond by adding an external pooler, which adds a hop, a component to operate, and a new failure mode.\n\nTiDB Cloud Starter takes a different path with the [TiDB Cloud serverless driver](https://docs.pingcap.com/tidbcloud/serverless-driver/), which talks to the database over HTTPS instead of TCP. There is no pool to exhaust because there is no persistent connection in the path. Each invocation makes an HTTPS request, gets its result, and ends.\n\n### Runtimes This Playbook Covers\n\nEverything below works on three targets: Vercel serverless functions (Node.js runtime), Vercel Edge Functions, and Cloudflare Workers. Edge runtimes are the strict case, because they do not allow raw TCP sockets at all. A driver that speaks HTTPS is not an optimization there. It is the only thing that connects.\n\n## From a v0.dev or Lovable Prototype to a Deployed Vercel App\n\nAI builders like v0.dev and Lovable scaffold a working Next.js app in minutes, then hand you a project that expects a database URL and ships with a generic Postgres or SQLite starter. Swapping that starter for TiDB Cloud Starter takes three steps: prototype, connect, deploy.\n\n**Prototype.** Generate the app as usual. The output is a standard Next.js project with an API layer, a data access file, and an `.env` or `.env.local` expecting `DATABASE_URL`.\n\n**Connect.** Find where the generated app reads that variable. In a Prisma project it is the `datasource` block in `prisma/schema.prisma`. In a Drizzle or Kysely project it is the client initialization file. Point it at a TiDB Cloud Starter connection string:\n\n```\nDATABASE_URL='mysql://<user>:<password>@<host>:4000/<database>?sslaccept=strict'\n```\n\nIf the scaffold assumed Postgres, change the provider to `mysql` and regenerate the client. TiDB speaks the MySQL wire protocol, so any MySQL driver, ORM, or migration tool works without modification.\n\n**Deploy.** Push to GitHub and import the repo into Vercel, or use the Marketplace integration covered later in this post, which sets the connection variables during deployment.\n\nThe reason to make the swap at the prototype stage rather than later: the starter database that ships with a generated app is sized for a demo. TiDB Cloud Starter scales horizontally on the same MySQL-compatible interface, so the prototype and the production system run the same code against the same engine.\n\n## Spin Up Your TiDB Cloud Starter Cluster (Your Vercel Database)\n\nProvisioning the database takes under a minute. Sign in to [TiDB Cloud](https://tidbcloud.com/free-trial), follow the on-screen instructions to create a free TiDB Cloud Starter cluster, then click the cluster name to open it.\n\n### Choose Your Entry Point: Cloud, Starter, or Zero\n\nThree on-ramps exist, and the right one depends on what you are building.\n\n- **TiDB Cloud Zero** provisions an ephemeral instance through a single API call with no sign-up and no billing details. Instances expire after 30 days unless you claim them, and claiming converts one into a persistent TiDB Cloud Starter instance with the data and schema migrated automatically. Zero is built for agent-driven workflows, demos, and CI, and it is currently in public preview at[zero.tidbcloud.com](https://zero.tidbcloud.com/) .\n- **TiDB Cloud Starter** is the free, fully managed serverless tier inside TiDB Cloud. This is the default choice for a Vercel app that needs to persist real data.\n- **TiDB Cloud** is the full platform. Starter sits inside it, and Essential and Dedicated add capacity, isolation, and enterprise controls as an app grows.\n\nStart on Zero if an agent or a script is doing the provisioning. Start on Starter if a human is building an app that has to outlive the week.\n\n### Grab Your Connection Details\n\nIn the cluster view, click **Connect** to open the connection details and note the **Host**, **Port**, and **User** values. You will use them to build the connection string the ORM reads.\n\nStore those values as Vercel environment variables rather than committing them to code. In the Vercel dashboard, go to **Settings** > **Environment Variables**, add `DATABASE_URL`, and scope it to the environments that need it. Locally, keep it in `.env.local`, which Next.js excludes from git by default.\n\nVerify connectivity before going further:\n\n```\nmysql --connect-timeout 15 -u '<user>' -h '<host>' -P 4000 -D '<database>' \\\n  --ssl-mode=VERIFY_IDENTITY --ssl-ca=/etc/ssl/certs/ca-certificates.crt -p\n```\n\n## Model AI App Data: Sessions, Chat Logs, Preferences, and Retrieval State\n\nAn AI app stores a predictable set of things: conversation sessions, the messages inside them, the actions an agent took, and the preferences that shape future responses. Prisma models all of it cleanly, and the mechanics are the same ones any Prisma project uses.\n\nInstall the adapter, the serverless driver, and the Prisma CLI:\n\n```\nnpm install @tidbcloud/prisma-adapter @tidbcloud/serverless\nnpm install prisma --save-dev\n```\n\nEnable driver adapters in `prisma/schema.prisma` and define the models:\n\n```\ngenerator client {\n  provider        = \"prisma-client-js\"\n  previewFeatures = [\"driverAdapters\"]\n}\n\ndatasource db {\n  provider = \"mysql\"\n  url      = env(\"DATABASE_URL\")\n}\n\nmodel Session {\n  id        String        @id @default(uuid())\n  userId    String        @map(\"user_id\") @db.VarChar(64)\n  title     String?       @db.VarChar(255)\n  createdAt DateTime      @default(now()) @map(\"created_at\")\n  messages  Message[]\n  actions   AgentAction[]\n\n  @@index([userId, createdAt])\n  @@map(\"sessions\")\n}\n\nmodel Message {\n  id         BigInt   @id @default(autoincrement())\n  sessionId  String   @map(\"session_id\") @db.VarChar(36)\n  role       String   @db.VarChar(16)\n  content    String   @db.Text\n  tokenCount Int?     @map(\"token_count\")\n  createdAt  DateTime @default(now()) @map(\"created_at\")\n  session    Session  @relation(fields: [sessionId], references: [id])\n\n  @@index([sessionId, createdAt])\n  @@map(\"messages\")\n}\n\nmodel AgentAction {\n  id        BigInt   @id @default(autoincrement())\n  sessionId String   @map(\"session_id\") @db.VarChar(36)\n  tool      String   @db.VarChar(64)\n  input     Json?\n  output    Json?\n  status    String   @db.VarChar(16)\n  createdAt DateTime @default(now()) @map(\"created_at\")\n  session   Session  @relation(fields: [sessionId], references: [id])\n\n  @@index([sessionId, status])\n  @@map(\"agent_actions\")\n}\n\nmodel UserPreference {\n  userId    String   @id @map(\"user_id\") @db.VarChar(64)\n  settings  Json\n  updatedAt DateTime @updatedAt @map(\"updated_at\")\n\n  @@map(\"user_preferences\")\n}\n```\n\nExport the connection string and push the schema:\n\n```\nexport DATABASE_URL='mysql://<user>:<password>@<host>:4000/<database>?sslaccept=strict'\nnpx prisma db push\nnpx prisma generate\n```\n\nTwo notes on how the adapter behaves. `prisma db push`, Prisma Migrate, and introspection use the traditional TCP connection, so run them from your machine or CI rather than from an edge function. Prisma Client queries go over HTTPS through the adapter. Initialize the client once per module:\n\n``` js\nimport { PrismaTiDBCloud } from '@tidbcloud/prisma-adapter';\nimport { PrismaClient } from '@prisma/client';\n\nconst adapter = new PrismaTiDBCloud({ url: process.env.DATABASE_URL });\nconst prisma = new PrismaClient({ adapter });\n```\n\nFor adapter versions earlier than v6.6.0, build the connection first with `connect()` from `@tidbcloud/serverless` and pass it to `new PrismaTiDBCloud(connection)`. The [TiDB Cloud serverless driver and Prisma integration post](https://www.pingcap.com/blog/integrating-tidb-cloud-serverless-driver-prisma-orm/) covers the adapter, transactions, and the differences from the TCP path in more depth.\n\n## Store Embeddings and Power Retrieval With TiDB Vector Search\n\nTiDB has a native `VECTOR` data type, so embeddings live in the same database as the sessions and messages they belong to. There is no second system to provision, no sync job, and no window where the vector store and the application database disagree.\n\nAdd a document table with a fixed-dimension vector column and an HNSW index. The dimension has to match your embedding model, and 1536 matches OpenAI’s `text-embedding-3-small`:\n\n```\nCREATE TABLE documents (\n  id BIGINT PRIMARY KEY AUTO_RANDOM,\n  session_id VARCHAR(36),\n  content TEXT,\n  embedding VECTOR(1536),\n  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,\n  VECTOR INDEX idx_embedding ((VEC_COSINE_DISTANCE(embedding)))\n);\n```\n\nPrisma has no native mapping for `VECTOR`, so create the column with raw SQL and query it through the serverless driver or `$queryRaw`. Retrieval is an ordinary SQL query:\n\n``` js\nimport { connect } from '@tidbcloud/serverless';\n\nconst conn = connect({ url: process.env.DATABASE_URL });\n\nconst results = await conn.execute(\n  `SELECT id, content, VEC_COSINE_DISTANCE(embedding, ?) AS distance\n   FROM documents\n   ORDER BY distance\n   LIMIT 10`,\n  [JSON.stringify(queryEmbedding)]\n);\n```\n\nWhen you need to filter by tenant, session, or user, run the nearest-neighbor search first and filter the result, because a `WHERE` clause ahead of the vector ordering can stop the index from being used:\n\n```\nSELECT * FROM (\n  SELECT id, session_id, content,\n         VEC_COSINE_DISTANCE(embedding, '[0.1, 0.2, ...]') AS distance\n  FROM documents\n  ORDER BY distance\n  LIMIT 50\n) t\nWHERE session_id = '<session-id>'\nORDER BY distance\nLIMIT 10;\n```\n\nThe payoff shows up at write time. An insert that stores a message, its embedding, and an agent action commits as one transaction, so retrieval state and application state stay consistent. See the [TiDB vector search documentation](https://docs.pingcap.com/tidbcloud/vector-search-overview/) for distance functions, index behavior, and hybrid search with full text.\n\n## Connect From the Edge: Vercel Edge Functions and Cloudflare Workers\n\nEdge runtimes are where database choices get tested, because they prohibit raw TCP sockets. Any driver built on a TCP connection fails there regardless of how it is configured. The TiDB Cloud serverless driver connects over HTTPS, and `@tidbcloud/prisma-adapter` v5.11.0 and later work in Vercel Edge Functions and Cloudflare Workers.\n\nA route handler running at the edge looks like an ordinary Prisma query:\n\n``` js\n// app/api/messages/route.ts\nexport const runtime = 'edge';\n\nimport { PrismaTiDBCloud } from '@tidbcloud/prisma-adapter';\nimport { PrismaClient } from '@prisma/client';\n\nconst adapter = new PrismaTiDBCloud({ url: process.env.DATABASE_URL });\nconst prisma = new PrismaClient({ adapter });\n\nexport async function GET(request: Request) {\n  const sessionId = new URL(request.url).searchParams.get('session');\n\n  const messages = await prisma.message.findMany({\n    where: { sessionId: sessionId ?? undefined },\n    orderBy: { createdAt: 'asc' },\n    take: 50,\n  });\n\n  return Response.json(messages);\n}\n```\n\nBecause each invocation issues its own HTTPS request, a burst of traffic produces a burst of independent requests rather than contention for a shared pool. There is no warm-up penalty on a cold start and no pool to size.\n\nTest locally before deploying:\n\n```\nnpm run dev\n```\n\nOpen `http://localhost:3000/api/messages?session=<session-id>` and confirm you get rows back. If the response is empty but no error appears, the connection is healthy and the table is empty, which is the expected state right after `prisma db push`.\n\n## Deploy on Vercel With the TiDB Cloud Integration\n\nConfiguring development, preview, and production environments by hand is slow and error prone, especially when connection details change. The [TiDB Cloud integration on the Vercel Marketplace](https://vercel.com/marketplace/tidb-cloud) handles it in a few clicks, and the demo app is published as a [TiDB Cloud Starter Template](https://vercel.com/templates/next.js/tidb-cloud-starter).\n\n1. Open the template and click **Deploy** . Vercel prompts you to create a GitHub repository. Give it a name, and Vercel creates it if it does not exist.\n2. In the **Add Integrations** section, add**TiDB Cloud** . In the popup, select the target Vercel project, then the TiDB**Organization** ,**Project** , and**Cluster** . The defaults are fine for a first deployment.\n3. Select **Prisma** as the framework and click**Add Integration** . Vercel returns you to the integration screen with a deployment in progress.\n4. When the deployment finishes, click **Continue to Dashboard** , then**Visit** to confirm the app is live.\n5. Check **Settings** >**Environment Variables** . The integration has already written the connection details, so there is nothing to paste by hand.\n\nThe last step is worth verifying rather than assuming. Preview deployments and production read the same variables, which is what keeps a branch deploy from pointing at the wrong database.\n\n## TiDB Cloud Starter vs. Vercel Postgres, Neon, and Supabase\n\nMost Vercel developers choose between Vercel Postgres (now Neon through the Marketplace), Supabase, and TiDB Cloud Starter. All three are managed, all three scale to zero, and all three offer an HTTP driver for edge runtimes. The differences that matter for AI apps show up in scaling model, vector handling, and analytics.\n\n|  | TiDB Cloud Starter | Vercel Postgres / Neon | Supabase | \n|---|---|---|---|\n| Wire protocol | MySQL | PostgreSQL | PostgreSQL | \n| Write scaling | Horizontal across nodes, no manual sharding | Vertical on a single primary, read replicas for reads | Vertical on a single primary, read replicas for reads | \n| Edge connectivity | HTTPS serverless driver, Prisma and Kysely adapters | HTTP driver ( `@neondatabase/serverless` ) | HTTP via PostgREST, or Supavisor for pooled TCP | \n| Vector search | Native `VECTOR` type with HNSW index in the same database | pgvector extension | pgvector extension | \n| Analytics on live data | HTAP: row store plus columnar replica in one system | Analytical queries hit the same row store | Analytical queries hit the same row store | \n| Beyond the database | Database only | Database only | Auth, storage, realtime, edge functions | \n\nRead the table by what your app needs rather than by row count. More detail on the tiers and limits is on the [TiDB Cloud Starter product page](https://www.pingcap.com/tidb-cloud-starter/).\n\n## Spin Up Your Free TiDB Cloud Starter Cluster\n\nYou now have the full path: a prototype wired to a real database, schema for sessions and agent state, embeddings stored beside the rows they describe, edge connectivity over HTTPS, and a one-click deployment that configures itself.\n\n[Start a free TiDB Cloud Starter cluster](https://tidbcloud.com/free-trial) and point your Vercel app at it. The full source for the demo app is in the [demo repository on GitHub](https://github.com/pingcap/tidb-prisma-vercel-demo).\n\nSpin up a database with 25 GiB free resources.\n\n## TiDB Cloud Dedicated\n\nA fully-managed cloud DBaaS for predictable workloads\n\n## TiDB Cloud Starter\n\nA fully-managed cloud DBaaS for auto-scaling workloads", "url": "https://wpnews.pro/news/vercel-and-tidb-cloud-starter-the-full-stack-playbook-for-ai-apps", "canonical_source": "https://www.pingcap.com/blog/build-with-tidb-cloud-starter-vercel-database/", "published_at": "2026-09-24 20:52:55+00:00", "updated_at": "2026-09-25 21:29:46.107630+00:00", "lang": "en", "topics": ["ai-infrastructure", "developer-tools", "ai-products"], "entities": ["Vercel", "TiDB", "TiDB Cloud Starter", "PingCAP", "v0.dev", "Lovable", "Next.js", "Cloudflare Workers"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/vercel-and-tidb-cloud-starter-the-full-stack-playbook-for-ai-apps", "markdown": "https://wpnews.pro/news/vercel-and-tidb-cloud-starter-the-full-stack-playbook-for-ai-apps.md", "text": "https://wpnews.pro/news/vercel-and-tidb-cloud-starter-the-full-stack-playbook-for-ai-apps.txt", "jsonld": "https://wpnews.pro/news/vercel-and-tidb-cloud-starter-the-full-stack-playbook-for-ai-apps.jsonld"}}