Skip to content

Build A Cloud App

What Are Cloud Apps?

Cloud apps are server-side applications that run on your own infrastructure (for example, a VM, or a cloud server) and connect to the PhyStack platform remotely. Unlike screen and edge apps that run on PhyOS devices, cloud apps run wherever you deploy them and communicate with PhyStack through a persistent Phyhub connection.

Cloud apps are managed through the same platform as other app types:

  • Published and versioned via your PhyStack tenant
  • Deployed and configured using the Console
  • Integrated with platform features, including:
    • Settings schemas
    • Centralized configuration and content management
    • Real-time event collection via Signals

Common Use Cases for Cloud Apps

Cloud apps run as services in the cloud while plugging into the full PhyStack platform, the same spaces, devices, peripherals, signals, and twins your edge and screen apps use. They let a service running in the cloud participate in the physical world as a first-class citizen, sharing one coherent model of each space with the devices on site and with AI agents over MCP. Typical scenarios include:

  • Bridging third-party cloud-managed peripherals into a space. Connect external cloud services and the hardware they control, payment terminals, lockers, access control, vendor-managed kiosks, so they appear in PhyStack as twins alongside on-site devices and are controllable through the same API.
  • Giving a cloud service a coherent view of physical spaces. A cloud app reads and writes the same space, device, and peripheral model the rest of the platform shares, so logic in the cloud, devices in the store, and agents acting through MCP all operate on one consistent, live picture of each location.
  • Running backend logic against real-world context. Scheduled or event-driven logic triggered by in-store activity via Signals, orchestrating workflows that span devices and locations, without running anything on the devices themselves.

How Cloud Apps Work

  • Runtime: Cloud apps run as standard server-side processes, no containers or special runtimes required. TypeScript and Rust are both supported.
  • Connection: The app authenticates with the platform using a credential set and opens a persistent connection to PhyHub.
  • Cloud Instances: Each activated space becomes a cloud instance. The app receives cloud instance twins in real time and can read their settings and report properties back.
  • Settings: Operators configure the app through the Console using the same settings schema system as screen and edge apps. Global settings apply to all spaces; per-space overrides let operators customize behavior per location.

Prerequisites

Official PhyStack cloud app templates are available in TypeScript (Bun) and Rust. This tutorial uses the TypeScript template.

Before you begin, make sure the following are set up and ready to go:

A PhyStack Tenant

You’ll need access to a PhyStack tenant. If you don’t yet have one, please refer to the Tenant Setup guide.

Local Development Environment with PhyCLI Installed and Configured

If you haven’t set up CLI on your machine yet, refer to the Dev Environment Setup guide.

Make sure you have PhyCLI 6.2.0 or later installed:

phy --version

Bun Installed

The TypeScript cloud app template uses Bun as the runtime and package manager. Install it if you haven’t already:

curl -fsSL https://bun.sh/install | bash

Step-by-Step: Creating and Publishing a Cloud App

Once your environment is ready, you can create and publish your first cloud app. This process involves generating a starter project, saving the one-time credentials, and running the app locally.

1. Scaffold the Cloud App Project

Run the following command to begin:

phy app create

You’ll be prompted to provide a name for your application. If you don’t specify one via CLI args, you’ll be asked interactively.

Then you’ll select the app type, choose ** Cloud Application (TypeScript)**

This tells the CLI to scaffold a server-side cloud application that connects to the PhyStack platform.

2. Save Your Credentials

After the template is cloned and the app is registered, the CLI displays a yellow credentials block:

============================================================
 CLOUD APP CREDENTIALS (ONE-TIME DISPLAY)
============================================================

Add these environment variables to your .env file:

  PHYSTACK_APP_REGISTRATION_ID=<your-app-id>
  PHYSTACK_APP_SECRET=<your-secret>
  PHYSTACK_CORE_API_URL=<gateway-url>
  PHYSTACK_PHYHUB_URL=<phyhub-url>
  PHYSTACK_REGION=<region>

WARNING: The APP_SECRET will NOT be shown again.
Save it now. If lost, you must recreate the app to get a new secret.
============================================================

Important: The secret is displayed only once and cannot be recovered. Copy all five values immediately.

For local development, create a .env file in the root of your new project directory (the same level as package.json) and paste the credentials:

PHYSTACK_APP_REGISTRATION_ID=abc123-def456
PHYSTACK_APP_SECRET=your-secret-value
PHYSTACK_CORE_API_URL=https://api.phystack.com
PHYSTACK_PHYHUB_URL=https://phyhub.phystack.com
PHYSTACK_REGION=EU

Tip: For production deployments, store these values securely using your environment’s secret management (e.g., environment variables on your hosting platform, a secrets vault, or CI/CD pipeline secrets) rather than a .env file.

3. Explore the Project

You can explore your newly created project. In the directory with the project, you will find a TypeScript application including:

  • src/ directory with:
    • index.ts, application entry point that connects to PhyHub, manages cloud twins, and emits events
    • schema.ts, settings schema for your application with example settings (learn more in the Settings Schemas guide)
    • analytics-schema.ts, analytics event types this app emits (learn more in the Reports guide)
  • package.json containing useful scripts (dev, build, pub)
  • tsconfig.json and other standard TypeScript project files

The index.ts file demonstrates the usage of the @phystack/hub-client package for platform integration. The connection is established with the credentials from your .env file:

const client = await PhyHubClient.connect({
  cloudApp: {
    appRegistrationId: process.env.PHYSTACK_APP_REGISTRATION_ID,
    appSecret: process.env.PHYSTACK_APP_SECRET,
    coreApiUrl: process.env.PHYSTACK_CORE_API_URL,
    phyhubUrl: process.env.PHYSTACK_PHYHUB_URL,
  },
});

The template app listens for twin lifecycle events and starts emitting analytics events for each active twin based on the settings it receives:

client.onCloudTwinUpdated((event) => {
  // Twin created or settings changed — restart event emitter with new settings
});

client.onCloudTwinDeleted((event) => {
  // Twin deactivated — stop emitting events for this space
});

The default schema.ts defines two operator-editable settings that appear in the Console:

export type Settings = {
  /** @title Event names */
  eventNames: string[];

  /** @title Frequency (ms) */
  frequencyMs: number;
};

Under the hood, the SDK exchanges your credentials for a short-lived token and opens a persistent connection to PhyHub. The token auto-refreshes before expiry, the transport stays connected.

4. Run the App Locally

Start the app in development mode with hot reload:

bun run dev

This runs bun --watch src/index.ts, which starts the app and automatically restarts it when you make changes.

You should see output confirming a successful connection to PhyHub. At this point the app reports 0 cloud twins, that’s expected, because you haven’t created an installation or activated any spaces yet.

Checkpoint

After completing this process, you’ll have:

  • A cloud app project on your local machine
  • A new app available in your tenant for installation
  • The app running locally and connected to PhyHub

Creating an Installation and Activating Spaces

Now that your app is running, the next step is to create an installation, configure settings, and activate spaces so your app starts receiving cloud twins.

Create an Installation

  1. Log in to console.phystack.com
  2. Navigate to Apps > Developer and locate your app in the list
  3. Press the Install button and provide a name for your new installation
  4. After confirmation, you will be redirected to the Installation page

Configure Global Settings

  1. Navigate to the Settings tab on your Installation page
  2. Click Edit settings on the Global settings card
  3. Select a build version from the dropdown (the version published during app creation)
  4. Fill in the settings form with your desired values, these are the default settings that apply to all spaces
  5. Press Save changes

After saving, a new build will be created automatically. You can verify this in the Builds tab, look for a new entry with a green status.

Activate a Space

Cloud apps don’t connect to physical devices. Instead, you activate the app in one or more of your tenant’s spaces. Each activation creates a cloud twin, a virtual representation of the app running in that space.

  1. Go back to the Settings tab
  2. In the Settings override section, you’ll see a list of your tenant’s spaces
  3. Click the Activate button next to a space

Once activated, the space icon turns pink and the space name becomes bold. Check your app’s terminal, you should see a log message indicating a new cloud twin was received:

event: cloudTwinCreated { id: "...", deviceId: "...", spaceId: "..." }

You can activate multiple spaces. Each activation creates an additional cloud twin, and your app receives each one independently.

Per-Space Settings Overrides

You can customize settings for individual spaces without affecting others:

  1. Click Edit settings for this space next to an activated space
  2. Modify one or more setting values
  3. Press Save changes

Only that space’s twin will receive the updated settings. Other spaces continue using their own overrides or the global defaults.

To revert a space back to global settings, open its settings editor and click Clear space settings overrides at the bottom of the form.

⏹ Deactivate a Space

To remove a cloud twin from a space:

  1. Click the deactivate button next to an active space
  2. Confirm the action in the modal

The app will receive a twin deletion event, and the space reverts to its inactive state. The app can be reactivated in the same space at any time.

Add a New Setting and Publish

Now let’s walk through a typical development iteration: adding a new setting to the schema, using it in the app code, and publishing the updated version.

1. Add a property to the settings schema

Open src/schema.ts and add a new appLabel property:

export type Settings = {
  /** @title Event names */
  eventNames: string[];

  /** @title Frequency (ms) */
  frequencyMs: number;

  /**
   * @title App label
   * @description A friendly label for this cloud instance, shown in logs.
   * @default "My Cloud App"
   */
  appLabel: string;
};

2. Use the new setting in your app code

Open src/index.ts and update the code to read and log the new appLabel setting when a twin arrives. For example, include it in the log output when a twin is added or updated:

const settings = parseSettings(twin);
log('info', `${tag} twin active — label: ${settings.appLabel}`, { settings });

Since bun run dev runs with --watch, the app will automatically restart. You can verify the change locally, twins will now include the label in log output (using the default value until you configure it in the Console).

3. Bump the version and publish

In package.json, increase the version number:

"version": "0.2.0"

Build and publish the new version to your tenant:

bun run build
bun run pub

4. Deploy the new version from Console

  1. Go back to your installation in the PhyStack Console
  2. Navigate to the Settings tab and click Edit settings on the Global settings card
  3. In the Build version dropdown, select 0.2.0
  4. You’ll see the new App label field in the settings form, fill it in
  5. Press Save changes

After a few moments, your app will receive updated twins with the new settings. You should see the label appear in the log output for each active twin.

Success!

Your cloud app is now running with real-time twin management, configurable settings, and per-space overrides.

You’ve successfully gone from creation to deployment, iteration, and production publishing, all with full integration into the PhyStack platform.

Checkpoint

After completing this part of the tutorial, you should have:

  • A fully functional cloud app connected to PhyHub
  • An installation configured in your tenant with at least one activated space
  • Cloud twins flowing to your app with configurable settings

Next Steps

Now that your app is set up, you can: