1.3 What you can build with it (and what it deliberately leaves out)
RS2 is opinionated about its sweet spot. Knowing where it shines — and where it intentionally stops — saves you from fighting the grain.
What it's good at
HTTP/JSON backends for apps and integrations. The common shape of a modern backend — store some files, store some validated records, let users log in, expose a few queries, glue in a third-party API — is exactly what RS2 assembles from configuration. A front-end developer can stand up a real backend without a separate server codebase.
Backend-for-frontend and API composition. Pipelines let you fan out to several mounts, reshape the results with JSONata, branch on conditions, and return one tidy response — so the browser makes one call instead of six. CORS, caching, and auth are configured in one place and apply uniformly.
Static sites and single-page apps. A file mount in static-site mode serves
a default document for directory requests and falls back to your app shell for
client-side routes, with CDN-friendly cache headers — no separate web server.
Safely running other people's (or AI-generated) code. Custom services run in a hard sandbox with default-deny capabilities, wall-clock and memory limits, and a per-tenant circuit breaker. You can host untrusted or experimental code next to trusted services without it being able to escape its grants or starve its neighbors. This is a core design goal, demonstrated under load (see Part 9).
Wrapping third-party SDKs. The JavaScript engine ships a compatibility layer that runs many popular API-wrapper SDKs unmodified after bundling — Stripe, OpenAI, Anthropic, Supabase, Octokit, Resend, and more. You write a small handler, grant it outbound HTTP to the host you need, and deploy.
Multi-tenant SaaS. One node cleanly isolates many tenants — separate data, users, config, and resource budgets — resolved by domain or subdomain.
What it deliberately leaves out (v1)
These omissions are intentional for the current version, not oversights. Most exist because they conflict with the sandboxing and statelessness guarantees, or are planned for a later milestone.
Real wall-clock timers and background work. Inside a custom service, timers are virtual: when your handler is otherwise idle, pending timers fast-forward (so an SDK's retry backoff completes instantly). There is no event loop and no way to do real-time waiting or run work after the response is sent. The host can invoke a mount on an interval or UTC cron schedule (7.11), but each tick is still an ordinary bounded request; durable queues and detached background jobs are out of scope for v1.
Long-lived connections. WebSocket connections are not supported
(WebSocket/ReadableStream are presence-only stubs that throw on real use).
Request/response is the model. Custom JS can opt into chunked request or
response bodies through RS2's own ctx.readBody/ctx.beginStream API (8.2),
and can open gated raw TCP/TLS sockets to speak non-HTTP protocols
(Postgres, Redis, Mongo). A socket lives only for the request that opened it,
except inside a resident adapter that pools it.
node: built-ins and native addons. Custom JS runs against an explicit,
documented API surface — not full Node.js. Dependencies must be bundled at
build time; nothing resolves modules at runtime. SDKs whose transport reaches
for node:os/node:path (e.g. axios-based clients) won't run.
Binary multipart uploads and zip/unzip in pipelines. Text-based form data works; binary multipart and archive split/join are not in v1.
Persistent in-memory state between requests. Each custom-service invocation
gets a fresh sandbox — globals do not survive. Durable state goes through the
ctx.state capability or the data store, not module-level variables.
Some storage backends, for now. The file store and data store ship with
local-filesystem, durable file-data, and in-memory adapters; there is no
built-in S3 or SQL-database adapter. You can, however, back a
file/data/query mount with a
loadable storage adapter — your own deployed code speaking the backend's wire
protocol (8.9) — and the project includes deployable MongoDB data/query adapters
plus tested Redis examples to start from.
How to think about the boundary
The unifying rule: RS2 is a stateless, sandboxed, request/response runtime. If a feature needs long-lived connections, real background time, or ambient access to the host machine, it's either out of scope or routed through an explicit capability. If it fits "transform an HTTP message, possibly by calling other messages," it's squarely in scope.
When you hit an edge — a static-site nicety, an email send, a webhook receiver — the usual answer is a pipeline, wrapper, proxy, provider adapter, or small custom service, not a missing general-purpose server. Parts 7 and 8 cover those choices.
← Previous: 1.2 The mental model · Manual home · Next: 1.4 How this manual is organized →