Deploy Files
The Deploy Files action is a server-side utility that allows platforms to programmatically deploy files to Vercel. This is the core functionality behind platforms like Mintlify and Hashnode that create Vercel deployments for their users without requiring direct Vercel account access.
Install the deploy-files action with the Vercel Platforms CLI:
npx @vercel/platforms@latest add deploy-filesYou can also install it with the shadcn CLI:
npx shadcn@latest add https://registry.platforms.guide/deploy-files.jsonBoth commands copy the action's TypeScript source into your project, so you own the code and edit it to fit your platform. The installed file exports two Server Actions, deployFiles and getDeploymentStatus.
The registry item doesn't install @vercel/sdk, which the action depends on. Add it to your project:
npm i @vercel/sdk- Programmatic deployment: Create production deployments with the Vercel SDK
- Custom domain support: Add a domain to the deployment's project
- Project configuration: Pass build settings such as the framework, build command, and output directory
- Public deployments: Remove SSO protection from new projects so their deployments are publicly reachable
- Unique deployment naming: Generate a UUID when you don't pass a deployment name
- Status checks: Poll a deployment's state with
getDeploymentStatus
The installed deployFiles action deploys a hardcoded sample: one index.html file with a randomly styled "Hello, world!" heading. The action doesn't accept files as an argument. To deploy your users' files, edit the action as shown in Deploy your own files.
Each call to deployFiles runs these steps:
- Reads the target project ID from the
DEPLOY_FILES_PROJECT_IDenvironment variable. - Creates a production deployment (
target: "production") from thefilesarray defined inside the action. - If
DEPLOY_FILES_PROJECT_IDisn't set, deploys to a project named after the sanitizeddeploymentName, then sets that project'sssoProtectiontonullso its deployments are public. - If you pass
domain, adds that domain to the deployment's project. - Returns the deployment object from the Vercel SDK, including its
idandurl.
The action imports vercel and VERCEL_TEAM_ID from ../lib/vercel, and the registry doesn't install that file. Create lib/vercel.ts in a lib directory next to the directory that contains deploy-files.ts, so the relative import resolves:
import { Vercel } from '@vercel/sdk';
export const VERCEL_TEAM_ID = process.env.VERCEL_TEAM_ID;
if (!(process.env.VERCEL_TOKEN && VERCEL_TEAM_ID)) {
throw new Error('VERCEL_TOKEN and VERCEL_TEAM_ID must be set');
}
export const vercel = new Vercel({
bearerToken: process.env.VERCEL_TOKEN,
});Set these environment variables:
| Variable | Required | Description |
|---|---|---|
VERCEL_TOKEN | Yes | Vercel access token that the SDK client uses to create deployments and update projects |
VERCEL_TEAM_ID | Yes | ID of the Vercel team that owns the deployments |
DEPLOY_FILES_PROJECT_ID | No | Existing project to deploy to. If unset, the action deploys to a project named after the sanitized deploymentName |
Call the installed action from server-side code:
import { deployFiles } from '@/actions/deploy-files';
const deployment = await deployFiles({
deploymentName: 'customer-deployment-1',
domain: 'customer-site.com',
});
console.log(deployment.url);deployFiles takes one optional object argument. The installed action has no files or projectId parameter; it reads files from the files array inside the action and the project from DEPLOY_FILES_PROJECT_ID.
| Option | Type | Required | Description |
|---|---|---|---|
deploymentName | string | No | Deployment name. Defaults to a UUID. The action lowercases it, replaces unsupported characters with -, and truncates it to 100 characters. It's also the project name when DEPLOY_FILES_PROJECT_ID isn't set |
config | ProjectSettings | No | Project settings for the deployment, such as framework, buildCommand, installCommand, and outputDirectory. When you omit it, Vercel detects the settings automatically |
domain | string | No | Domain to add to the deployment's project after the deployment is created |
getDeploymentStatus(id) takes a deployment ID and returns an object with the deployment's readyState, url, and id.
To deploy files your platform generates, change the action to accept a files argument. In your installed deploy-files.ts, add files to the argument type, remove the hardcoded files constant, and read files from the arguments instead:
export async function deployFiles(args: {
files: InlinedFile[];
deploymentName?: string;
config?: ProjectSettings;
domain?: string;
}) {
// you can update this to load the project id from your database instead
const projectId = process.env.DEPLOY_FILES_PROJECT_ID;
const { files, deploymentName = crypto.randomUUID(), config, domain } = args;
const sanitizedName = sanitizeProjectName(deploymentName);
// The rest of the function body stays the same
}The action already imports the InlinedFile and ProjectSettings types from @vercel/sdk/models/createdeploymentop.js. To deploy each user's files to that user's own project, replace the DEPLOY_FILES_PROJECT_ID lookup, for example by loading the project ID from your database.
After the change, pass files when you call the action:
import { deployFiles } from '@/actions/deploy-files';
const deployment = await deployFiles({
files: [
{
file: 'index.html',
data: '<html><body><h1>Hello from my platform!</h1></body></html>',
},
],
deploymentName: 'customer-deployment-1',
config: {
framework: null, // Static HTML, no build step
},
domain: 'customer-site.com',
});For a framework app, pass its source files and set config to match, for example framework: 'nextjs' with buildCommand and outputDirectory.
After creating a deployment with this action, you typically show the Claim Deployment component to allow users to take ownership:
// 1. Deploy files server-side
const deployment = await deployFiles({ domain })
// 2. Show claim interface client-side
<ClaimDeployment
url={deployment.url}
onClaimClick={handleTransferOwnership}
/>deployFilesis a Server Action, so any client that can reach your app can call it with arguments it chooses. Check authentication and authorization inside the action before deploying- This action requires Vercel API credentials with deployment permissions
- Always validate and sanitize file contents and domains before deployment
- Consider implementing rate limiting to prevent abuse
- Store API credentials securely using environment variables
Was this helpful?