Early access. New accounts need approval, so signing up puts you on a waitlist for now.

Documentation

Doclet runs small web apps and decides who can open them.

Quickstart

$npm install -g doclet-cli
$doclet login
$doclet deploy

doclet login opens your browser to approve the CLI. doclet deploy packs the current folder, uploads it, installs dependencies and starts it, then prints the URL. The first deploy creates the app, named after the folder; later deploys update it.

Doclet is in early access. New accounts need approval, so signing up puts you on a waitlist, and we email you when you are in.

What you can deploy

Doclet picks how to run your folder by looking for, in order:

  • a start command in doclet.json
  • a start script in package.json (dependencies are installed, and npm run build runs first if you have one)
  • server.js, index.js or index.ts
  • an index.html, served as a static site

node_modules, .git and .env files are never uploaded. Your .gitignore is respected; add a .docletignore for anything else.

doclet.json

Run doclet init in a project folder to write one. Everything in it is optional, and you can commit it so teammates deploy the same way.

{
  "name": "invoice-tracker",
  "workspace": "acme",
  "start": "node server.js",
  "build": false,
  "static": "dist",
  "access": "workspace",
  "jobs": [{ "name": "nightly", "schedule": "0 3 * * *", "path": "/api/nightly" }]
}

name is the app’s address and name, workspace where it goes, start how to run it, build: false skips npm run build, and static is the folder served for a static site. jobs is covered under Scheduled jobs.

access is restricted, workspace or public, and applies once, when the app is first created. Changing sharing later in the dashboard is never overwritten. Public is available on paid plans. Flags such as --app and --workspace win over the file.

In an empty folder, doclet init --template node|static|notes creates a small working app to start from; notes keeps its notes in SQLite.

How your app runs

Your app is a normal process. Doclet gives it:

  • PORT: listen here, on all interfaces
  • DATA_DIR: a persistent directory. SQLite files and uploads written here survive restarts, sleeps and redeploys. Everything else on disk is rebuilt on each deploy.
  • Node 22, which includes the built-in node:sqlite module.

Apps sleep when idle and wake on the next request, so the first visit after a quiet spell takes a few seconds. Keep in-memory state to things you can rebuild.

If your app stops. Doclet adds one small script to your HTML pages. When someone returns to a tab that has been in the background, it checks that the app still answers. If it doesn’t, the page is covered by a notice with a Reload button, instead of looking fine while nothing works. The script only asks when the tab comes back into view, so an open tab never keeps an app awake. To opt a page out, send the response header x-doclet-watch: off.

Add favicon.svg (or .ico, .png) to your project and Doclet uses it as the app’s icon. You can also choose a file or upload an image in the app’s settings. An app with no icon shows Doclet’s in the browser tab.

Knowing who's visiting

Visitors are signed in before a request reaches your app, and the edge adds these headers. Any copies a client sends are discarded, so you can trust them.

x-doclet-user-email   maya@acme.co
x-doclet-user-id      stable id for this person
x-doclet-user-name    URL-encoded display name, if they've set one

On a public app visitors are anonymous and these headers are absent.

Environment variables

doclet env set API_KEY=sk-live-... GREETING=hello --redeploy
doclet env list
doclet env unset API_KEY

Values are write-only: they can be replaced but not read back. They apply the next time the app starts, which --redeploy does immediately. Names Doclet owns (PORT, DATA_DIR, DOCLET_*) can’t be overridden.

Sharing

New apps are private. People who can always open an app: its creator, and workspace owners and admins. Everyone else needs one of:

  • Shared by email. They sign in with that address, using a one-time code or a password.
  • Workspace. Every member of the workspace.
  • Public. Anyone with the link, no sign-in. Available on paid plans.
doclet share maya@acme.co dev@acme.co
doclet share --workspace-wide
doclet share --public
doclet unshare maya@acme.co

Removing access takes effect within seconds, including for people who already have the app open. If an app is paused, the Share dialog says so, because the people you share it with will see a paused page.

Members and viewers. Members belong to your workspace. They create and deploy apps, and they are what your plan is priced on. A viewer is anyone an app is shared with who isn’t a member, such as a client, a contractor, or a teammate at another company. Viewers are free and unlimited.

Previews

A preview puts your current code at its own address, next to the real app, so you can look at a change before it ships. It never touches the live app or its data.

doclet deploy --preview            # named after your git branch
doclet deploy --preview new-login  # or pick a name
doclet previews                    # list them
doclet previews rm new-login
  • A preview of crm called new-login lives at crm-new-login.<workspace>.doclet.site. Deploying to the same name again updates it.
  • It is open to exactly the people the app is open to, and changes to the app’s sharing apply to it immediately.
  • It runs with the app’s environment variables, plus DOCLET_PREVIEW=1 and DOCLET_PREVIEW_NAME so your code can tell. Its data is separate: a preview starts with an empty DATA_DIR.
  • The app has to exist first, previews don’t count toward your app limit, and they don’t run scheduled jobs. A preview with no deploy for 14 days is removed. Free allows 1 preview per app, Pro 3, Team 10.

Scheduled jobs

For work that should happen on a schedule, like a nightly report or a sync, list it in doclet.json. At each time Doclet wakes the app if it is asleep and sends it an HTTP request. Your app does the work in that request.

"jobs": [
  { "name": "nightly-report", "schedule": "0 3 * * *", "path": "/api/report" },
  { "schedule": "*/15 * * * *", "path": "/api/sync", "method": "GET" }
]
  • schedule is a standard five-field cron expression in UTC (minute, hour, day of month, month, day of week), or @hourly, @daily, @weekly, @monthly.
  • path is a path on your app. method is POST unless you say GET. name is optional.
  • The request carries x-doclet-job: <name>. Only Doclet can set it, so you can use it to refuse everyone else. There is no signed-in user, so the user headers are absent.
  • Jobs follow the code that is live: each deploy replaces the list, and a rollback restores the earlier one. Mistakes (a bad schedule, a reserved path) are shown in the deploy log, and the rest still run.

A run counts as success if your app answers below 400. If the app is asleep, Doclet waits up to about 90 seconds for it to start, then fails the run. A job that is still running is not started again. The dashboard’s Settings tab shows each job’s next and last run, and has a Run now button. After three failed runs in a row, whoever created the app gets one email. Missed runs, for example during an outage, are skipped rather than replayed.

Jobs count as requests against your plan. Free allows 1 job per app, running at most hourly. Pro allows 5, at most every 5 minutes. Team allows 20, every minute.

Custom domains

Every app has an address under doclet.site. On Pro and Team you can also serve it from a domain you own, like docs.acme.com. Both addresses keep working, and sharing rules are the same on either.

  • Open the app, then Settings, then Custom domain, and enter the domain.
  • Add the records Doclet shows you where you manage DNS: a CNAME to Doclet (or A and AAAA records for a bare domain like acme.com), and a TXT record at _doclet.<your domain> that proves it’s yours.
  • Doclet checks every couple of minutes, or press Check now. Once both records are found it issues an HTTPS certificate, which takes a minute or two.

If your DNS host proxies traffic (Cloudflare’s orange cloud, for example), turn the proxy off for this record. Each app can have up to 2 custom domains on Pro and 5 on Team. If a workspace moves back to Free, its custom domains stop serving until it upgrades again, and nothing is deleted.

Logs and rollbacks

doclet logs             # the last 100 lines your app printed
doclet logs -f          # keep watching
doclet logs --system    # include startup and health messages
doclet history          # recent deploys, newest first
doclet rollback         # put the previous version back
doclet rollback 3       # or a specific one

The same logs are in the dashboard’s Logs tab, with a switch to show system messages. They show recent output only, and only people who can manage the app can read them, because apps sometimes print what visitors send them.

A rollback runs an earlier version’s code again as a new deploy. Environment variables aren’t versioned, so it uses the ones set now. Repeating doclet rollback keeps going back rather than undoing itself. In the dashboard, open any version under Deployments to see its log and view its source code. If a deploy fails, whoever started it gets an email with the error and the commands above.

Deploying from CI

Create a token under Account, Access tokens (optionally limited to one workspace), store it as a secret, and:

DOCLET_TOKEN=dl_... doclet deploy --workspace acme --app invoices -m "$GITHUB_SHA"

CLI reference

doclet login / logout / whoami
Manage the CLI's sign-in
doclet init [--template name]
Write doclet.json, or start from a template
doclet deploy [dir] [-m note]
Upload and start the app
doclet list
Apps in the workspace
doclet status
State, URL, sharing, variables
doclet open
Open the app in a browser
doclet share / unshare
Control who can open it
doclet env set|unset|list
Environment variables
doclet logs [-f] [-n lines] [--system]
What the app printed recently
doclet history / rollback [n]
Deploy history; restore an earlier version
doclet deploy --preview [name]
Deploy to a preview address instead of the live app
doclet previews [rm name]
List previews, or delete one
doclet pause / resume
Take it offline without deleting
doclet delete
Remove the app and its data

Every command accepts --workspace and --app. After the first deploy the folder remembers its app in .doclet/project.json.

Limits

Plans are priced per member, and your allowances grow with every member you add. Pro and Team have no limit on the number of apps; what’s metered is usage. A Pro workspace gets 250K requests and 25 GB of bandwidth per member each month, so ten members get 2.5M requests and 250 GB. The Free plan is a flat 25K requests and 1 GB of bandwidth a month, with up to 3 apps and 3 members.

Storage per app and upload size are fixed by plan. When a workspace reaches its monthly requests or bandwidth, visitors see a “limit reached” page until the 1st (UTC) or until you add members or upgrade. Workspace owners and admins get an email at 80% and again at 100%, once each per month. Change plan any time from Plans in the dashboard. Past 50 members, workspaces move to a custom plan. Email hello@doclet.cloud and we’ll set one up.