> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/astral-sh/uv/llms.txt
> Use this file to discover all available pages before exploring further.

# GitLab CI/CD Integration

> Use uv in GitLab CI/CD pipelines with Docker images and caching

Integrate uv into your GitLab CI/CD pipelines for efficient Python dependency management.

## Using uv Docker Images

<Steps>
  <Step title="Select a base image">
    Use one of the official uv Docker images. You can choose from distroless, Alpine, or Debian-based images:

    ```yaml theme={null}
    variables:
      UV_VERSION: "0.10.8"
      PYTHON_VERSION: "3.12"
      BASE_LAYER: trixie-slim
      # GitLab CI creates separate mountpoints, use copy mode
      UV_LINK_MODE: copy

    test:
      image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
      script:
        - uv sync --locked
        - uv run pytest
    ```
  </Step>

  <Step title="For distroless images">
    When using distroless images, specify the entrypoint:

    ```yaml theme={null}
    test:
      image:
        name: ghcr.io/astral-sh/uv:0.10.8
        entrypoint: [""]
      script:
        - uv --version
    ```
  </Step>
</Steps>

## Pipeline Configuration

Here's a complete example pipeline:

```yaml theme={null}
variables:
  UV_VERSION: "0.10.8"
  PYTHON_VERSION: "3.12"
  BASE_LAYER: trixie-slim
  UV_LINK_MODE: copy

stages:
  - lint
  - test
  - build

lint:
  image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
  script:
    - uv sync --locked
    - uv run ruff check .

test:
  image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
  script:
    - uv sync --locked --all-extras
    - uv run pytest tests --cov
  coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'

build:
  image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-$BASE_LAYER
  script:
    - uv build
  artifacts:
    paths:
      - dist/
```

## Caching Dependencies

Persist the uv cache between pipeline runs to improve performance:

```yaml theme={null}
variables:
  UV_CACHE_DIR: .uv-cache
  UV_LINK_MODE: copy

test:
  image: ghcr.io/astral-sh/uv:0.10.8-python3.12-trixie-slim
  cache:
    - key:
        files:
          - uv.lock
      paths:
        - $UV_CACHE_DIR
  script:
    - uv sync --locked
    - uv run pytest
  after_script:
    - uv cache prune --ci
```

<Note>
  Use `uv cache prune --ci` to reduce cache size. See the [cache documentation](https://docs.astral.sh/uv/concepts/cache/) for more details.
</Note>

### Advanced Caching

Cache based on both lockfile and Python version:

```yaml theme={null}
variables:
  UV_CACHE_DIR: .uv-cache

test:
  cache:
    - key:
        files:
          - uv.lock
        prefix: $PYTHON_VERSION
      paths:
        - $UV_CACHE_DIR
  parallel:
    matrix:
      - PYTHON_VERSION: ["3.10", "3.11", "3.12"]
  image: ghcr.io/astral-sh/uv:0.10.8-python$PYTHON_VERSION-trixie-slim
  script:
    - uv sync --locked
    - uv run pytest
  after_script:
    - uv cache prune --ci
```

## Matrix Testing

Test across multiple Python versions:

```yaml theme={null}
test:
  parallel:
    matrix:
      - PYTHON_VERSION: ["3.10", "3.11", "3.12"]
        BASE: ["trixie-slim", "alpine"]
  image: ghcr.io/astral-sh/uv:0.10.8-python$PYTHON_VERSION-$BASE
  script:
    - uv sync --locked
    - uv run pytest tests
```

## Using uv pip

For workflows using the `uv pip` interface, enable system Python:

```yaml theme={null}
variables:
  UV_SYSTEM_PYTHON: 1

test:
  image: ghcr.io/astral-sh/uv:0.10.8-python3.12-trixie-slim
  script:
    - uv pip install -r requirements.txt
    - python -m pytest
```

<Note>
  When using `uv pip`, consider using `requirements.txt` or `pyproject.toml` instead of `uv.lock` in your cache key.
</Note>

## Installing uv in Custom Images

If you need to use a custom base image:

```yaml theme={null}
test:
  image: python:3.12-slim
  before_script:
    # Copy uv from official image
    - apt-get update && apt-get install -y curl
    - curl -LsSf https://astral.sh/uv/0.10.8/install.sh | sh
    - export PATH="/root/.local/bin:$PATH"
  script:
    - uv sync --locked
    - uv run pytest
```

## Complete Example with Multiple Stages

```yaml theme={null}
variables:
  UV_VERSION: "0.10.8"
  PYTHON_VERSION: "3.12"
  UV_CACHE_DIR: .uv-cache
  UV_LINK_MODE: copy

stages:
  - check
  - test
  - build
  - deploy

.base:
  image: ghcr.io/astral-sh/uv:$UV_VERSION-python$PYTHON_VERSION-trixie-slim
  cache:
    - key:
        files:
          - uv.lock
      paths:
        - $UV_CACHE_DIR
  before_script:
    - uv sync --locked

format:
  extends: .base
  stage: check
  script:
    - uv run ruff format --check .

lint:
  extends: .base
  stage: check
  script:
    - uv run ruff check .

type-check:
  extends: .base
  stage: check
  script:
    - uv run mypy .

test:
  extends: .base
  stage: test
  parallel:
    matrix:
      - PYTHON_VERSION: ["3.10", "3.11", "3.12"]
  script:
    - uv run pytest tests --cov --cov-report=xml
  coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml
  after_script:
    - uv cache prune --ci

build:
  extends: .base
  stage: build
  script:
    - uv build
  artifacts:
    paths:
      - dist/
    expire_in: 1 week
  only:
    - tags

publish:
  extends: .base
  stage: deploy
  script:
    - uv publish --token $PYPI_TOKEN
  only:
    - tags
  when: manual
```

## Best Practices

* **Pin versions**: Always specify exact versions for `UV_VERSION` and `PYTHON_VERSION`
* **Use cache**: Enable caching to speed up pipeline runs
* **Set UV\_LINK\_MODE**: Use `copy` mode since GitLab creates separate mountpoints
* **Prune cache**: Run `uv cache prune --ci` in `after_script` to optimize cache size
* **Cache key**: Use `uv.lock` as the cache key for projects, `requirements.txt` for pip workflows
