Ship an App
Build your App’s front-end in the AI tool you already use: Claude Code, Cursor, Lovable, Replit, Bolt or your own editor. work.studio is everything behind it: sign-in, data, agents, automations, connectors, plans and billing. It also hosts the built front-end at https://<address>.workstudio.run, inside your own organization and environment.
The work looks like this:
- Start from a template, or from a project you already have.
- Connect your AI tool to work.studio, so it builds against your App’s real setup.
- Deploy. Every upload is checked and gets its own preview address.
- Make it live, and roll back if you need to.
What gets hosted
Section titled “What gets hosted”An App on workstudio.run has two parts:
- A static front-end: the folder your build makes, with HTML, JavaScript, CSS, images, fonts and other web files.
- App functions (optional): your own server code, served at
/api/*on the same address. Use them for what must not run in the browser: a call with a secret API key, results only paying people get, a check people must not be able to skip. Every organization that can host an App can use them. See App functions.
Everything else goes through the App SDK to the platform: people sign in on work.studio’s hosted page, their records live in the App’s data collections, and its agents, plans and connectors run on work.studio.
Before you start
Section titled “Before you start”- A work.studio organization that has been approved, whose owner has verified their email. Hosting is only for these organizations.
- Node.js on your machine, if you deploy with the command line.
- For the command line, an organization API key. See API keys.
1. Start from a template or your own project
Section titled “1. Start from a template or your own project”The App Kit makes a new project with the App’s front-end, its workstudio.app.yaml and instructions for AI tools.
npm create workstudio-app@latest corner-bakery# or a members-only tool:npm create workstudio-app@latest ops-desk -- --template internal-tool# or the smallest App, sign-in and one collection:npm create workstudio-app@latest pocket-notes -- --template blank# or sign-in, notes, photos and an AI assistant, with no payments to set up:npm create workstudio-app@latest my-showcase -- --template showcase
cd corner-bakerynpm installexport WORKSTUDIO_API_KEY=svx_tk_… # your organization API key (or: npx workstudio login, once)npx workstudio apps apply # makes the App on work.studio, claims corner-bakery.workstudio.run, writes .env.localnpm run dev| Template | What you get |
|---|---|
starter (the default) |
People sign in, keep their own records, pay for a plan, share by link, and talk to the App’s assistant |
internal-tool |
Members only: only your organization’s members sign in. A team table over a data collection, and an assistant that knows it |
blank |
People sign in and keep their own notes, in one notes collection. No AI, no payments, no functions, so there’s nothing to delete before you build |
showcase |
People sign in, keep notes, upload photos, and chat with a small assistant (Claude Haiku). No payments, so there’s no Stripe key to set up: each person gets a small monthly AI allowance |
The folder name becomes the App’s key, its address and its name. Everything the App is on the platform lives in workstudio.app.yaml: npx workstudio apps plan shows what would change, and npx workstudio apps apply makes it so.
Each template includes AGENTS.md and CLAUDE.md. They tell your AI tool the rules: a static front-end, server code only in functions/, everything else through the SDK, and npx workstudio deploy to ship. They also tell it to deploy a preview early, and where the App’s requests and errors are written down.
A new App also gets a .mcp.json, which connects Claude Code to work.studio’s MCP server for this project (see Connect your AI tool). It holds no key, so you can commit it.
The starter template includes an example function in functions/index.ts, served at /api/pro-tip, and the page code that calls it with the person’s sign-in (src/api.ts). If your organization can’t use App functions yet, deploy stops with FUNCTIONS_NOT_ENABLED: set functions: false under hosting in workstudio.app.yaml, or delete the functions/ folder.
Any project that builds a static site works: Vite, Create React App, Astro, Next.js with a static export, or plain HTML. Add the App Kit’s command line and a workstudio.app.yaml next to your package.json:
npm i -D @workstudio-inc/cliversion: 1app: key: corner-bakery # lower case, digits and dashes name: "Corner Bakery"hosting: slug: corner-bakery # https://corner-bakery.workstudio.run dir: dist # the folder your build makes (default dist); it must hold index.html build: npm run build # what deploy runs first (default); "" for none spa: true # a path that isn't a file serves /index.html (default true)Then apply, with your API key in WORKSTUDIO_API_KEY (or kept once with npx workstudio login). apply makes the App on work.studio if it doesn’t exist and claims the address:
npx workstudio apps applyTo use sign-in, data or agents from your code, add the App SDK (npm i @workstudio-inc/sdk) and declare what you use in the manifest.
Tools that build in the browser don’t need the command line. Make the App in work.studio, export the built folder from your tool, and upload it.
- Open your App’s page in work.studio (Distribute › Apps, then the App). Make one first if you need to.
- On the App’s Overview, find Build with your AI tool and select Lovable / Replit / Bolt. Select Copy prompt and paste the prompt into your tool. It describes your App’s real sign-in, data collections, plans and agents.
- When the build is done, export the built folder: the one with
index.htmlat its top, usuallydist,buildorout. A .zip of that folder works too. - Upload it on Ship › Hosting (see Deploy).
Claim the address
Section titled “Claim the address”Each App has one address, https://<address>.workstudio.run. It’s first come, first served, and stays yours for as long as the App exists.
- The command line claims it on
npx workstudio apps apply, fromhosting.slug. - In work.studio, open the App’s Ship › Hosting, type the Address and select Claim address.
An address is 3 to 40 lowercase letters, digits and hyphens, starting and ending with a letter or digit, with no --. Platform words (such as www, api, admin, login) and well-known brand names are reserved. Once a deployment has gone live, the address is fixed; a new address means new hostnames.
Every hostname of the site is added to your App’s web sign-in addresses automatically, so sign-in works on it without more setup.
2. Connect your AI tool
Section titled “2. Connect your AI tool”work.studio’s MCP server lets your AI tool read how your App is really set up: its data collections and fields, its plans’ feature keys, its agents’ ids, who can sign in, and its hosting. With it, the tool writes code that matches the platform instead of guessing.
An App made with npm create workstudio-app already has a .mcp.json that names the server. Open the project in Claude Code, approve the workstudio server when it asks, then run /mcp and sign in to work.studio.
For every project instead, add it once:
claude mcp add --scope user --transport http --client-id mcp-public workstudio https://api.work.studio/mcp/v1The first time Claude Code uses it, it asks you to sign in to work.studio. You can also run /mcp in Claude Code to sign in.
Add this to ~/.cursor/mcp.json, or to .cursor/mcp.json in the project. Cursor opens the work.studio sign-in.
{ "mcpServers": { "workstudio": { "url": "https://api.work.studio/mcp/v1" } } }The server is https://api.work.studio/mcp/v1 (streamable HTTP, with OAuth sign-in). To use an API key instead, send it as the X-API-Key header from your tool’s own settings. Never put a key in a file you commit.
If you belong to more than one environment, my.studio’s Settings › Connect an agent gives the exact command for the one you’re in. See MCP.
The tool works as you, with exactly the access you have. These are the App tools:
| Tool | What it does |
|---|---|
workstudio_list_apps |
Lists your organization’s Apps, to find the App and its id |
workstudio_get_app |
The App’s setup: sign-in, data collections and fields, plans and feature keys, agents, hosting |
workstudio_app_build_brief |
The same setup written as instructions for building the front-end |
workstudio_hosting_status |
The address, what is live in each environment, recent deployments and their findings |
workstudio_hosting_promote |
Makes a checked deployment live |
workstudio_hosting_rollback |
Makes an earlier deployment live again |
Uploads always go through the command line or the upload on Ship › Hosting, not through the MCP server. A tool connected with an API key needs the key’s own permission to change automations to make a deployment live or roll back.
3. Deploy
Section titled “3. Deploy”npx workstudio deploydeploy runs your build, packs the built folder, checks it, uploads it, and prints what the checks found and a preview address. It refuses before uploading when the platform would refuse the bundle, and when a built file holds what looks like a secret key, such as a Stripe secret key, a work.studio API key, an AWS key or a private key. It names the file and the kind of key, never the key itself.
Without --promote, a deployment is only a preview. A preview address is a public link: anyone who has it can open the App and call its functions. Preview functions don’t receive the App’s secrets; a secret reads as undefined there, and only the live deployment’s functions get them. Deploy early all the same, as soon as the App builds, and again after each change. Checking the App on its preview address finds what local testing can’t, such as the browser rules below.
| Option | What it does |
|---|---|
--promote (or --prod) |
Makes the deployment live once it passes the checks |
--message "fix header" |
A note you see in the list of deployments |
--no-build |
Skips the build and uploads the folder as it is |
--dir build |
Uploads another folder than hosting.dir |
--env <name> |
Deploys to another environment of the App |
The command exits with 0 when the deployment is ready or live, 2 when it’s rejected, and 3 when it’s held for review, so you can use it in a script.
deploy warns when .env.local is missing or was written for another environment: the build bakes in the App ids that npx workstudio apps apply writes there. Run apply before your first deploy and again after every change to the manifest, also once the App is deployed: it changes only what differs.
- Open your App’s page and select Ship › Hosting. Claim an address first if you haven’t.
- Under Upload a build, drop your built folder on the box, or select Choose folder or Choose .zip. A .tar.gz works too.
- Optionally type a Message (optional), such as what changed.
- Select Upload and check.
When you upload a folder, files that would be public on the site or aren’t part of a build, such as .env files and node_modules, are left out, and the page lists them under Left out.
An upload in work.studio carries static files only. To deploy App functions, use the command line.
Every upload is checked before anything is served. The result is one of:
| Result | What it means |
|---|---|
| Ready | Passed the checks. Open its preview, then make it live |
| Rejected | Something under BLOCK must be fixed. Nothing is served from it |
| Held for review | Something under HOLD looks like a phishing or credential page. A person at work.studio reviews it. It isn’t served, not even as a preview, until it’s released |
See Checks on every upload for what each finding means.
4. Preview, make live, roll back
Section titled “4. Preview, make live, roll back”Each deployment gets its own preview address, https://<address>--d<last 8 characters of its id>.workstudio.run. Open it and check the App before you make it live.
Make it live:
- In work.studio: on Ship › Hosting, select Make live on the deployment.
- From the command line:
npx workstudio hosting promote <id>. The whole id always works;deployprints it.npx workstudio hosting deploymentsalso shows a short id for each. Or deploy with--promotein one step. - From your AI tool: ask it to make the deployment live (
workstudio_hosting_promote).
The deployment that was live before stays in the list. It no longer has a preview address, and its functions no longer receive the App’s secrets. Rolling back to it gives both back.
Roll back:
- In work.studio: select Roll back to this on an earlier deployment.
- From the command line:
npx workstudio hosting rollback <id>. - From your AI tool:
workstudio_hosting_rollback.
npx workstudio hosting status shows the address, what’s live in each environment and today’s use. npx workstudio hosting deployments lists deployments, newest first. work.studio keeps the last 10 deployments of each environment, plus whatever is live.
Environments
Section titled “Environments”The environment where you claimed the address is served at https://<address>.workstudio.run. Each other environment of the App has its own address, https://<address>--<environment>.workstudio.run, and its own live deployment. Deploy to one with --env <name>. See Environments.
Take an App offline
Section titled “Take an App offline”On Ship › Hosting, select Take offline, or run npx workstudio hosting delete --yes. Every address of the App stops answering and the address is released for anyone to claim. The App itself, its data and its sign-in stay.
Delete an App
Section titled “Delete an App”npx workstudio apps delete # asks you to type the App's address firstnpx workstudio apps delete --yes # without asking, for scriptsThis deletes, in the environment you run it for:
- The App’s site. Every address stops answering and is released.
- The App, with every version. Its people lose their installs.
- The agents
npx workstudio apps applymade for it. An agent the App bundles from elsewhere stays.
It can’t be undone. work.studio refuses while businesses still run the App: they must remove it first. The App’s people keep their sign-in accounts, because those aren’t yours. To delete a person’s data too, see Delete one of the App’s people. The next npx workstudio apps apply in the folder makes a new App.
Delete one of the App’s people
Section titled “Delete one of the App’s people”npx workstudio apps users list # account id, status and install of each personnpx workstudio apps users delete 6f1c2a9e-… # asks you to type the id first; --yes for scriptsIt needs the connection:delete permission in the App’s environment. Outside the App’s folder, name the App with --app <address>. What is erased, and how it matches the person deleting their own account, is in Delete one of your App’s people.
App functions (/api/*)
Section titled “App functions (/api/*)”An App function is your own server code, served at /api/* on the App’s address. The rest of the site stays static.
Write one
Section titled “Write one”Put it in functions/index.ts (or .js, .mjs) next to workstudio.app.yaml. It default-exports an object with a fetch handler:
export default { async fetch(request: Request, env: Record<string, string>): Promise<Response> { const user = request.headers.get('X-WS-User'); // absent when nobody is signed in const features = (request.headers.get('X-WS-Features') ?? '').split(','); if (!user) return Response.json({ error: 'Sign in first' }, { status: 401 }); if (!features.includes('pro')) return Response.json({ error: 'Pro only' }, { status: 403 });
const res = await fetch('https://api.example.com/v1/answer', { headers: { Authorization: `Bearer ${env.EXAMPLE_API_KEY}` }, // a function secret }); return Response.json(await res.json()); },};npx workstudio deploy bundles the file and everything it imports into one module and sends it with the static files. Functions are deployed only from the command line. They have a preview, go live and roll back together with the deployment they belong to. On a preview, functions run without the App’s secrets, so make them answer sensibly when one is missing. To use another folder, set hosting.functions; for a static-only App with a functions/ folder you don’t want deployed, set functions: false.
Functions run on a web-standard runtime (Request, Response, fetch). Node built-ins such as fs and net aren’t available.
Who is asking
Section titled “Who is asking”Before your function runs, work.studio checks the person’s sign-in and tells your code who they are in these headers:
| Header | What it holds |
|---|---|
X-WS-User |
The signed-in person’s id. Absent when nobody is signed in |
X-WS-App |
Your App’s id |
X-WS-Plan |
The person’s plan |
X-WS-Features |
What their plan unlocks, comma separated |
X-WS-Email-Verified |
true or false |
Any X-WS- header a caller sends is removed first, so a function can trust these. Never check a token in your function yourself.
The headers are filled in only when the page sends the person’s token. The starter template’s api() helper does that:
// src/api.ts in the starterconst token = (await app.auth.signedIn()) ? await app.auth.token() : null;const res = await fetch('/api/pro-tip', { headers: token ? { Authorization: `Bearer ${token}` } : {},});Secrets
Section titled “Secrets”A function reads secrets, such as a third-party API key, from env. Secrets are kept per App and environment, and can’t be read back once saved.
- From the command line:
npx workstudio secrets set EXAMPLE_API_KEYreads the value from what you type or pipe in.npx workstudio secrets listshows names only;npx workstudio secrets delete EXAMPLE_API_KEYremoves one. - In work.studio: on Ship › Hosting, under Function secrets, type the Name and Value and select Add.
Names use capital letters, digits and underscores, starting with a letter, such as STRIPE_KEY. WS_APP_ID, WS_ENV and WS_SITE are set by work.studio. A changed secret reaches the live functions straight away. Only the live deployment’s functions receive secrets; previews don’t. Never put a secret in the front-end: everything in it is public.
Calls to other services
Section titled “Calls to other services”Every fetch a function makes passes a filter first:
https://on the standard port only, with no user name or password in the URL;- no IP addresses, and no private, local or cloud metadata addresses;
- never another App on workstudio.run;
- of work.studio’s own addresses, only
https://api.work.studio; - a short list of known abuse targets is refused.
A blocked call gets a 403 response. Every call’s data counts toward the App’s monthly data limit.
Function limits
Section titled “Function limits”| What | Limit |
|---|---|
| CPU time | 50 ms per request |
| Calls to other services | 20 per request, and 1,000 a minute per site (then 429) |
| Calls to your functions | 600 a minute per site, across all of its addresses (then 429 with Retry-After) |
| Module size | 1 MB, bundled |
| Secrets | 50 per App |
Each function call counts toward the site’s daily requests. Over either limit, work.studio answers 429 with {"error":"over_quota"} without running the function; over the 600 a minute, the Retry-After header says how many seconds until the next call is accepted, and the refused call doesn’t count toward the daily requests. The 600 is counted over the last minute, not per calendar minute.
Members-only Apps and shared data
Section titled “Members-only Apps and shared data”Only your organization signs in
Section titled “Only your organization signs in”An App can be for your own team: an internal tool that only your organization’s members can use.
- On the App’s page, open Sign-in › Sign-in page.
- Under Who can sign in, choose Only members of your organization (the other choice is Anyone (public)).
- Select Save.
With the App Kit, set it in the manifest instead and run npx workstudio apps apply:
signIn: audience: members # public (the default) or membersA person gets in only when their verified email belongs to a member of your organization. Anyone else is turned away and sees that the App is only for your organization’s members. A members-only App stays Private: it can’t be listed in the marketplace while it’s members-only.
A table the whole team shares
Section titled “A table the whole team shares”In a members-only App, a data collection can be shared by the team: every member who signs in reads, adds, changes and deletes the same rows. Declare it in workstudio.app.yaml and run npx workstudio apps apply:
data: - collection: requests shared: members # leave this out for records each person keeps to themselves fields: - { name: title, type: STRING, required: true } - { name: status, type: STRING }- work.studio stamps each row with who added it and who changed it last:
createdBy,createdByName,updatedByandupdatedByNameon each record the SDK returns. Your App can’t set them. - Any member can change or delete any row. When two people save the same row at once, the last save wins.
- Only a members-only App can share a collection. To open the App to the public, make every shared collection private first.
- A collection without
sharedis private: each person sees only their own rows, as in any App. - Someone removed from your organization can keep access for up to 15 minutes, until their sign-in expires.
Limits and checks
Section titled “Limits and checks”Limits
Section titled “Limits”These limits are per organization.
| What | Limit |
|---|---|
| Sites (Apps with an address) | 3 |
| Storage, all deployments together | 200 MB |
| Deployments | 30 a day (UTC) |
| Requests | 200,000 a day, per site |
| Data served | 5 GB a month, per site, including what functions fetch |
| One upload | 19 MB compressed, 100 MB uncompressed, 2,000 files, 25 MB per file |
| App functions | See Function limits |
When a site goes over its requests for the day or its data for the month, it shows a “too many requests” page until the period resets. The organization’s owner gets an email at 80% of a limit and again when it’s reached. Ship › Hosting shows the site’s use against its limits under Usage.
AI and data use inside the App are covered by the App’s own budgets and allowances, as for any App. Hosting adds nothing to them.
What the browser allows
Section titled “What the browser allows”Every page is served with a fixed set of security headers. They shape what your front-end can do:
- Scripts must be files in your build. Inline
<script>blocks and scripts from other sites don’t run. - Calls (
fetch, WebSockets) can go to your own address and to work.studio. To call another service, add its origin tohosting.connectOriginsin the manifest, such ashttps://api.example.com, and runnpx workstudio apps apply. Up to 20 origins. - Fonts and stylesheets must be in your build. Images can come from any
https://address. - Camera, microphone, location and payment APIs are turned off. Take payments through your App’s plans.
- Framing: other sites can’t show your App in a frame.
- No cookies. The SDK keeps the person’s sign-in in the page, not in cookies.
Checks on every upload
Section titled “Checks on every upload”Every file is checked on every upload. Each finding has a level:
| Level | What happens | What is found |
|---|---|---|
| BLOCK | The deployment is rejected | Secret files (such as .env, .npmrc, key files, .git folders, database dumps); server code among the static files (.php, .py, .rb, .jsp, .aspx, .cgi, .sh, .ps1, .bat); executables, installers and archives; links; unsafe paths; no index.html; over a limit; a functions module that isn’t one ES module with a default export, or that imports code it doesn’t bundle |
| HOLD | Held for a person at work.studio to review. Not served, not even as a preview, until released | Look-alike sign-in pages: a password field whose form posts to another site, or that sits near brand names; forms asking for a seed phrase, private key or “verify your account”; a page that only redirects to another site; heavily obfuscated script, in pages or in functions |
| WARN | Served as usual | Source maps (anyone can read them), very large images, unusual file types |
Your App never needs a password field: people sign in on work.studio’s hosted page through the SDK.
Acceptable use and abuse reports
Section titled “Acceptable use and abuse reports”Sites on workstudio.run must follow the work.studio terms. work.studio can suspend a site that breaks them; a suspended site shows a page saying so, and nothing can be deployed to it. To report abuse on a workstudio.run site, email abuse@workstudio.run or use the contact form and choose Report abuse on a workstudio.run site. Include the full address.
Troubleshooting
Section titled “Troubleshooting”Each entry starts with what you see. Messages in quotes are the text the command line or work.studio shows. For errors from sign-in and data calls in the App itself, see Troubleshoot App sign-in and data. The requests behind them are on App HTTP requests.
“Not uploaded - the built files hold what looks like a secret”
Section titled ““Not uploaded - the built files hold what looks like a secret””A key ended up in the built front-end, usually through a VITE_* variable or a key pasted into the code. Everything in the site is public. Take the key out of the front-end: put one your App needs in a function secret (npx workstudio secrets set NAME) or in workstudio.app.yaml as ${env:NAME}. Then rotate the key, because it may already be in a build someone has. In functions/ the same finding is only a warning, but the key still belongs in a function secret.
FUNCTIONS_NOT_ENABLED: “App functions are not enabled for this organization yet”
Section titled “FUNCTIONS_NOT_ENABLED: “App functions are not enabled for this organization yet””App functions are turned off for your organization. Deploy without them: set functions: false under hosting in workstudio.app.yaml, or delete the functions/ folder. npx workstudio secrets is refused the same way, because secrets are only for functions. If you expected functions to work, contact us.
/api/* answers 429 over_quota
Section titled “/api/* answers 429 over_quota”Your site’s functions were called more than 600 times in the last minute, or the site used up its requests for the day. Wait the number of seconds in the Retry-After header and try again; with no Retry-After, the daily limit is reached and resets at 00:00 UTC. If your own front-end calls a function in a loop, slow it down.
A function sees no X-WS-User
Section titled “A function sees no X-WS-User”The page called the function without the person’s token. Send it as Authorization: Bearer <token> (the starter template’s api() helper does). Signed-out calls reach the function without the identity headers.
A function’s fetch gets 403
Section titled “A function’s fetch gets 403”The call was refused by the outbound filter: it isn’t https://, goes to an IP address or a private address, goes to another workstudio.run App, or goes to a blocked service. See Calls to other services.
FUNCTIONS_IMPORT or FUNCTIONS_REMOTE_IMPORT
Section titled “FUNCTIONS_IMPORT or FUNCTIONS_REMOTE_IMPORT”The functions module imports code it doesn’t contain. Deploy with npx workstudio deploy, which bundles everything into one module, and don’t import code from a URL.
FUNCTIONS_NOT_MODULE: “must be an ES module with a default export”
Section titled “FUNCTIONS_NOT_MODULE: “must be an ES module with a default export””functions/index.ts needs export default { fetch(request, env, ctx) { ... } }.
SECRET_FILE: “This looks like an environment file, which would be public on the site”
Section titled “SECRET_FILE: “This looks like an environment file, which would be public on the site””A file that holds secrets, such as a .env file, a key file or a .git folder, is in the folder you uploaded. Remove it from the build output. Never put secrets in the front-end: everything in it is public.
BLOCKED_FILE_TYPE
Section titled “BLOCKED_FILE_TYPE”The static files contain server code, an executable or an archive. Static files are web files only. Remove the file; server code belongs in an App function, an automation or an agent.
NO_INDEX_HTML
Section titled “NO_INDEX_HTML”The folder you uploaded has no index.html at its top. Upload the built folder (dist, build or out), not the project. A single top-level folder inside a .zip is fine.
Held for review (HOLD)
Section titled “Held for review (HOLD)”The checks found something that looks like a sign-in or credential page. Nothing is served until a person at work.studio releases it. If it’s a page of your own, remove the password field and use the SDK’s sign-in (app.auth.signIn()). Once released, make it live with Make live or npx workstudio hosting promote <id>.
A blank page, and a Content Security Policy error in the browser console
Section titled “A blank page, and a Content Security Policy error in the browser console”A script, stylesheet or font comes from another site, or the page has an inline <script>. Bundle them into your build. For calls to another service, add its origin to hosting.connectOrigins.
A page reloads to 404 on a deep link
Section titled “A page reloads to 404 on a deep link”Turn on the single-page app setting: spa: true under hosting (the default), or Single-page app: send addresses that are not files to index.html when you claim the address.
“…is taken by another App” or “…is reserved”
Section titled ““…is taken by another App” or “…is reserved””Choose another hosting.slug (or Address). Reserved words include platform words and well-known brands.
Windows: “An Application Control policy has blocked this file” during the build
Section titled “Windows: “An Application Control policy has blocked this file” during the build”Apps made with create-workstudio-app 0.6.0 or later don’t hit this: their package.json already overrides rollup with @rollup/wasm-node, so no native rollup file is installed. The rest of this section is for older Apps.
Windows Smart App Control, or another application control policy on your machine, blocks a program file it hasn’t seen before. A new release of rollup, the bundler inside Vite, ships such a file, so npm run build fails with ERR_DLOPEN_FAILED and a path ending in rollup.win32-x64-msvc.node.
npx workstudio deploy handles this for you. It says so in one line, then builds once more with @rollup/wasm-node, the WebAssembly build of the same rollup. It’s slower, and the output is the same. Nothing in your project changes.
-
To use it from the start, set
WORKSTUDIO_ROLLUP_WASM=1beforenpx workstudio deploy. -
To use it everywhere,
npm run buildandnpm run devtoo, add an override topackage.jsonwith the rollup version the message names, then runnpm install:"overrides": { "rollup": "npm:@rollup/wasm-node@4.66.0" }
There is no need to turn Smart App Control off for this.
A refused command says “(request id …)”
Section titled “A refused command says “(request id …)””Every failed call from npx workstudio ends with the request’s id. When you write to work.studio support about it, include that id: it finds the request in our logs.
“Your organisation is at a hosting limit”
Section titled ““Your organisation is at a hosting limit””You have 3 sites, 200 MB stored, or 30 deployments today. Take a site you no longer need offline, or deploy again tomorrow (UTC).
“Hosting is for approved organizations whose owner has verified their email”
Section titled ““Hosting is for approved organizations whose owner has verified their email””Your organization isn’t approved yet, or its owner hasn’t verified their email address.
Sign-in fails on a site you host somewhere else
Section titled “Sign-in fails on a site you host somewhere else”Only workstudio.run addresses are added to sign-in for you. For your own domain, add it under Sign-in › Where it runs. See App SDK.