Deploy a Viam application
Package your client app and upload it to Viam Applications, Viam’s hosting service for web apps. Once uploaded, your app is served at {appname}_{namespace}.viamapplications.com with authentication and machine-credential injection handled by the platform.
Viam Applications are distributed through the Viam module registry, which is why the CLI commands live under viam module. This has nothing to do with building server-side modules; the module in the command name is an artifact of the registry plumbing.
Prerequisites
- A built client app. Any bundler output that produces HTML, JavaScript, and CSS works: a Vite
dist/directory, a Create React Appbuild/directory, a Flutter web build, and so on. See TypeScript setup for a minimal Vite starting point. - The Viam CLI installed and authenticated (
viam login). - A public namespace for your organization. Set this in the organization settings if you have not already. Viam Applications require a public namespace because the app’s URL uses it.
Create the module registry entry
First-time setup only. Each Viam Application is represented as a module in the Viam registry. Create the registry entry:
viam module create --name my-app --public-namespace your-namespace
This creates a meta.json in your current directory with a module_id of your-namespace:my-app and visibility: private. You will change the visibility and add the applications field in the next step.
Configure meta.json
Edit meta.json to declare the application. The generated file needs two changes:
- Change
visibilityfromprivatetopublic. Viam Applications require public visibility. - Add an
applicationsarray describing the app.
A complete meta.json for a single-machine browser app:
{
"$schema": "https://dl.viam.dev/module.schema.json",
"module_id": "your-namespace:my-app",
"visibility": "public",
"applications": [
{
"name": "my-app",
"type": "single_machine",
"entrypoint": "dist/index.html"
}
]
}
Key fields in the applications entry:
name— appears in the URL as{name}_{namespace}.viamapplications.com. Lowercase alphanumeric and hyphens only. Must be unique within your namespace.type—single_machineormulti_machine. Single-machine apps pick one machine and inject that machine’s credentials. Multi-machine apps inject a user access token and let the app enumerate machines.entrypoint— path to the HTML entry point, relative to the uploaded archive’s root. For a Vite build, this is typicallydist/index.html.
See the meta.json applications reference for all available fields, including fragmentIds, logoPath, and customizations.
Build your app
Run your bundler to produce the static output. For Vite:
npm run build
Confirm the output directory contains an index.html and all its asset files. The path you put in entrypoint must match what the build produces.
Package and upload
Create a tarball of everything you want to serve, including meta.json:
tar -czvf module.tar.gz meta.json dist/
Adjust the tar command to include whatever directories your build produced. The meta.json must be at the root of the archive.
Upload to the registry:
viam module upload --upload module.tar.gz --platform any --version 0.0.1
Use --platform any for Viam Applications. Static web apps are platform-independent; the any platform tag tells the registry to serve the same archive to every user regardless of operating system.
The --version flag is required and must be a semver string. You cannot reuse a version number, so each upload needs a higher version than the last.
Verify the deployment
Your app is now live at:
https://{name}_{namespace}.viamapplications.com
Replace {name} with the name field from your meta.json and {namespace} with your organization’s public namespace. Open the URL in a browser. You should see:
- A redirect to the Viam login flow.
- After login, for a single-machine app: the machine picker (if the app has no fragment filter) or the app itself (if the URL targets a specific machine).
- For a multi-machine app: your app loads directly with the user access token already in cookies.
If the app does not load, check:
- The
applicationsarray in the uploadedmeta.json. If the registry sees no applications, no URL is assigned. Re-upload with the correct field after fixingmeta.json. - The
entrypointpath. The path is relative to the archive root. Ifmeta.jsonis at the root and your HTML is atdist/index.html, the entrypoint should bedist/index.html, not/dist/index.htmlorindex.html. - The namespace. The URL uses your organization’s public namespace, not the organization name or ID. Confirm the public namespace in the organization settings.
Release updates
To release a new version of your app, rebuild and re-upload with a higher version number:
npm run build
tar -czvf module.tar.gz meta.json dist/
viam module upload --upload module.tar.gz --platform any --version 0.0.2
Viam Applications always serve the latest uploaded version. There is no staging step and no version selection in the URL.
To roll back, upload the previous code under a new, higher version number. The registry rejects duplicate version numbers, so you cannot reuse an older one.
Next
- meta.json applications reference for the full schema
- Hosting platform reference for URL patterns, cookie structure, caching behavior, and limits
- Test against a local machine for iterating on your app before each upload
Was this page helpful?
Glad to hear it! If you have any other feedback please let us know:
We're sorry about that. To help us improve, please tell us what we can do better:
Thank you!