Copy link to headingHow can I use GitLab and Bitbucket Pipelines with Vercel?
Vercel for GitLab and Vercel for Bitbucket deploy your repository on every push and comment preview URLs on merge and pull requests. They also keep your custom domains pointed at the latest production deployment. For most teams, that connection is all the continuous integration and continuous delivery (CI/CD) they need.
Some teams need their own pipeline instead, either because they run tests and approval gates before a deploy or because their Git server runs inside their own network. GitLab CI/CD and Bitbucket Pipelines both handle that through the Vercel CLI, and the setup is close to identical on either provider. Here's how to set up both, starting with the mechanism they share and ending with the failures that show up once your CI owns the build.
Copy link to headingWhen to replace the Vercel GitLab or Bitbucket integration with your own pipeline
Vercel's Git integration owns the deployment lifecycle. It builds each push, publishes a preview URL, promotes to production, and rolls back instantly. A pipeline adds the steps that run around that work. Three situations call for one:
- Gated deploys: Run your tests, security scans, and approval steps in the pipeline, then hand Vercel a build that has already passed them.
vercel buildandvercel deployare separate commands, so the gate sits between them. - Self-hosted Git: Vercel supports Self-Managed GitLab and Bitbucket Data Center through pipelines, which deploy from inside your own network using an access token.
- Source code control:
vercel buildcompiles in your own runner and uploads only the output, so your source stays on your infrastructure.
If none of those apply, the built-in integration already covers the job, and adding a pipeline on top means managing build caching and preview URL comments yourself.
Copy link to headingHow GitLab and Bitbucket Pipelines deploy to Vercel
The pipeline builds your project in its own runner, then uploads the finished output to Vercel instead of the source.
Three CLI commands do the work:
vercel pull: Downloads the project settings and environment variables for the target environment into a local.verceldirectory.vercel build: Detects your framework and compiles the project into a.vercel/outputfolder that follows the Build Output API specification.vercel deploy --prebuilt: Uploads that output folder and creates a deployment. Vercel skips the build step entirely.
The --prebuilt flag tells Vercel the build is already done, so it serves the uploaded output as-is. Leave the flag off and Vercel rebuilds an artifact your pipeline already produced, which doubles your CI minutes and slows every deployment down.
Because the build no longer runs on Vercel, no Git metadata travels with the deployment, so both configs pass the branch details explicitly with the --meta option.
Copy link to headingHow to set up GitLab CI/CD with Vercel
GitLab needs one pipeline file and three CI/CD variables. Start with the pipeline file, since the variables it references are the ones you'll add afterward.
Copy link to headingWrite the .gitlab-ci.yml pipeline
Create a .gitlab-ci.yml file at the root of your repository with a preview job and a production job:
Set the image to the same Node.js major version your project builds with on Vercel, which supports 24.x, 22.x, and 20.x. The rules keyword replaces the older only and except keywords, which GitLab has deprecated in favor of rules.
Copy link to headingAdd the Vercel credentials as GitLab CI/CD variables
The pipeline reads three values that have to exist before it can run. Collect them in this order:
- Create a Vercel access token and copy it.
- Install the Vercel CLI locally and run
vercel login. - Run
vercel linkin your project directory to create or connect a Vercel project. - Open the generated
.vercel/project.jsonfile and copy theprojectIdandorgIdvalues. - In GitLab, add
VERCEL_TOKEN,VERCEL_ORG_ID, andVERCEL_PROJECT_IDas CI/CD variables under Settings > CI/CD > Variables.
Mark all three as masked and protected so they don't appear in job logs. Scope the token to a single team or project when you create it, which limits what a leaked CI credential can reach.
Copy link to headingRun the pipeline and confirm the deployment
Push a branch and open a merge request against your default branch. GitLab runs deploy_preview, and the pipeline log ends with the deployment URL, since vercel deploy always writes that URL to standard output.
Merging the request runs deploy_production and promotes the build to your production domains. Reverting and merging the revert produces a new production deployment from the earlier state, so rollbacks follow the same path as any other change.
Copy link to headingHow to set up Bitbucket Pipelines with Vercel
Bitbucket uses the same three CLI commands and the same three credentials as GitLab, and --prebuilt behaves identically. Only the file syntax and the variable screen change.
Copy link to headingWrite the bitbucket-pipelines.yml file
Create a bitbucket-pipelines.yml file at the root of your repository:
The default section runs for any branch not listed under branches, so every branch gets a preview deployment. If previews stop appearing, check for a narrower pattern like feature/*, which skips every branch that doesn't match.
Copy link to headingAdd the Vercel credentials as Bitbucket repository variables
The pipeline needs three values stored as secured repository variables. Collect them in this order:
- Create a Vercel access token and copy it.
- Install the Vercel CLI locally and run
vercel login. - Run
vercel linkin your project directory to create or connect a Vercel project. - Open the generated
.vercel/project.jsonfile and copy theprojectIdandorgIdvalues. - In Bitbucket, add
VERCEL_TOKEN,VERCEL_ORG_ID, andVERCEL_PROJECT_IDas secured variables under Repository settings > Repository variables.
Select Secured for the token so its value is masked in the build output. Repository variables are available to every branch, so scope the Vercel token to the team or project you deploy to.
Copy link to headingRun the pipeline and confirm the deployment
Push a branch and open a pull request. Bitbucket runs the default step, builds the project in its own runner, and uploads the output to Vercel as a preview deployment.
Merging the pull request into main runs the production step and promotes the build to your production domains. As with GitLab, reverting a merged commit and merging that revert creates a fresh production deployment from the earlier state.
Copy link to headingHow to deploy from Bitbucket without the Vercel Bitbucket integration
You can deploy from Bitbucket with nothing installed on the Bitbucket side. The CLI authenticates with a token, so the Vercel for Bitbucket app is optional. This is the path for Bitbucket Data Center, for repositories, your security policy keeps off third-party apps, and for anyone who wants Bitbucket to own deployment triggering outright.
You use the same bitbucket-pipelines.yml file and the same three repository variables either way. Without the app installed, four behaviors change:
- Preview URLs come from the pipeline log: The Vercel bot posts preview URLs through the Git integration. Without it, read the URL from the pipeline log or post it with a Bitbucket step.
- Branch metadata is passed explicitly: Include
m bitbucketDeployment="1"andm bitbucketCommitRefso the deployment binds to a branch rather than HEAD. - Redeploys run from the pipeline: Deploy Hooks work with a connected Git repository, so trigger redeploys from the pipeline or the Vercel REST API instead.
- Skip conditions live in the pipeline: The Ignored Build Step applies to builds that run on Vercel, so put the skip condition in
bitbucket-pipelines.ymlwhen your pipeline owns the build.
One team-level setting can block this path. Deployment Policies restrict which mechanisms may deploy to an environment, so confirm the CLI is permitted for the environment you're targeting before you debug the pipeline itself.
Copy link to headingWhich Vercel features change in a GitLab or Bitbucket pipeline
Your pipeline produces the same artifact on the same infrastructure the Git integration would have used. Instant rollback, Skew Protection, and Fluid compute behave identically. The differences sit around the deployment rather than in it.
Copy link to headingPreview and production targeting
Preview and production are selected by two flags rather than by branch. vercel pull --environment=preview fetches the preview environment's variables, and adding --prod to vercel build and vercel deploy targets production. For a custom environment, pass --target=staging on the deploy command using your environment's name.
Copy link to headingEnvironment variables at build time
Environment variables reach your build through vercel pull, which writes them into the local .vercel directory before vercel build runs. System Environment Variables are the exception, since they're populated by Vercel's build infrastructure and your runner isn't it. Frameworks that read values such as VERCEL_URL or VERCEL_ENV at build time need those values set in the pipeline environment instead.
Copy link to headingDeploy hooks alongside a pipeline
Deploy hooks stay available whenever the Git integration is still connected. A deploy hook is a URL that triggers a deployment of one branch on a GET or POST request, which suits content management system (CMS) publish events and scheduled rebuilds. It runs the build on Vercel rather than in your pipeline, so treat it as a second path into the same project rather than a replacement for the CLI.
Copy link to headingHow to troubleshoot GitLab and Bitbucket Pipelines with Vercel
Most pipeline problems come from a short list of causes, and the symptoms are specific enough to identify quickly.
Copy link to headingBranch URLs and branch-scoped variables are missing
A deployment created without Git metadata binds to HEAD, so branch-specific domains and environment variables never match. Fix it by passing both metadata keys on the deploy command, since the provider flag has to travel with the ref.
Pass the branch name on its own, not a full ref path. Values like refs/heads/main, or a code review ref such as refs/changes/45/2345/1, don't match a branch name, so the deployment falls back to HEAD and the branch URL never appears. Use $CI_COMMIT_BRANCH in GitLab and $BITBUCKET_BRANCH in Bitbucket, both of which hold the bare branch name.
Copy link to headingYour pipeline and the classic git integration both deploy the same commit
Search results and support threads use the phrase classic git integration to mean Vercel's built-in Git connection. If it's still connected when your pipeline starts deploying, both systems fire on the same push and you get two deployments per commit.
Turn off automatic deployments with git.deploymentEnabled in vercel.json:
Setting it to an object instead of false turns deployments off per branch with minimatch patterns such as "internal-*": false. Keeping the integration connected while disabling its deployments preserves pull request comments and repository metadata.
Copy link to headingThe build fails because system environment variables are missing
With --prebuilt, the build runs in your runner, so Vercel's System Environment Variables aren't available at build time. Frameworks that read them while compiling will fail or produce wrong output.
Set the values your framework needs directly in the pipeline environment, or move that project back to Git-based deployments. Skew Protection still works on Next.js under --prebuilt through a custom deployment ID, which cannot use the dpl_ prefix.
Copy link to headingA GitLab merge request pipeline fails while the branch pipeline passes
GitLab can report a passing branch pipeline alongside a failing merge pipeline, which lets a merge request merge with failing tests. This is a GitLab issue rather than a Vercel behavior.
Deploying through the Vercel CLI, as both sample configs do, avoids the mismatch because a single pipeline owns both the build and the deployment. The deploy job either succeeds or fails on its own result, with no second pipeline reporting something different.
Copy link to headingThe deployment hits the file upload limit
Projects with thousands of output files can exceed the files limit during upload. Compress the output before it ships by adding the archive option:
Archiving negates the source file caching that speeds up later uploads, so apply it only to the projects that need it. Working through these five causes in order accounts for the failures you're likeliest to hit before you need to open the build logs.
Copy link to headingNext steps
Once the pipeline runs cleanly on a branch, connect it to the rest of your workflow by adding your test and approval steps between vercel build and vercel deploy. Create the Vercel project the pipeline deploys to at vercel.com/new, or start from the completed GitLab CI/CD and Bitbucket Pipelines examples.
Copy link to headingRelated resources
- Vercel for GitLab
- Vercel for Bitbucket
- vercel deploy CLI reference
- Build Output API
- Git configuration in vercel.json
- Why are my branch specific variables and domains not linked to my CLI deployments?
Copy link to headingFrequently asked questions
Copy link to headingHow do I deploy a monorepo to Vercel from GitLab or Bitbucket Pipelines?
Run vercel link --repo from the monorepo root to link every Vercel project at once, then scope each pipeline job with vercel --cwd apps/your-app. Each project needs its own VERCEL_PROJECT_ID variable. See the monorepo documentation for root directory and workspace settings.
Copy link to headingHow do I stop Vercel from building commits that don't need a deployment?
When your pipeline builds the project, the skip condition belongs in your CI config: use rules:changes in GitLab or a condition on the step in Bitbucket. Vercel's Ignored Build Step applies to builds that run on Vercel, and a --prebuilt upload skips that build step entirely.
Copy link to headingDoes Vercel support self-managed GitLab and Bitbucket Data Center?
Yes. Both are listed as supported products. Each deploys through a CLI pipeline that runs inside your own network and authenticates to Vercel with an access token, rather than through the built-in Git integration. See the self-managed GitLab guide for the short answer.
Copy link to headingCan I deploy to a Vercel custom environment from a pipeline?
Yes, pass --target= with your environment's name on the deploy command, for example vercel deploy --prebuilt --target=staging. Match it with vercel pull --environment=staging so the build receives that environment's variables instead of the preview set. Branch-scoped domains still need the --meta branch details. Custom environments are documented under Environments.
Copy link to headingDo instant rollback and Skew Protection still work with --prebuilt deployments?
Instant rollback works unchanged, because it repoints the domain alias at an existing deployment with no rebuild. Skew Protection works on Next.js projects when you configure a custom deployment ID, which cannot use the dpl_ prefix. Both behave the same as under the Git integration.