Apps
Apps are containerized applications you deploy and run on the platform. Use this resource to create an app, upload a code bundle, deploy it, control its lifecycle (start/stop/restart), and watch its status, logs, and metrics.
Access it as client.apps on a Strongly client, or the same path on AsyncStrongly with await. All methods exist on both with identical signatures.
Quick start
from strongly import Strongly
client = Strongly()
# List (auto-paginates as you iterate) # filters: status, environment_id, search
for app in client.apps.list():
print(app.id)
Methods
Core
list
list(*, status: str | None = None, environment_id: str | None = None, search: str | None = None, limit: int | None = None) -> SyncPaginator[App]
List apps with pagination and filtering.
Parameters
status(str | None, optional): Filter by app status.environment_id(str | None, optional): Filter by the runtime environment the app runs in.search(str | None, optional): Search by name or description.limit(int | None, optional): Maximum number of items to return (default: all matching items).
create
create(*, name: str, description: str | None = None, display_name: str | None = None, source_volume_id: str | None = None, source_folder: str | None = None, github_repo_url: str | None = None, github_branch: str | None = None, github_ssh_key_id: str | None = None, github_subdirectory: str | None = None, instances: int | None = None, cpu: str | None = None, memory: str | None = None, disk: str | None = None, gpu: str | None = None, gpu_type: str | None = None, use_spot: bool | None = None, spot_fallback: bool | None = None, environment_id: str | None = None, environment_variables: Mapping[str, str] | None = None, addons: Sequence[str] | None = None, data_sources: Sequence[str] | None = None, ai_models: Sequence[str] | None = None, ml_models: Sequence[str] | None = None, workflows: Sequence[str] | None = None, feature_stores: Sequence[str] | None = None, agents: Sequence[str] | None = None, volumes: Sequence[str] | None = None, tags: Sequence[str] | None = None) -> App
Create a new app.
An app has no default size: it runs at exactly the size it is given.
Set environment_id (the app runs at that environment's size), or
cpu and memory (disk optional). deploy refuses an app
with neither and names what is missing.
Parameters
name(str): App name.description(str | None, optional): App description.display_name(str | None, optional): Name shown in the UI.source_volume_id(str | None, optional): Build from a volume's code, as last synced (what a workspace's Sync pushes): the volume's ID.source_folder(str | None, optional): The folder of that volume's code holdingstrongly.manifest.yaml; omit for the whole code.github_repo_url(str | None, optional): Build from a GitHub repository instead: its SSH URL (git@github.com:owner/repo.git). Needsgithub_branchandgithub_ssh_key_id.github_branch(str | None, optional): The branch to build.github_ssh_key_id(str | None, optional): The ID of one of your SSH keys (Profile > Integrations) GitHub accepts for the repository.github_subdirectory(str | None, optional): The repository folder holdingstrongly.manifest.yaml; omit for the root.instances(int | None, optional): Number of replicas.cpu(str | None, optional): CPU cores, e.g."0.5","2"or"500m".memory(str | None, optional): Memory, e.g."1GB"or"512MB".disk(str | None, optional): Disk, e.g."10GB".gpu(str | None, optional): Number of GPUs as a string, e.g."1".gpu_type(str | None, optional): GPU type whengpuis set, e.g."nvidia-t4".use_spot(bool | None, optional):Trueruns the app on spot capacity (cheaper; it can be reclaimed, and the app restarts on a new node).spot_fallback(bool | None, optional): Withuse_spot:True(the API's default) falls back to on-demand capacity when no spot is available;Falsewaits for spot.environment_id(str | None, optional): Runtime environment the app runs in (and at the size of).environment_variables(Mapping[str, str] | None, optional): Environment variables as a name -> value mapping.addons(Sequence[str] | None, optional): Add-on IDs to connect (credentials reach the app throughSTRONGLY_SERVICES).data_sources(Sequence[str] | None, optional): Data source IDs to connect.ai_models(Sequence[str] | None, optional): AI model IDs to connect.ml_models(Sequence[str] | None, optional): Model registry model IDs to connect.workflows(Sequence[str] | None, optional): Deployed workflow IDs the app may trigger.feature_stores(Sequence[str] | None, optional): Feature store IDs the app reads features from.agents(Sequence[str] | None, optional): Deployed agent IDs the app talks to.volumes(Sequence[str] | None, optional): Volume IDs the app mounts: a project's volume you have not shared at/volumes/local/<name>, every shared volume (yours included) at/volumes/shared/<name>;code/read-only,data/read and write, each written file saved as a new version. Needs a disk:disk, or an environment that has one.tags(Sequence[str] | None, optional): Tags.
Returns
App: The newly createdApp.
Raises
ValueError: Both a volume and a GitHub source are given, or a GitHub source without its branch or SSH key.
retrieve
retrieve(app_id: str) -> App
Get a single app by ID.
update
update(app_id: str, *, name: str | None = None, description: str | None = None, display_name: str | None = None, instances: int | None = None, cpu: str | None = None, memory: str | None = None, disk: str | None = None, use_spot: bool | None = None, spot_fallback: bool | None = None, environment_id: str | None = None, environment_variables: Mapping[str, str] | None = None, addons: Sequence[str] | None = None, data_sources: Sequence[str] | None = None, ai_models: Sequence[str] | None = None, ml_models: Sequence[str] | None = None, workflows: Sequence[str] | None = None, feature_stores: Sequence[str] | None = None, agents: Sequence[str] | None = None, volumes: Sequence[str] | None = None, tags: Sequence[str] | None = None, port: int | None = None) -> App
Update an app's definition.
Sizes are checked as given: cpu must be a number of cores and
memory / disk sizes such as "1GB". List arguments replace
the whole set. A change reaches the running app when it is redeployed
(deploy).
delete
delete(app_id: str) -> None
Delete an app.
Lifecycle & actions
start
start(app_id: str) -> App
Start an app; returns the app.
stop
stop(app_id: str) -> App
Stop an app; returns the app.
restart
restart(app_id: str) -> App
Restart an app (a rolling restart of its pods); returns the app.
deploy
deploy(app_id: str, **kwargs) -> App
Deploy an app at exactly its size.
Its environment's size, or the cpu and memory set on it. An app with neither is
refused with a ValidationError naming what is missing; set it with update.
Parameters
app_id(str): The app ID.**kwargs(Any): Optional deployment configuration options.
Returns
App: The app; the deployment has started (pollstatus).
deploy_upload
deploy_upload(app_id: str, file: str | Path | BinaryIO, **kwargs) -> App
Deploy a zip bundle to an existing app.
Parameters
app_id(str): The app ID.file(str | Path | BinaryIO): Path to a zip file, or a file-like object (opened in binary mode).**kwargs(Any): Additional form fields to include.
Returns
App: The app, its new source building.
Examples
result = client.apps.deploy_upload("app-id", "my-app.zip")
Other
add_member
add_member(resource_id: str, *, user_id: str, role: str) -> Permissions
Share the resource with a user.
Parameters
resource_id(str): The resource's id.user_id(str): The user to share it with.role(str):"editor"(use and change it) or"user"(use it only; types without a use-only tier, such as knowledge bases, take"editor"only).
analytics
analytics(app_id: str, *, range: str | None = None) -> dict[str, Any]
Get the app's usage over 7d, 30d or 90d.
analytics_users
analytics_users(app_id: str, *, range: str | None = None, q: str | None = None, sort: str | None = None) -> SyncPaginator[AppUsageUser]
List who used the app over the range: sessions, minutes, requests, last seen.
build_logs
build_logs(app_id: str, *, limit: int | None = None, level: str | None = None) -> dict[str, Any]
Get the image build's log lines, which say why a build failed.
build_status
build_status(app_id: str) -> dict[str, Any]
Get the app's image build: queued, building, completed or failed.
create_with_upload
create_with_upload(file: str | Path | BinaryIO, *, name: str | None = None, description: str | None = None, framework: str | None = None, runtime: str | None = None, **kwargs) -> App
Create a new app by uploading a zip bundle.
Parameters
file(str | Path | BinaryIO): Path to a zip file, or a file-like object (opened in binary mode).name(str | None, optional): App name. Defaults to the filename without extension.description(str | None, optional): App description.framework(str | None, optional): App framework (e.g."express","react").runtime(str | None, optional): App runtime (e.g."node18").**kwargs(Any): Additional form fields to include.
Returns
App: The new app, with its build.
Examples
app = client.apps.create_with_upload(
"my-app.zip",
name="My App",
description="An awesome app",
)
delete_plan
delete_plan(app_id: str, plan_id: str) -> dict[str, Any]
Stop offering a plan; returns the paid access with the plans that remain.
get_user
get_user(app_id: str, user_id: str) -> AppUser
One of the app's users.
list_users
list_users(app_id: str, *, status: str | None = None, q: str | None = None, sort: str | None = None) -> SyncPaginator[AppUser]
List the app's users: status, role and free access.
logs
logs(app_id: str, *, lines: int | None = None, since: str | None = None, container: str | None = None) -> Any
Get app logs.
Parameters
app_id(str): The app ID.lines(int | None, optional): Number of log lines to return.since(str | None, optional): ISO timestamp; return logs after this time.container(str | None, optional): Specific container name.
metrics
metrics(app_id: str) -> dict[str, Any]
Measure a running app now (about 6 seconds).
Returns cpu (usage_millicores, limit_millicores, percent)
and memory (usage_bytes, limit_bytes, percent) against the
app's size summed over replicas, network (receive_bytes_per_second,
transmit_bytes_per_second, total_bytes_per_second,
window_seconds), response_time (avg_ms, min_ms, max_ms,
samples), replicas (ready, total, measured),
containers (every container of every replica with its usage and size,
platform containers marked by role), platform_containers_total
and measured_at. Raises ConflictError (409) when the app is not
running, and an API error with the reason when a measurement fails.
paid_access
paid_access(app_id: str) -> dict[str, Any]
Get the app's paid access: masked Stripe keys, whether it charges, grace days, plans.
permissions
permissions(resource_id: str) -> Permissions
Return who can reach the resource: its owner, members and their roles, and visibility.
Parameters
resource_id(str): The resource's id.
rebuild
rebuild(app_id: str, *, bundle_source_type: str | None = None, bundle_source: Mapping[str, Any] | None = None) -> App
Build a new version of an app from source; the build runs on after this answers.
With no source it rebuilds from where the current version came from (its volume folder or GitHub branch, as it is now).
remove_member
remove_member(resource_id: str, user_id: str) -> None
Stop sharing the resource with a user.
Parameters
resource_id(str): The resource's id.user_id(str): The user to stop sharing it with.
remove_user
remove_user(app_id: str, user_id: str) -> None
Remove a user from the app; their platform account is kept.
reset_user_password
reset_user_password(app_id: str, user_id: str) -> AppUser
Email a user a password reset link to the app's branded page; returns the user.
set_env
set_env(app_id: str, environment_variables: Mapping[str, str]) -> App
Replace the app's environment variables (they apply on its next start).
set_plan
set_plan(app_id: str, plan_id: str, **plan) -> dict[str, Any]
Create or replace a plan.
Plan: name, description, kind (individual or team),
stripe_price_id, min_seats, trial_days. Returns the paid access.
set_visibility
set_visibility(resource_id: str, visibility: str) -> Permissions
Make the resource public (every user can find and use it) or private.
Parameters
resource_id(str): The resource's id.visibility(str):"public"or"private".
status
status(app_id: str) -> AppStatus
Get app deployment status.
subscriptions
subscriptions(app_id: str, *, status: str | None = None, q: str | None = None, sort: str | None = None) -> SyncPaginator[AppSubscription]
List the app's subscriptions: payer, plan, seats and status.
update_auth
update_auth(app_id: str, **settings) -> dict[str, Any]
Change the app's branded sign-in.
Settings: enabled, slug, signup_enabled, access (instant or
approval), allowed_domains and logo. Returns {app_id, auth}.
update_paid_access
update_paid_access(app_id: str, *, stripe_secret_key: str | None = None, stripe_webhook_secret: str | None = None, enabled: bool | None = None, grace_days: int | None = None) -> dict[str, Any]
Set up or change paid access with the owner's own Stripe account.
update_user
update_user(app_id: str, user_id: str, *, active: bool | None = None, free_access: bool | None = None) -> AppUser
Let a user sign in (or not), or let them use a paid app without a plan.