Migrate Python content off Connect
This guide walks through moving a deployed Python content item out of Posit Connect and running it somewhere else, with the same package versions Connect used. This is useful when content must be retired from a Connect server, archived so it can be restored later, or handed to a team that does not use Connect.
The workflow combines two rsconnect-python commands: rsconnect content download-bundle recovers the source code, and rsconnect content venv recreates the Python environment.
Prerequisites
Before you begin, you must have:
- Posit Connect 2025.12.0 or later
rsconnect-python1.29.0 or later- uv available on your
PATH - Owner or Collaborator access to the content item
- An API key for your Connect server
Administrator access alone is not enough. Administrators who are not collaborators on a content item can read its package list, but cannot download its bundle. Add yourself as a collaborator first.
Export your server address and API key so that each command below can find them:
Terminal
export CONNECT_SERVER=https://connect.example.com
export CONNECT_API_KEY=<your-api-key>Background
Connect holds two separate pieces of a deployed Python project:
- The source bundle: the files the publisher uploaded, plus the
manifest.jsondescribing how the content is run. See Content Bundles. - The lockfile: the exact set of Python packages Connect installed to run the active bundle.
Both are needed. A project’s requirements.txt often lists unpinned dependencies, such as streamlit rather than streamlit==1.46.0, so reinstalling from it can produce a different environment than the one Connect built. The lockfile records the resolved versions of every direct and transitive dependency, along with the Python version Connect actually used.
Step 1: Find the content GUID
Every command in this workflow identifies content by GUID. Find it in the content’s URL in the Connect dashboard, in the content Settings pane under General > Information > GUID, or search for the content by title:
Terminal
rsconnect content search --title-contains "Quarterly report"Step 2: Download the source bundle
Download the active bundle and unpack it:
Terminal
rsconnect content download-bundle \
--guid <GUID> \
--output bundle.tar.gz
mkdir project && tar -xzf bundle.tar.gz -C project && cd projectStep 3: Recreate the Python environment
From the unpacked bundle directory, create a virtual environment from the content’s lockfile:
Terminal
rsconnect content venv .venv --guid <GUID>This downloads the lockfile, then uses uv to create .venv with the Python version Connect used and install the exact packages Connect installed. If that Python version is not present on your machine, uv downloads it, so you can recreate an environment for a Python version your system no longer provides.
Activate the environment:
Terminal
source .venv/bin/activateAlways pass --guid. Without it, rsconnect content venv looks for local deployment metadata that only exists in a directory you have deployed from, and an unpacked bundle does not contain it.
The environment holds the packages from the lockfile and nothing else, which includes no pip. Use uv pip install to add anything else you need.
Step 4: Run the content
Start the content with the tool matching its content type. The app_mode field reports which framework Connect ran it with:
Terminal
rsconnect content describe --guid <GUID>app_mode |
Command |
|---|---|
python-shiny |
shiny run app.py |
python-streamlit |
streamlit run main.py |
python-fastapi |
uvicorn app:app |
jupyter-voila |
voila report.ipynb |
The argument is the content’s entrypoint, in the form that framework expects: an application file such as app.py or report.ipynb, or a module:object pair for APIs. When it is not obvious, the bundle’s manifest.json records the entrypoint; see entrypoint in the Manifests section. Shiny Express content records an internal module path there; run its application file instead.
For other Python content types, app_mode tells you which framework Connect launched; consult that framework’s documentation for its local run command.
Limitations
Python content only. The lockfile describes Python environments, so R content and static content report:
Content does not have a managed Python environment
Environment management must be enabled. Content that Connect does not build a Python environment for, because Python.EnvironmentManagement is disabled for the server or for the content, reports the same error. See Python package management.
The Python patch version may differ. Connect records the full version it ran, but only the major and minor version are requested when building the environment, so the patch release is whichever uv resolves. Content that Connect ran on Python 3.8.1 gets an environment on Python 3.8.20.
Environment variable values stay on Connect. The names of a content item’s variables are readable from GET /__api__/v1/content/<GUID>/environment, but the values never leave the server, so every secret, token, and password must be set again by hand. See Setting environment variables.
The package index must be reachable. The first line of the lockfile records the index Connect installed from. If that is an internal mirror, the commands must run somewhere that can reach it, or you must install the packages from another index yourself.
Rendered reports need their renderer. A notebook or Quarto document runs inside the recreated environment, but the renderer, such as Quarto, is a separate installation on the target machine.
Fetch only the lockfile
If you cannot use uv, download the lockfile and install it with the tool of your choice:
Terminal
rsconnect content get-lockfile \
--guid <GUID> \
--output requirements.txt.lock
pip install -r requirements.txt.lockWith this approach you are responsible for creating the environment with the correct Python version. The py_version field reports the version Connect used:
Terminal
rsconnect content describe --guid <GUID>