> For the complete documentation index, see llms.txt.
Skip to main content

Check out Port for yourself ➜ 

Migration guide to the v2 integration

This guide walks through the process of migrating from Port's GitLab integration to the new GitLab-v2 integration.

For installation methods, live events, and where to paste YAML in Port, use the setup and configuration sections on the GitLab v2 integration page.

Overview

GitLab-v2 introduces significant authentication and performance improvements:

  • Simplified authentication: Replace multiple group tokens with a single service account token.
  • Enhanced performance: Faster resync with improved API efficiency.
  • Typed configuration: First-class selectors for kinds such as merge-request, member, group-with-members, project-with-members, tag, release, and branch.
  • Native search and file selectors: Use searchQueries and includedFiles on project instead of the deprecated file:// and search:// mapping prefixes. For how those selectors work in mappings, see Enrich entities with file contents and Enrich entities with search queries on the capabilities page.

Changes

Authentication model

GitLab approach: Multiple group access tokens mapped to specific paths

integration:
secrets:
tokenMapping: |
{"glpat-token1": ["**/Group1/**"], "glpat-token2": ["**/Group2/**"]}

GitLab-v2 approach: Single service account token with broad access

integration:
config:
gitlabToken: "glpat-service-account-token"
Parameter naming

The GitLab-v2 integration uses gitlabToken (not token). When using the hosted UI or Helm installer, use the parameter name exactly as it appears in the integration spec. Parameter reference and install flows live under setup on the GitLab v2 integration page.

Blueprint mapping changes

The blueprints used in GitLab-v2 have evolved to provide cleaner data structures and better relationships between entities. Understanding these changes is essential for a successful migration.

Fields that Port adds on top of the GitLab API payload use a double underscore prefix (for example .__languages and .__includedFiles), similar to other Ocean integrations. For feature-level behavior beyond this migration page, see the capabilities page.

In the YAML below, identifier, title, and blueprint are standard Port entity mapping fields (they are not GitLab integration switches):

  • identifier: stable unique key for the entity in your catalog (often derived from GitLab IDs or paths).
  • title: human-readable label shown in the UI.
  • blueprint: slug of the Port blueprint that defines the entity's schema and relations.

Those three lines stay the same when you already map GitLab projects or MRs into the same blueprints as before. What changes in each subsection are selectors (what GitLab sends into the integration) and properties (what you store on the entity).

Kind mapping changes by resource type

1. project kind (Required update)

GitLab configuration:

- kind: project
selector:
query: "true"
includeLabels: "true" # ❌ Remove: No longer supported
port:
entity:
mappings:
identifier: .path_with_namespace | gsub(" "; "")
title: .name
blueprint: '"service"'
properties:
language: .__languages | to_entries | max_by(.value) | .key
labels: .__labels # ❌ Remove: project labels not enriched in v2

GitLab-v2 configuration:

- kind: project
selector:
query: "true"
includeLanguages: "true" # ✅ Add: New selector for language detection
port:
entity:
mappings:
identifier: .path_with_namespace | gsub(" "; "")
title: .name
blueprint: '"service"'
properties:
language: .__languages | to_entries | max_by(.value) | .key
Why project labels went away

GitLab-v2 does not offer includeLabels or a project-level .__labels field. The v1 integration optionally fetched extra project label data into the payload. That enrichment path was removed to simplify the project sync and reduce API surface. Issues, merge requests, and other kinds can still expose labels where the underlying GitLab object includes them (see the issue example later on this page). If your scorecards or queries depended on project labels, move that signal to a supported surface, for example MR/issue labels, includedFiles, or searchQueries on project.

2. merge-request kind (Configuration update)

GitLab configuration:

- kind: merge-request
port:
entity:
mappings:
identifier: .id | tostring
title: .title
blueprint: '"gitlabMergeRequest"'

GitLab-v2 configuration:

- kind: merge-request
selector:
query: "true"
states: ["opened", "merged"] # ✅ Add: control which MR states are synced
updatedAfter: 90 # ✅ Add: only applies when querying non-open states (days)
port:
entity:
mappings:
identifier: .id | tostring
title: .title
blueprint: '"gitlabMergeRequest"'
properties:
creator: .author.name
reviewers: .reviewers | map(.name)
Merge request parity

The default merge-request behavior is not equivalent between v1 and v2:

  • v1 fetched all opened MRs and closed MRs from roughly the last 14 days.
  • v2 defaults to states: ["opened"] only. The updatedAfter value (default 90 days) is applied only when you also include non-open states (merged, closed, locked).

To preserve v1's catalog coverage, explicitly set states to include merged and/or closed and tune updatedAfter to your retention needs.

Both v1 and v2 support project-with-members and group-with-members. The recommended modeling in v2, however, is to use a dedicated member kind and reference it via relations, rather than embedding members as properties on projects and groups.

In the selectors below, includeVerboseMemberObject only changed how verbose each member object was in the raw payload. GitLab-v2 uses a single standardized member shape, so that toggle is gone. It has nothing to do with blueprint (which only selects which Port blueprint receives the entity).

GitLab approach - Members as embedded properties:

- kind: project-with-members
selector:
query: 'true'
includeInheritedMembers: false
includeBotMembers: false
includeVerboseMemberObject: false # ❌ Remove: not supported in v2
port:
entity:
mappings:
identifier: .path_with_namespace | gsub(" "; "")
title: .name
blueprint: '"service"'
properties:
members: .__members # Members embedded as properties

- kind: group-with-members
selector:
query: 'true'
includeInheritedMembers: false
includeBotMembers: false
includeVerboseMemberObject: false # ❌ Remove: not supported in v2
port:
entity:
mappings:
identifier: .full_path
title: .name
blueprint: '"gitlabGroup"'
properties:
members: .__members # Members embedded as properties

GitLab-v2 recommended approach - Members as separate entities with relations:

# ✅ New: Dedicated member entities
- kind: member
selector:
query: 'true'
includeBotMembers: false
port:
entity:
mappings:
identifier: .username
title: .name
blueprint: '"gitlabMember"'
properties:
url: .web_url
state: .state
email: .email
locked: .locked

# ✅ Updated: Groups with member relations (not embedded properties)
- kind: group-with-members
selector:
query: 'true'
includeBotMembers: false
port:
entity:
mappings:
identifier: .full_path
title: .name
blueprint: '"gitlabGroup"'
properties:
url: .web_url
visibility: .visibility
description: .description
relations:
gitlabMembers: .__members | map(.username) # ✅ Relations, not properties
4. file kind (Search API and repository format changes)

For file resync, GitLab-v2 now uses GitLab's Advanced Search API with its specific syntax and limitations:

GitLab format:

- kind: file
selector:
files:
path: '**/package.json' # ❌ Custom glob patterns
repos:
- "backend-service" # ❌ Simple repository name
- "frontend-app"

GitLab-v2 format:

- kind: file
selector:
files:
path: 'package.json' # ✅ GitLab Advanced Search syntax (https://docs.gitlab.com/user/search/advanced_search/#use-advanced-search)
repos:
- "my-org/backend-service" # ✅ Full namespace/project path
- "my-org/frontend-app"
skipParsing: false # ✅ New option to skip parsing and return raw content
Path search limitations

GitLab-v2's path parameter uses GitLab's Advanced Search syntax, which differs from v1's glob patterns. The search supports simple * wildcards for filename patterns like *.tf, package.json, and test_*, as well as exact file paths like src/app/main.py and infra/terraform/main.tf.

The search doesn't support path wildcards like infra/terraform/*.tf ❌, recursive patterns like **/filename ❌, or complex patterns like *.{js,ts}, [abc]*, and !exclude ❌.

When migrating complex v1 patterns, you can split them into multiple file kinds or specify exact paths for targeted files. See the Migration Pattern Comparison table below for specific examples.

5. folder kind (Repository selector changes)

For folder resync, GitLab-v2 changes the repository specification format to support branch-specific folder mapping:

GitLab format:

- kind: folder
selector:
folders:
- path: "src"
repos:
- "backend-service" # ❌ Simple repository name
- "frontend-app"
branch: "main" # ❌ Single branch for all repos

GitLab-v2 format:

- kind: folder
selector:
folders:
- path: "src"
repos:
- name: "my-org/backend-service" # ✅ Full namespace/project path
branch: "main" # ✅ Branch specified per repository
- name: "my-org/frontend-app"
branch: "develop" # ✅ Different branches per repository
6. First-class kinds with typed selectors in GitLab-v2

pipeline, job, and issue were already syncable in v1 through the integration's resync logic, but v2 promotes them (along with group, tag, release, and branch) to first-class kinds with typed selectors in port-app-config.yml. This means cleaner configuration, validation, and consistent defaults rather than hardcoded behavior.

pipeline kind:

- kind: pipeline
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id | tostring
title: .name
blueprint: '"gitlabPipeline"'

job kind:

- kind: job
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id | tostring
title: .name
blueprint: '"gitlabJob"'
properties:
status: .status
stage: .stage
duration: .duration

issue kind:

- kind: issue
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id | tostring
title: .title
blueprint: '"gitlabIssue"'
properties:
creator: .author.name
status: .state
labels: "[.labels[]]"
relations:
project: .references.full | gsub("#.+"; "")
7. Additional first-class kinds: group, tag, release, branch

GitLab-v2's GitlabPortAppConfig exposes typed selectors for group, tag, release, and branch. If you tracked any of these in v1 via custom mappings, you can now use the dedicated kinds for cleaner configuration. See the GitLab v2 examples for usage, and Ingest files from your repositories when you rely on the file kind.

8. Visibility and minimum access level filters

GitLab-v2 introduces a top-level visibility configuration on the integration's app config to limit which projects and groups are synced based on the requesting user's access level:

visibility:
useMinAccessLevel: true
minAccessLevel: 30 # Developer

Use this to scope ingestion to projects/groups where the service account has at least a chosen access level.

9. Replacing file:// and search:// mapping prefixes

Both v1 and v2 deprecate the file:// and search:// prefixes inside Port mappings. v2 provides first-class selectors on the project kind to replace them:

  • includedFiles: declaratively pull file contents into project entities (replaces file:// lookups in mappings).
  • searchQueries: declaratively run GitLab Advanced Search queries (replaces search:// lookups).

Example:

- kind: project
selector:
query: "true"
includedFiles:
- path: "package.json"
repos:
- "my-org/backend-service"
searchQueries:
- name: "todos"
query: "TODO"

When you migrate, replace any remaining file:// or search:// references in your mappings with these selectors. Read Enrich entities with file contents and Enrich entities with search queries for concrete YAML patterns.

Configuration selector changes

GitLab-v2 introduces new selector options while removing some GitLab-specific configurations that are no longer needed.

Removed selectors

The following selectors from GitLab are no longer available in GitLab-v2:

  • includeLabels: optional v1 enrichment that pulled GitLab project labels into .__labels for mapping. GitLab-v2 drops this path entirely (see the Why project labels went away callout under project kind on this page). Use includeLanguages when you want primary language on project entities instead.
  • includeVerboseMemberObject: v1-only switch for the shape of member objects on member-related kinds. GitLab-v2 always uses one canonical member shape, so the flag was removed.

New selectors in GitLab-v2

GitLab-v2 introduces several new selector options that provide better control over data resync:

  • includeLanguages: Enables language detection and inclusion in project entities. When set to true, the integration will analyze repository languages and include the primary language in the project properties
  • states: Available for merge requests, allows you to specify which merge request states to resync (opened, closed, merged)
  • updatedAfter: For merge requests, helps limit resync to recently updated merge requests by specifying the number of days to look back

File and folder mapping updates

The way you specify repositories for file and folder resync has changed significantly between versions.

Repository SpecificationGitLab FormatGitLab-v2 Format
File repos"backend-service""my-org/backend-service"
Folder repos"frontend-app""my-org/frontend-app"

The namespace path format follows GitLab's standard group/project or group/subgroup/project structure, ensuring accurate repository identification even when multiple projects share the same name across different groups.

Short repo names on file and folder kinds

For file and folder selectors (and similar searches scoped by repo list), treat path_with_namespace style paths as required in GitLab-v2. Short names such as "backend-service" were tied to how the legacy integration resolved repos and do not behave as reliable aliases in v2. Keeping the old strings usually breaks ingestion or targets the wrong GitLab project once you have more than one project with the same name under different groups. This change applies to file/folder configuration specifically, not to fields such as identifier that still use .path_with_namespace from the project object.

Summary of key changes

The following table summarizes all the major differences between GitLab and GitLab-v2 to help you prepare for migration:

Kind/FeatureGitLabGitLab-v2Action Required
AuthenticationtokenMapping (multi-token, path-scoped)Single gitlabTokenReplace token mapping with a single service account token
project kindincludeLabels selectorincludeLanguages selectorReplace includeLabels: true with includeLanguages: true
merge-request kindDefaults to opened + ~14 days of closed MRsDefaults to opened only; updatedAfter (default 90d) only applies for non-open statesAdd non-open states explicitly and tune updatedAfter to match v1 coverage
Member handlingproject-with-members + group-with-members (embedded)Recommended: dedicated member kind with relationsOptional: introduce member kind and switch groups/projects to relations
includeVerboseMemberObject✅ Supported❌ RemovedRemove from member/project/group selectors
file kindCustom glob patterns + simple repo namesGitLab Advanced Search syntax + full namespace paths + skipParsing optionUpdate to GitLab search syntax, update repo names to org/repo format
folder kindSimple repo names + single branchRepository objects with name/branch pairsUpdate repos to objects with name and branch properties
file:// / search:// prefixesDeprecatedReplaced by includedFiles and searchQueries on projectMigrate mapping prefixes to selectors
pipeline / job / issueAvailable via integration resyncPromoted to first-class kinds with typed selectorsUse the typed selectors in port-app-config.yml
group / tag / release / branchCustom mappingsFirst-class kinds with typed selectorsOptional: switch to dedicated kinds

Migration steps

Step 1: Create a GitLab service account

Choose the appropriate setup method for your GitLab instance:

For GitLab.com (SaaS):

  1. Navigate to your top-level group settings
  2. Go to Access Tokens under the group settings
  3. Create a Group Service Account

For GitLab self-managed:

  1. Create a new user account (e.g., port-integration-bot)
  2. Add this user to all relevant groups with Developer permissions or higher

Step 2: Generate the access token

  1. Sign in to your service account
  2. Navigate to User Settings > Access Tokens
  3. Create a new personal access token with:
    • Name: Port Integration Token
    • Scopes: api (or read_api + read_repository for read-only)
    • Expiration: Set according to your security policy
  4. Save the generated token securely
Token permissions

The service account needs access to all groups and projects you want to sync. For webhook functionality, it also needs permission to create webhooks.

Step 3: Update your integration configuration

Replace your current token mapping configuration with the new single token approach. This step eliminates the complexity of managing multiple tokens while ensuring the service account has appropriate access across your GitLab instance. When you are ready to paste the full mapping into Port, use the YAML editor described under configuration on the GitLab v2 integration page.

Before: GitLab configuration with token mapping (click to expand)
integration:
secrets:
tokenMapping: |
{
"glpat-old-token-1": ["**/DevTeam/**", "**/BackendServices/**"],
"glpat-old-token-2": ["**/FrontendApps/**"]
}
After: GitLab-v2 configuration with single token (click to expand)
integration:
config:
gitlabToken: "glpat-your-new-service-account-token"

When your mapping lives in a repository

If you keep the integration mapping in a repository (for example port-app-config.yml), you will need short-lived edits in the Port UI while you validate selector changes. For each pass, copy only the relevant resources blocks into the mapping in Port, run the steps below, then copy the final YAML back to the repository. The configuration section on the GitLab v2 integration page explains how the mapping is stored and synced.

Step 4: Update resource selectors and blueprints

Review your mapping configuration for deprecated selectors and blueprint references. Cross-check the examples under Blueprint mapping changes and the Summary of key changes table before you deploy.

Update each kind mapping specifically:

  1. For project kinds:

    • Remove includeLabels: true from selectors
    • Add includeLanguages: true to selectors
    • Remove labels: .__labels from property mappings
  2. For merge-request kinds:

    • To preserve v1's coverage of closed MRs, add states such as states: ["opened", "merged", "closed"]. Without this, v2 syncs opened only.
    • Tune updatedAfter (in days, default 90) to bound how far back closed/merged MRs are fetched. v1's behavior was roughly a 14-day window.
    • Simplify reviewer mappings to reviewers: .reviewers | map(.name).
  3. For member handling (recommended modeling change):

    • Optional: introduce a dedicated member kind and switch groups/projects to use relations instead of embedded properties.
    • You can keep project-with-members and group-with-members if you prefer to migrate without changing your modeling, both are still supported in v2.
    • Remove the deprecated includeVerboseMemberObject selector. includeInheritedMembers and includeBotMembers remain supported.
  4. For file kinds:

    • Update file paths to use GitLab Advanced Search syntax (change '**/package.json' to '*package.json')
    • Update all repo specifications from "repo-name" to "org/repo-name" format
    • Optionally add skipParsing: false to selector if you want to control content parsing
  5. For folder kinds:

    • Update all repo specifications from simple strings to objects with name and branch properties
    • Change from repos: ["repo-name"] to repos: [{"name": "org/repo-name", "branch": "main"}]
    • Take advantage of per-repository branch specification for more flexible folder mapping
  6. Adopt first-class kinds where helpful:

    • Use the typed pipeline, job, and issue kinds for CI/CD and issue tracking.
    • Use the typed group, tag, release, and branch kinds if you previously approximated these with custom mappings.
    • Replace any remaining file:// and search:// mapping prefixes with includedFiles and searchQueries selectors on the project kind.

Step 5: Update file and folder mappings

Update any file or folder mappings to use GitLab's Advanced Search API syntax and repository formats required by GitLab-v2. For selector semantics and limitations, see Ingest files from your repositories on the capabilities page.

  1. Update file paths to GitLab Advanced Search syntax:

    • Change path: '**/package.json' to path: 'package.json'
    • Change path: '**/*.yml' to path: '*.yml'
    • GitLab-v2 uses GitLab's Advanced Search API which supports * wildcards but follows GitLab's search syntax
  2. Update repository specifications:

    • Change repository names to include the full group path
    • Review all repos specifications in your file and folder kinds
  3. Test the updated configuration with a small subset first

Example file kind transformation:

# GitLab format
- kind: file
selector:
files:
path: '**/package.json' # ❌ Custom glob pattern
repos:
- "backend-service" # ❌ Simple name

# GitLab-v2 format
- kind: file
selector:
files:
path: '*package.json' # ✅ GitLab Advanced Search syntax
repos:
- "my-org/backend-service" # ✅ Full namespace
skipParsing: false # ✅ Optional parsing control

Example folder kind transformation:

# GitLab format
- kind: folder
selector:
folders:
- path: "src"
repos:
- "backend-service" # ❌ Simple name
branch: "main" # ❌ Single branch for all repos

# GitLab-v2 format
- kind: folder
selector:
folders:
- path: "src"
repos:
- name: "my-org/backend-service" # ✅ Full namespace with branch object
branch: "main"
- name: "my-org/frontend-app" # ✅ Different branches per repo
branch: "develop"

Migration Pattern Comparison

V1 PatternV2 PatternWhat it matchesMigration Notes
**/infra/**/terraform/*.{tf,tfvars}*.tf + *.tfvarsTerraform files anywhereSplit into multiple file kinds
**/infra/**/terraform/*.{tf,tfvars}infra/prod/terraform/main.tf + infra/staging/terraform/main.tfTerraform files in specific pathsSplit into multiple file kinds with exact paths
**/package.jsonpackage.jsonFiles named "package.json" anywhereSearches entire repository
**/DockerfileDockerfileAll Dockerfiles anywhereSearches entire repository
**/docker-compose.ymldocker-compose.ymlDocker Compose files anywhereSearches entire repository
GitLab Advanced Search capabilities

GitLab-v2 follows GitLab's Advanced Search syntax which supports:

  • * for partial matches (e.g., *package.json or *.yml)
  • filename: prefix for filename searches
  • Other advanced search operators

See GitLab's documentation for the complete list of supported search patterns and limitations.

This change ensures accurate repository identification and prevents conflicts when multiple repositories share the same name across different GitLab groups.

Step 6: Deploy and verify

  1. Deploy the GitLab-v2 integration with your updated configuration (follow setup on the GitLab v2 integration page for hosted, self-hosted, or CI installs)
  2. Trigger a manual resync from Port's UI to initiate data resync
  3. Verify data consistency:
    • Check that all expected projects are resynced
    • Confirm merge requests and issues are updating correctly
    • Test webhook functionality if enabled
  4. Monitor the logs for any authentication or permission issues
Parallel testing

Consider running both GitLab and GitLab-v2 integrations temporarily to compare results before fully switching over.

Step 7: Clean up GitLab integration

Once GitLab-v2 is working correctly:

  1. Disable the GitLab integration
  2. Revoke the old group access tokens
  3. Remove GitLab configuration files
  4. Update any documentation referencing the old setup

This cleanup ensures security by removing unused tokens and prevents confusion from having multiple configurations.

Webhooks and self-managed differences

The GitLab and GitLab-v2 integrations expose different knobs for live events. Self-hosted installs should align base_url / networking with the guidance in setup so GitLab can reach the integration for webhook delivery:

  • GitLab (v1) exposed configuration like appHost, useSystemHook, and tokenGroupHooksOverrideMapping to control where and how webhooks were registered.
  • GitLab-v2 registers group webhooks automatically when the integration is configured with a reachable base_url and a token that can create webhooks. On Port's hosted (SaaS) deployment, live events are enabled by default (liveEvents.enabled: true in the integration spec).

For self-managed setups, ensure that:

  • The integration is reachable from your GitLab instance at a stable URL (the equivalent of v1's appHost).
  • The service account token has permission to create and manage group webhooks for the groups you want to sync.

GitOps

The v1 integration declared a gitops feature in its spec; the v2 integration spec lists the exporter feature only. If you rely on GitOps workflows (committing entity manifests to GitLab and having Port sync them), read the GitLab v2 GitOps guide and the GitOps section on the GitLab v2 integration page before fully decommissioning v1.

New features in GitLab-v2

Pipeline jobs support

GitLab-v2 introduces comprehensive pipeline job tracking, allowing you to monitor CI/CD job status, stages, and duration. This feature provides detailed insight into your build and deployment processes.

- kind: job
selector:
query: 'true'
port:
entity:
mappings:
identifier: .id | tostring
title: .name
blueprint: '"gitlabJob"'
properties:
status: .status
stage: .stage
duration: .duration

Enhanced group management

Groups in GitLab-v2 provide cleaner member resync and better hierarchy handling. The separation of member and group concerns allows for more flexible data modeling and improved relationship management between users, groups, and projects.

Troubleshoot common issues

For integration health checks and common setup errors, also see Troubleshooting on the GitLab v2 integration page.

IssueCauseSolution
Authentication errorsService account lacks access to required groupsVerify service account has been added to all relevant groups with appropriate permissions
Missing repositoriesIncorrect namespace formatting in GitLab-v2Ensure repository paths use the full namespace/project format
Missing member dataMember selectors not aligned with v2 (e.g. relying on removed includeVerboseMemberObject)Remove unsupported selectors. Either keep project-with-members / group-with-members, or switch to the dedicated member kind with relations.
Member relation errorsMembers modeled as embedded properties when relations were expectedUpdate group-with-members (or project-with-members) to use relations to a member blueprint instead of embedded member properties
Missing closed/merged MRs after migrationv2 default states: ["opened"] and updatedAfter windowSet states to include merged / closed and tune updatedAfter to your retention needs
Webhook failuresService account lacks webhook creation permissionsCheck that service account has sufficient privileges to create and manage webhooks
File sync issuesIncorrect search syntaxUpdate file paths to use GitLab Advanced Search syntax (e.g., *package.json instead of **/package.json)
Repository not found errorsOutdated repository names in file/folder selectorsUpdate repo names to use full namespace format (org/repo)

If you encounter issues during migration:

  1. Check the integration logs in Port's UI for specific error messages
  2. Verify your service account permissions in GitLab to ensure proper access
  3. Contact Port support with your specific error messages and configuration details

This migration ensures your GitLab integration benefits from improved security through centralized token management, enhanced performance with optimized API calls, and new capabilities including pipeline job tracking while maintaining all your existing data resync patterns.