Documentation
Doclet runs small web apps and decides who can open them.
Quickstart
npm install -g doclet-clidoclet logindoclet deploydoclet 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
startcommand indoclet.json - a
startscript inpackage.json(dependencies are installed, andnpm run buildruns first if you have one) server.js,index.jsorindex.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 interfacesDATA_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:sqlitemodule.
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.
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
crmcallednew-loginlives atcrm-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=1andDOCLET_PREVIEW_NAMEso your code can tell. Its data is separate: a preview starts with an emptyDATA_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" }
]scheduleis a standard five-field cron expression in UTC (minute, hour, day of month, month, day of week), or@hourly,@daily,@weekly,@monthly.pathis a path on your app.methodis POST unless you say GET.nameis 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
CNAMEto Doclet (orAandAAAArecords for a bare domain likeacme.com), and aTXTrecord 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.