snoozestack
Functions

Your functions are the boundary.

Clients call code you own. Every entry point — an HTTP call, a queue message, a cron schedule, a webhook, an agent's tool call — lands on the same committed handler, holding only what it declared.

snoozestack/
export default async function (req, app) {
const user = app.auth.user
return Response.json(app.db.query(
"select * from notes where user_id = ?", [user.id]))
}
01

One handler contract

The same request and response shape locally and hosted, whatever triggered it.

02

Capabilities, not credentials

A function reaches what it declares and nothing else — the blast radius is in the diff.

03

Background work included

Queues, schedules, and webhooks are declared beside the functions they run.

Functions, running

local development
await snoozestack.functions.call( "list-rounds", { season: 2026 } )
→ [ { id: 1, score: 72 }, { id: 2, score: 68 }, ]
04

One handler, every trigger

Write the behavior once and decide how it can be reached. An HTTP call from your app, a queue message, a cron schedule, an inbound webhook, and an agent's tool call all arrive at the same committed handler with the same request shape.

  • Web-standard request and response objects, locally and hosted
  • Background work shares the code path that serves requests
  • Retries, dead letters, and timing are all testable on your machine
snoozestack/project.toml
[[functions]]
name = "post-round"
entry = "post-round/index.ts"
auth = "required"
capabilities = ["db", "storage"]

[[queues]]
name = "new-rounds"
functions = ["notify"]
05

Only the capabilities it declares

A function receives a scoped context as its second argument. The database, storage, push, secrets, and Signals appear only when the project says they should — so a reviewer can see a function's blast radius without reading its body.

  • No ambient credentials for code to reach for
  • An undeclared capability isn't restricted, it simply isn't there
  • Capability changes show up in code review as a one-line diff
snoozestack/functions/post-round/index.ts
export default async function handler(req, capabilities) {
  const user = capabilities.auth.user;
  const { strokes } = await req.json();

  capabilities.db.query(
    "insert into rounds (user_id, strokes) values (?, ?)",
    [user.id, strokes],
  );
  return new Response("ok");
}

Built for real applications

What teams build with Functions.

Anything that needs a secret

A model, a payment provider, an email service. The key is declared for that one function, and the client never sees it.

Rules the client can't be trusted with

Applying a discount, awarding credits, moving money. The client asks; the function decides, validates, and writes.

Work that outlives the request

Enqueue it and answer immediately, or put it on a schedule — the same handler, reached a different way.

Committed functions give every client a clear, durable boundary around application behavior.

Why Snoozestack →

More of the platform