apps/docs/content/docs/guides/integrations/vercel-deployment.mdx
This guide shows you how to implement instant app deployment using Vercel's API with integrated Prisma Postgres databases. You'll learn to programmatically create, deploy, and transfer full-stack applications with a single API call.
Instant app deployment solves a critical problem for AI coding platforms, no-code tools, and educational platforms: getting from generated code to a live, production-ready application. Instead of requiring users to manually set up hosting infrastructure, you can offer one-click deployments with both application and database.
By the end of this guide, you'll understand how to integrate Vercel's deployment API with Prisma Postgres to create a smooth deployment experience for your users.
Experience the instant deployment flow with our interactive demo. You can deploy and claim real applications to see the complete process in action.
Available examples:
Demo features:
Visit the GitHub repository for the demo.
This guide is designed for developers building:
Before implementing the deployment flow, let's understand the key concepts:
The deployment process uses several key Vercel API endpoints:
POST /v10/projects - Create a new Vercel projectPOST /v1/integrations/billing/authorization - Authorize Prisma integrationPOST /v1/storage/stores/integration - Create Prisma Postgres databasePOST /v13/deployments - Deploy application codePOST /v9/projects/{id}/transfer-request - Generate claim code for user transfer:::tip[Contact us for elevated partner level access for db creation]
By default, every new partner is on our free plan which limited to 5 dbs per account, so if you are trying out this API and need higher db creation limits (which we suspect that most of you will), then please contact us to get partner level access. :::
Your primary authentication token for Vercel API calls.
Where to get it:
:::tip
You need "Owner" level access to the Vercel team to ensure the ACCESS_TOKEN works for all the API calls.
:::
ACCESS_TOKEN="vercel_token_here"
:::note[Credit card requirement] Vercel requires a credit card to be attached to your account (even on the Hobby plan) to use the deployment APIs. Make sure to add payment information in your Vercel account settings before proceeding. :::
Your Vercel team identifier for API requests.
Where to get it:
team_abc123xyz)TEAM_ID="team_abc123xyz"
Your team's Prisma integration configuration identifier.
Where to get it:
https://vercel.com/teams/your-team/integrations/icfg_abc123xyzicfg_abc123xyz partINTEGRATION_CONFIG_ID="icfg_abc123xyz"
The Prisma Product ID is used to identify the Prisma integration in the Vercel API and it's a constant value of: iap_yVdbiKqs5fLkYDAB or prisma-postgres.
PRISMA_PRODUCT_ID="iap_yVdbiKqs5fLkYDAB"
The region where your Prisma Postgres database will be deployed. Choose a region close to your users for optimal performance.
Available regions:
iad1 - US East (Virginia)fra1 - Europe (Frankfurt)sfo1 - US West (San Francisco)sin1 - Asia Pacific (Singapore)hnd1 - Asia Pacific (Tokyo)cdg1 - Europe (Paris)PRISMA_POSTGRES_REGION="iad1"
See the complete list of supported Prisma Postgres regions and their corresponding Vercel region codes.
The billing plan determines database limits and features. Available plans:
free - Limited to 5 databases, suitable for developmentpro - Higher limits with connection pooling and cachingbusiness - Enterprise features with priority supportenterprise - Custom limits and dedicated supportpartnerEntry - Partner-level access with high database limitsPRISMA_BILLING_PLAN="partnerEntry"
:::tip[Partner access recommended]
For production deployments requiring multiple databases, we recommend the partnerEntry plan which provides higher database creation limits. Apply for partner access to unlock these capabilities.
:::
The code snippet below shows the complete deployment flow:
const CONFIG = {
ACCESS_TOKEN: process.env.ACCESS_TOKEN,
TEAM_ID: process.env.TEAM_ID,
INTEGRATION_CONFIG_ID: process.env.INTEGRATION_CONFIG_ID,
PRISMA_PRODUCT_ID: process.env.PRISMA_PRODUCT_ID || "iap_yVdbiKqs5fLkYDAB", // or can be `prisma-postgres`
PRISMA_POSTGRES_REGION: process.env.PRISMA_POSTGRES_REGION || "iad1",
PRISMA_BILLING_PLAN: process.env.PRISMA_BILLING_PLAN || "partnerEntry",
VERCEL_API_URL: "https://api.vercel.com",
};
async function deployApp() {
console.log("🚀 Starting instant deployment...");
// 1. Create project
const project = await createProject();
// 2. Authorize Prisma integration
const auth = await createPrismaAuthorization();
// 3. Create database
const database = await createPrismaDatabase(project.name, auth.id, auth.configId);
// 4. Connect database to project
await connectDatabaseToProject(project.id, database.id, auth.configId);
// 5. Deploy application (assumes files already uploaded)
const deployment = await deployApplication(project.name, fileSha);
// 6. Generate claim code
const transfer = await createProjectTransfer(project.id);
console.log("🎉 Deployment completed!");
console.log(`Live URL: https://${deployment.url}`);
console.log(`Claim URL: ${transfer.claimUrl}`);
return {
projectId: project.id,
deploymentUrl: `https://${deployment.url}`,
claimCode: transfer.code,
claimUrl: transfer.claimUrl,
};
}
The complete example above demonstrates the entire deployment process. Now let's break down each step in detail.
Every deployment starts with creating a project container.
async function createProject(): Promise<{ id: string; name: string }> {
const projectName = `demo-project-${Date.now()}`;
const response = await fetch(`${CONFIG.VERCEL_API_URL}/v10/projects?teamId=${CONFIG.TEAM_ID}`, {
method: "POST",
headers: {
Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ name: projectName }),
});
const project = await response.json();
console.log(`✅ Project created: ${project.name} (${project.id})`);
return { id: project.id, name: project.name };
}
Key parameters:
name: Unique project identifier (auto-generated with timestamp)teamId: Your team ID for proper project ownershipLearn more in the Vercel Projects API documentation.
Before creating databases, you need authorization to use Prisma on behalf of your team.
async function createPrismaAuthorization(): Promise<{
id: string;
configId: string;
}> {
const response = await fetch(
`${CONFIG.VERCEL_API_URL}/v1/integrations/billing/authorization?teamId=${CONFIG.TEAM_ID}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
integrationIdOrSlug: "prisma",
productId: CONFIG.PRISMA_PRODUCT_ID,
billingPlanId: CONFIG.PRISMA_BILLING_PLAN,
metadata: JSON.stringify({ region: CONFIG.PRISMA_POSTGRES_REGION }),
integrationConfigurationId: CONFIG.INTEGRATION_CONFIG_ID,
}),
},
);
const authData = await response.json();
return {
id: authData.authorization.id,
configId: authData.authorization.integrationConfigurationId,
};
}
Key parameters:
billingPlanId: Billing plan ("partnerEntry" recommended for production)region: Database region for optimal performancemetadata: JSON string containing region and other configurationLearn more in the Vercel Integrations API documentation.
Create a new database instance with automatic connection pooling and caching.
async function createPrismaDatabase(
projectName: string,
authId: string,
configId: string,
): Promise<{ id: string }> {
const response = await fetch(
`${CONFIG.VERCEL_API_URL}/v1/storage/stores/integration?teamId=${CONFIG.TEAM_ID}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
metadata: { region: CONFIG.PRISMA_POSTGRES_REGION },
billingPlanId: CONFIG.PRISMA_BILLING_PLAN,
name: `postgres-${projectName}`,
integrationConfigurationId: configId,
integrationProductIdOrSlug: CONFIG.PRISMA_PRODUCT_ID,
authorizationId: authId,
source: "marketplace",
}),
},
);
const storageData = await response.json();
return {
id: storageData.store.id,
};
}
Key parameters:
name: Database identifier (typically matches project name)source: "marketplace" for Vercel marketplace integrationsbillingPlanId: Billing plan that determines features and limitsLearn more in the Vercel Storage API documentation.
Link the database to your Vercel project for automatic environment variable injection.
async function connectDatabaseToProject(
projectId: string,
storeId: string,
configId: string,
): Promise<void> {
await fetch(
`${CONFIG.VERCEL_API_URL}/v1/integrations/installations/${configId}/products/${CONFIG.PRISMA_PRODUCT_ID}/resources/${storeId}/connections?teamId=${CONFIG.TEAM_ID}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ projectId }),
},
);
console.log("✅ Database connected to project");
}
This connection automatically adds DATABASE_URL and other environment variables to your project.
Learn more in the Vercel Integration Resources documentation.
Deploy your application code to Vercel.
async function deployApplication(
projectName: string,
fileSha: string,
): Promise<{ id: string; url: string }> {
const response = await fetch(
`${CONFIG.VERCEL_API_URL}/v13/deployments?teamId=${CONFIG.TEAM_ID}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
files: [{ file: ".vercel/source.tgz", sha: fileSha }],
name: `deployment-${Date.now()}`,
projectSettings: { framework: "nextjs" },
project: projectName,
}),
},
);
const deploymentData = await response.json();
return {
id: deploymentData.id,
url: deploymentData.alias?.[0] || deploymentData.url,
};
}
Key parameters:
files: Array of uploaded files (requires prior file upload in tgz format)framework: "nextjs", "react", "vue", etc. for automatic configurationprojectSettings: Framework-specific build and runtime settingsLearn more in the Vercel Deployments API documentation or see the Vercel API Reference.
Create a transfer code that allows users to claim ownership of the deployed project.
async function createProjectTransfer(
projectId: string,
): Promise<{ code: string; claimUrl: string }> {
const response = await fetch(
`${CONFIG.VERCEL_API_URL}/v9/projects/${projectId}/transfer-request?teamId=${CONFIG.TEAM_ID}`,
{
method: "POST",
headers: {
Authorization: `Bearer ${CONFIG.ACCESS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
},
);
const transferData = await response.json();
const claimUrl = `https://vercel.com/claim-deployment?code=${transferData.code}&returnUrl=https://myapp.com/dashboard/projects`;
return {
code: transferData.code,
claimUrl,
};
}
Key details:
returnUrl redirects users to a specific page if the claim URL is invalid or expiredLearn more in the Vercel Claim Deployments documentation.
After deployment, users can claim ownership through a secure transfer process:
https://vercel.com/claim-deployment?code=xxx&returnUrl=https://myapp.com/dashboard/projects
Parameters:
code: The transfer code from Step 6 (valid 24 hours)returnUrl: Redirects users to a specific page if the claim URL is invalid or expiredWhen a user claims a deployment, they receive:
Learn more in the Claim Deployments documentation.
async function handleApiErrors(response: Response, operation: string) {
if (!response.ok) {
const errorData = await response.text();
// Handle specific error cases
switch (response.status) {
case 401:
throw new Error(`Authentication failed: Check your ACCESS_TOKEN`);
case 403:
throw new Error(`Permission denied: Verify team access and scopes`);
case 429:
throw new Error(`Rate limit exceeded: Implement retry logic`);
case 404:
throw new Error(`Resource not found: Check IDs and configuration`);
default:
throw new Error(`${operation} failed: ${response.status} - ${errorData}`);
}
}
}
Proper error handling prevents deployment failures and provides clear debugging information to your users.
Vercel enforces rate limits on API endpoints. You can implement exponential backoff to handle rate limits:
async function apiCallWithRetry(url: string, options: RequestInit, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
const waitTime = Math.pow(2, attempt) * 1000; // Exponential backoff
await new Promise((resolve) => setTimeout(resolve, waitTime));
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries) throw error;
}
}
}
Retry logic ensures your deployment service remains reliable during high-traffic periods.
Learn more in the Vercel API Limits documentation.
These practices protect your integration from common security vulnerabilities and ensure stable operation.
The following are some production considerations for your deployment service:
You can integrate your deployment service with existing platforms to provide a smooth experience for your users:
// Example integration with an AI coding platform
class DeploymentService {
async deployGeneratedApp(code: string, userId: string) {
// 1. Package generated code
const packagedCode = await this.packageCode(code);
// 2. Deploy with Vercel + Prisma
const deployment = await this.deployApp(packagedCode);
// 3. Store deployment info
await this.storeDeployment(userId, deployment);
// 4. Notify user
await this.notifyUser(userId, deployment.claimUrl);
return deployment;
}
}
Track key metrics for your deployment service:
Now that you understand instant app deployment with Vercel and Prisma Postgres, you can:
For questions or support with your integration, reach out through the Prisma Community Discord or Vercel Support.