Run a Node web service that scales to zero

· the plori team

Ask a plori agent to build and test a small Node HTTP service on its persistent disk. After you review and activate it, the service gets its own plori.site address. The first request boots an isolated container; after a short idle window, that container stops and runtime billing stops with it.

The source directory persists on the agent's disk. Each activation or redeploy takes a snapshot of that directory for the service container. Editing the source does not change the live service until you redeploy it.

One service, through its full lifecycle

The owner activates the tested app, then verifies cold wake, idle sleep, snapshot isolation, redeploy, and runtime billing.

  1. 01

    Build

    Server + manifest

    Tested on disk

  2. 02

    Activate

    Owner reviews first

    Public or private

  3. 03

    Wake + sleep

    Request, then idle

    Scale to zero

  4. 04

    Redeploy

    Snapshot v2

    Next request boots

What do you need?

  • A registered plori account and one agent.
  • A server that listens on process.env.PORT or the port declared in plori-service.json.
  • A globally unique name for the service's <name>.plori.site address.
  • Enough credits for the service's running minutes. A service costs $0.01 per started minute while its container is running, including the short idle window before it sleeps. It uses no runtime credits while asleep.

This example uses only Node's built-in http module. It needs no package install, database, secret, or external service.

What prompt should you give plori?

This is the prompt used to build the production test service. It asks the agent to stop after handing you a ready-to-activate card because activation makes the endpoint reachable and starts runtime billing.

plori prompt
Create a minimal dependency-free Node HTTP service in /app. Write /app/server.js so it listens on process.env.PORT || 3000 and returns JSON with exactly {"ok":true,"version":"v1","message":"plori scale-to-zero service"} for every request. Write /app/plori-service.json with start "node server.js" and port 3000.

Test the service locally on an available port, confirm the exact response, and stop the test process. Do not publish or activate it yourself. When the files and local test are complete, use the product's ready-to-activate handoff for /app as a Service so I can review and activate it in the UI. Do not add dependencies, databases, external services, secrets, or background processes.

What does the agent create?

The app directory contains the server and a small service manifest:

{
  "start": "node server.js",
  "port": 3000
}

start is the command the service container runs from the app directory. port must be between 1024 and 65535, and the server must listen on it. The manifest can also declare non-secret environment values and snapshot exclusions. Do not put API keys or other secrets in the manifest; it is a file on the agent's disk.

The agent tests the process before handoff and then stops it. A successful local test shows that the code can answer on the declared interface. It does not publish the app or prove the production cold-start path.

How do you activate the service?

  1. Open the Ready to activate card in the agent conversation.
  2. Check that the app directory is /app and the publish mode is Service.
  3. Choose Private or Public. Private is the safer default while you test.
  4. Click Activate service. Activation is always an owner action; the agent cannot do it for you.
  5. Open the service. The first request boots the container and may include a brief cold start. The owner page changes from Asleep to Running.

You can reach the same dialog from Files: open plori-service.json, click Publish as a website, and keep Service selected. The full UI path is in Publish a site.

What did the production run prove?

On 30 August 2026, we ran this lifecycle against production with a dedicated test agent. The owner activated a public service, verified the v1 JSON response, left it without traffic for more than 140 seconds, and saw the owner status change to Asleep. The next request returned HTTP 200 with the same body in 2.888 seconds and changed the status to Running.

We then changed the source response from v1 to v2 on the agent's disk. Before redeploy, the public endpoint still returned v1. After the owner clicked Redeploy, the service returned the exact v2 JSON on its next request in 2.708 seconds:

{ "ok": true, "version": "v2", "message": "snapshot redeploy works" }

The service's own ledger references recorded ten $0.01 runtime charges, totaling $0.10 across two v1 runs and the redeployed v2 run. Those entries show that live service usage reached the owner-visible ledger; they are not a forecast for a different app or traffic pattern.

Why did the endpoint keep serving v1 after the source changed?

A service runs a deployed snapshot, not the live agent disk. This keeps the running app separate from files the agent may still be editing. It also gives you a clear release point:

  1. Change and test the source on the agent's persistent disk.
  2. Open Site settings and click Redeploy.
  3. The current container stops.
  4. The next request boots a new container from the new snapshot.

If a change must not reach users yet, leave it on disk and do not redeploy. Switching a service between public and private changes access immediately, but it does not create a new code snapshot.

What persists when the service sleeps?

The source files on the agent's disk persist. The running service container does not. Files that the server writes inside its own container disappear when that container is replaced or scaled to zero. Use an external database or object store when application data must survive restarts.

The current service shape is deliberately small:

  • scale-to-zero only; there is no always-on setting;
  • one plori.site address per agent, backed by either a static site or a service;
  • no managed database, cache, custom domain, or buildpack;
  • a brief cold start on the first request after sleep;
  • runtime charged by started minute while the container is live, including its idle window.

For a browser-only page, use a static site instead. Static files update as soon as they are saved, keep serving while the agent sleeps, and have no service-runtime charge.

How do you verify your own service safely?

Use a versioned response or health endpoint, then check each boundary separately:

  1. Test the server locally and stop the test process.
  2. Activate it privately first and verify the exact response.
  3. Wait for the owner page to show Asleep, then request it again and confirm a cold wake.
  4. Change the version on disk and confirm the endpoint still serves the old snapshot.
  5. Redeploy, request it again, and confirm the new version.
  6. Open Dashboard → Billing and look for Service entries.
  7. Deactivate the service when the test is over.

The credits guide explains the shared balance and ledger. See pricing for the current plans and other usage rates.

When should you deactivate it?

Deactivate a test endpoint as soon as you finish. Open Site settings and click Deactivate. The URL stops serving, and the reserved name stays attached to that agent. Deleting the agent also removes its source files, so download anything you need first.

Build it in plori

Open a plori agent and paste the prompt. Review the generated server and manifest, then activate the service yourself from the ready card.