---
title: BYOC Provisioning Reference
product: vercel
url: /docs/networking/bring-your-own-cloud/provisioning-reference
canonical_url: "https://vercel.com/docs/networking/bring-your-own-cloud/provisioning-reference"
last_updated: 2018-10-20
type: reference
prerequisites:
  - /docs/networking/bring-your-own-cloud
  - /docs/networking
related:
  - /docs/networking/bring-your-own-cloud
  - /docs/networking/bring-your-own-cloud/operations
  - /docs/rest-api
  - /docs/networking/bring-your-own-cloud/deploy-with-github-actions
  - /docs/webhooks/webhooks-api
summary: "Reference for Bring Your Own Cloud (BYOC) provisioning: the descriptor.json format, generated files, values to preserve, size limits, permissions,..."
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

# BYOC Provisioning Reference

> **Availability**: Bring Your Own Cloud is available on Enterprise plans and is set up through your Vercel account team. Contact your account team to request access.

A [Bring Your Own Cloud (BYOC)](/docs/networking/bring-your-own-cloud) provisioning tool reads the files that `vercel deploy describe` generates and creates matching AWS Lambda layers and functions in your account. Use this reference to build or audit a provisioning tool, whether you use Terraform, the AWS SDK, the AWS CLI, or a script generated by the [BYOC agent skill](https://github.com/vercel-labs/vercel-byoc).

## Generated files

`vercel deploy describe --id <deployment-id> --aws-account-id <aws-account-id>` writes these files:

| Path                                    | Contents                                                                                       | Uploaded to Vercel |
| --------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------ |
| `.vercel/<deployment-id>/descriptor.json` | The functions and layers to create, in the [descriptor format](#descriptor-file-format)       | No                 |
| `.vercel/<deployment-id>/zips/<sha256>.zip` | One function package per file. The file name is the SHA-256 hash of the ZIP contents.     | No                 |
| `.vercel/<deployment-id>/layers/<sha256>.zip` | One runtime layer package per file                                                        | No                 |
| `.vercel/<deployment-id>/build/`        | The original build output, moved from `.vercel/output`                                        | No                 |
| `.vercel/output/`                       | The build output with function code removed                                                   | Yes, by `vercel deploy continue` |
| `.vercel/output/provision.json`         | The mapping from routes to Lambda functions, in the [`provision.json` format](#route-mapping-file-format) | Yes, by `vercel deploy continue` |

`vercel deploy describe` creates the `.vercel/<deployment-id>/` directory with owner-only permissions (`0700`) and writes `descriptor.json` and the function ZIP files with mode `0600`. Function ZIP files include your application code and the deployment's environment variables, so keep them private in CI artifacts and caches.

If you run `vercel deploy describe` again for the same deployment, it reads the original build from `.vercel/<deployment-id>/build/` instead of the code-free `.vercel/output`.

## Descriptor file format

The descriptor file, `descriptor.json`, describes every Lambda layer and function to create for one deployment.

### Top-level fields

| Field          | Type     | Description                                                                                                  |
| -------------- | -------- | ------------------------------------------------------------------------------------------------------------ |
| `version`      | `number` | Descriptor format version. Always `1`.                                                                       |
| `deploymentId` | `string` | The Vercel deployment ID, in the form `dpl_...`                                                              |
| `awsAccountId` | `string` | The 12-digit AWS account ID passed to `--aws-account-id`                                                     |
| `layers`       | `object` | A map from layer key to the layer ZIP file path, relative to the descriptor, such as `layers/<sha256>.zip`   |
| `functions`    | `array`  | One entry per Lambda function to create. See [Function fields](#function-fields).                            |

### Function fields

| Field           | Type       | Description                                                                                                  |
| --------------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
| `code`          | `string`   | The function ZIP file path, relative to the descriptor, such as `zips/<sha256>.zip`                          |
| `region`        | `string`   | The AWS region to create the function in, such as `us-east-1`                                                |
| `layers`        | `string[]` | Keys into the top-level `layers` map, in the order the function needs them                                   |
| `configuration` | `object`   | Lambda function settings, using AWS `CreateFunction` parameter names. See [Configuration fields](#configuration-fields). |

A deployment that runs in several regions has one `functions` entry per function per region.

### Configuration fields

`configuration` uses the parameter names of the AWS Lambda [`CreateFunction`](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html) API, so you can pass it to the API with only the role, code, and layers added.

| Field                   | Type                     | Required | Description                                       |
| ----------------------- | ------------------------ | -------- | ------------------------------------------------- |
| `FunctionName`          | `string`                 | Yes      | The function name Vercel invokes                  |
| `Handler`               | `string`                 | Yes      | The entry point inside the function package      |
| `Runtime`               | `string`                 | Yes      | The Lambda runtime identifier                     |
| `MemorySize`            | `number`                 | Yes      | Memory in MB                                      |
| `Environment.Variables` | `Record<string, string>` | Yes      | Environment variables for the function            |
| `Tags`                  | `Record<string, string>` | Yes      | Tags to apply to the function                     |
| `Timeout`               | `number`                 | No       | Maximum execution time in seconds                 |
| `Architectures`         | `string[]`               | No       | The instruction set architecture, such as `x86_64` or `arm64` |
| `EphemeralStorage.Size` | `number`                 | No       | Size of the `/tmp` directory in MB                |

`configuration` never contains `Role`, `Code`, or `Layers`. Your provisioning tool supplies them:

| Parameter | Value to supply                                                                                       |
| --------- | ----------------------------------------------------------------------------------------------------- |
| `Role`    | The ARN of your Lambda execution role                                                                 |
| `Code`    | The function ZIP file at `code`, uploaded directly or from Amazon S3                                  |
| `Layers`  | The ARNs of the layer versions you published in the function's region, in the order of `layers`      |

### Example descriptor

This example shows the structure of a descriptor for one function in one region. Generated values differ for every deployment:

```json filename=".vercel/dpl_1234567890abcdefghij/descriptor.json"
{
  "version": 1,
  "deploymentId": "dpl_1234567890abcdefghij",
  "awsAccountId": "<AWS_ACCOUNT_ID>",
  "layers": {
    "example_layer_key": "layers/example_layer_sha256.zip"
  },
  "functions": [
    {
      "code": "zips/example_function_sha256.zip",
      "region": "us-east-1",
      "layers": ["example_layer_key"],
      "configuration": {
        "FunctionName": "example_function_name",
        "Handler": "example_handler",
        "Runtime": "nodejs22.x",
        "MemorySize": 1024,
        "Timeout": 300,
        "Architectures": ["x86_64"],
        "Environment": {
          "Variables": {
            "EXAMPLE_VARIABLE": "example_value"
          }
        },
        "Tags": {
          "example_tag_key": "example_tag_value"
        }
      }
    }
  ]
}
```

## Provisioning requirements

A provisioning tool must do the following for every deployment:

1. **Publish layers per region**: For each region that a function uses, publish every layer it references. Use the layer key as the layer name, and reuse an existing layer version when its code hash matches the ZIP file.
2. **Create functions**: Create each function in its `region` with its `configuration`, plus `Role`, `Code`, and `Layers`.
3. **Wait for Active**: Wait until every function reaches the Lambda `Active` state before running `vercel deploy continue`.
4. **Grant invocation**: Make sure the invocation role allows `lambda:InvokeFunction` on every created function.
5. **Record an inventory**: Save the ARNs of the functions and layer versions you created, so you can [retry and clean up](/docs/networking/bring-your-own-cloud/operations) later.

Finish steps 1 to 4 and run `vercel deploy continue` within 15 minutes of `vercel deploy init`.

### Values to keep as generated

Vercel invokes functions by their generated names, and your build depends on the generated runtime settings. Keep these values exactly as they appear in the descriptor:

- `FunctionName`
- `Handler`
- `Runtime`, `Architectures`, `MemorySize`, `Timeout`, and `EphemeralStorage`
- `Environment.Variables`
- `Tags`
- The layer order in `layers`

You can add settings that the descriptor doesn't define, such as a VPC configuration, additional layers, or extra tags, through your provisioning tool. If you attach functions to a VPC, give the execution role the permissions Lambda needs to manage network interfaces, such as the AWS managed policy `AWSLambdaVPCAccessExecutionRole`, and route the subnets through a NAT gateway or equivalent egress.

### Existing functions

A function with the same name can already exist, for example from an earlier attempt at the same deployment. Reuse an existing function only when its code hash and full configuration match the descriptor. Don't update or overwrite a function that differs, because it may serve another deployment that's still receiving traffic. Stop and investigate the conflict instead.

### Function package size

AWS Lambda accepts function ZIP files up to 50 MB when you upload them directly. For larger packages, upload the ZIP file to a private Amazon S3 bucket in the same region as the function and create the function from the bucket. The standard Vercel Functions bundle size limits still apply. See [BYOC limitations](/docs/networking/bring-your-own-cloud#byoc-limitations).

## Provisioning identity permissions

The identity that runs your provisioning tool needs permission to publish layers, create and read functions, tag them, and pass the execution role to Lambda. This example policy covers those actions. Replace `<AWS_ACCOUNT_ID>` with your AWS account ID and `byoc-lambda-execution` with your execution role name:

```json filename="provisioner-policy.json"
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ManageByocLayers",
      "Effect": "Allow",
      "Action": [
        "lambda:ListLayerVersions",
        "lambda:GetLayerVersion",
        "lambda:PublishLayerVersion"
      ],
      "Resource": "*"
    },
    {
      "Sid": "ManageByocFunctions",
      "Effect": "Allow",
      "Action": [
        "lambda:CreateFunction",
        "lambda:GetFunction",
        "lambda:GetFunctionConfiguration",
        "lambda:TagResource"
      ],
      "Resource": "arn:aws:lambda:*:<AWS_ACCOUNT_ID>:function:*"
    },
    {
      "Sid": "PassExecutionRole",
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::<AWS_ACCOUNT_ID>:role/byoc-lambda-execution",
      "Condition": {
        "StringEquals": {
          "iam:PassedToService": "lambda.amazonaws.com"
        }
      }
    }
  ]
}
```

Add `s3:PutObject` and `s3:GetObject` on your staging bucket if you upload large packages through Amazon S3, and `lambda:DeleteFunction` and `lambda:DeleteLayerVersion` if the same identity runs cleanup. Don't grant `AdministratorAccess` to the provisioning identity.

## Route mapping file format

The route mapping file, `provision.json`, maps each function route in your build to the Lambda function that serves it. Vercel reads it to decide which function to invoke for a request. Don't edit it.

| Field          | Type       | Description                                       |
| -------------- | ---------- | ------------------------------------------------- |
| Key            | `string`   | The function's route path in the build output     |
| `awsAccountId` | `string`   | The AWS account that hosts the function           |
| `functionName` | `string`   | The Lambda function name Vercel invokes           |
| `regions`      | `string[]` | The AWS regions the function runs in              |
| `digest`       | `string`   | The hash of the function package                  |
| `size`         | `number`   | The size of the function package in bytes         |

## Deployment provisioning states

A BYOC deployment includes a `manualProvisioning` object in the [Vercel REST API](/docs/rest-api) deployment response, for example from `GET /v13/deployments/{idOrUrl}`. The deployment stays in the `INITIALIZING` state until you run `vercel deploy continue`.

| `manualProvisioning.state` | Meaning                                                                                                   |
| -------------------------- | --------------------------------------------------------------------------------------------------------- |
| `PENDING`                  | The deployment is waiting for you to provision its functions and run `vercel deploy continue`             |
| `COMPLETE`                 | Vercel received the continuation. `manualProvisioning.completedAt` holds the completion timestamp.        |
| `TIMEOUT`                  | 15 minutes passed without a continuation, and the deployment failed                                       |

## CLI commands

| Command                                                                  | Purpose                                                                                        |
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `vercel deploy init --target <environment> --json`                       | Create a deployment that waits for provisioning. Uploads no files.                              |
| `vercel build --id <deployment-id> --target <environment>`               | Build with the deployment's environment variables                                               |
| `vercel deploy describe --id <deployment-id> --aws-account-id <aws-account-id>` | Generate `descriptor.json`, function packages, and the code-free output. Add `--json` for machine-readable output. |
| `vercel deploy continue --id <deployment-id>`                            | Upload the code-free output and `provision.json`, then wait for the deployment to finish       |
| `vercel deploy continue --id <deployment-id> --error "<reason>"`         | Mark a pending deployment as failed                                                             |
| `vercel inspect <deployment-id> --wait`                                  | Wait for the deployment to finish and show its status                                           |
| `vercel curl <path> --deployment <deployment-id>`                        | Send a request to a specific deployment                                                         |

`vercel deploy describe` requires Vercel CLI 62.7.0 or later. Use Vercel CLI 63.1.2 or later for BYOC deployments.

## Webhook events

| Event                        | When it fires                                                                                                           | Used for                                                                                                    |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `deployment.build-requested` | Vercel created a BYOC deployment from a Git push and is waiting for your environment to build it                       | Starting builds from Git. See [Deploying with BYOC from GitHub Actions](/docs/networking/bring-your-own-cloud/deploy-with-github-actions). |
| `deployment.cleanup`         | A deployment is permanently deleted, after its 30-day recovery period                                                   | Triggering AWS resource cleanup. See [Cleanup and retention](/docs/networking/bring-your-own-cloud/operations#cleanup-and-retention). |

For webhook payloads, see the [webhooks API reference](/docs/webhooks/webhooks-api).

## Related

- [Deploying with BYOC using the Vercel CLI](/docs/networking/bring-your-own-cloud/deploy-with-cli)
- [Operating BYOC deployments](/docs/networking/bring-your-own-cloud/operations)
- [AWS Lambda `CreateFunction` API](https://docs.aws.amazon.com/lambda/latest/api/API_CreateFunction.html)


---

[View full sitemap](/docs/sitemap)
