GCP Artifact Registry & Poetry Integration Guide
-
Jason Yang - 25 Nov, 2025
- Updated 04 Jan, 2026
- Views —
This guide covers the standard procedures for deploying shared libraries (e.g., shared-libs) to the GCP Artifact Registry and consuming them in other microservices.
🚨 Critical Warning
The most important distinction: The URL format differs for uploading (Publish) and downloading (Install).
- Publish (Upload):
.../python-shared-libs/(Must NOT end with/simple/) - Install (Download):
.../python-shared-libs/simple/(Must END with/simple/)
1. Infrastructure Setup (One-time Setup)
Perform this once per GCP project.
1.1 Create Repository
gcloud artifacts repositories create python-shared-libs \
--repository-format=python \
--location=us-central1 \
--description="Python Shared Libraries" \
--project=[your-project-id]
1.2 Verify Repository
gcloud artifacts repositories list --project=[your-project-id] --location=us-central1
2. Publisher Guide (Library Developer)
Follow these steps when developing and deploying the shared library (shared-libs-fastapi).
2.1 Configure Poetry Repository (Local Config)
Register the target repository in Poetry. Ensure the URL does not end with /simple/.
# Configuration Command
poetry config repositories.gcp-artifact https://us-central1-python.pkg.dev/[your-project-id]/python-shared-libs/
2.2 Build & Publish (Deployment Workflow)
Since auth tokens expire quickly, it is best practice to inject the token directly into the publish command to avoid authentication errors.
# 1. Build the package
poetry build
# 2. Publish with token injection (Non-interactive mode)
poetry publish -r gcp-artifact \
-u oauth2accesstoken \
-p "$(gcloud auth print-access-token)"
3. Consumer Guide (Library User)
Follow these steps in the services that use the library (e.g., user-service).
3.1 Add Source to pyproject.toml
When defining the download source, the URL must end with /simple/ to comply with PEP 503 standards.
# Add source to Poetry
poetry source add --priority=supplemental gcp-artifact https://us-central1-python.pkg.dev/[your-project-id]/python-shared-libs/simple/
Running this command will automatically append the following configuration block to the bottom of your pyproject.toml file.
[[tool.poetry.source]]
name = "gcp-artifact"
url = "https://us-central1-python.pkg.dev/[your-project-id]/python-shared-libs/simple/"
priority = "supplemental"
TIP) “Setting priority = "supplemental" ensures that Poetry searches the official PyPI repository first, querying the GCP repository only if the package is not found. This prevents unnecessary authentication overhead and performance degradation when installing standard open-source packages.
3.2 Install the Library
Refresh the authentication token and add the library.
# 1. Refresh Auth Token (Grant download permission)
poetry config http-basic.gcp-artifact oauth2accesstoken "$(gcloud auth print-access-token)"
# 2. Add Library
poetry add careerscore-shared-libs --source gcp-artifact
The token expiry trap
gcloud auth print-access-token mints a token that lives for about an hour. poetry config http-basic does store the credential, but a stored token is dead within the hour — so you refresh it before each publish or install, overwriting yesterday’s expired one. The failure a stale token produces is a confusing 401 or 403 that looks like a permissions problem when it’s really just expiry. When something that worked an hour ago suddenly can’t authenticate, re-run the token command first.
Authenticating in CI
Personal gcloud tokens are fine locally, but a build pipeline has no human to run them. In CI, authenticate with a service account that has the Artifact Registry Reader role (or Writer, to publish), then feed its short-lived token into the same http-basic config:
poetry config http-basic.gcp-artifact oauth2accesstoken "$(gcloud auth print-access-token)"
The oauth2accesstoken username is the constant here — GCP always expects that literal string, with the actual credential as the “password.” If you’re managing the Python side of these services, the Poetry project setup guide covers the surrounding pyproject.toml structure.