# Full Stack Apps

> Build full-stack Cloudflare apps with Workers, static assets, SSR, API routes, SPA/hybrid rendering, cache headers, and binding-backed data. Use when implementing frontend-plus-backend applications on Cloudflare Workers.

- Skill: `zllovesuki/full-stack-apps` (Agent Skill)
- Install (CLI): `npx skillmds@latest add zllovesuki/full-stack-apps`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zllovesuki/full-stack-apps/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: zllovesuki (https://skillmd.com/u/zllovesuki)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/zllovesuki/full-stack-apps

---

# Full-Stack Apps

Use this skill when a Cloudflare Worker serves both frontend assets and backend routes.

## Rendering decision

| Page type | Prefer | Notes |
|---|---|---|
| Marketing/docs/static content | Static assets | Lowest cost and operational complexity |
| Personalized dashboard | SSR or API + SPA | Fetch user data through bindings |
| Highly interactive app | SPA + API routes | Keep data APIs clean and cacheable where possible |
| Mixed site | Hybrid | Static shell with SSR islands or API-backed hydration |

## Route layout pattern

```ts
export interface Env {
  ASSETS: Fetcher;
  DB: D1Database;
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);

    if (url.pathname.startsWith("/api/")) {
      return api(request, env, ctx);
    }

    // Serve compiled frontend assets.
    return env.ASSETS.fetch(request);
  }
} satisfies ExportedHandler<Env>;
```

## API route pattern

```ts
async function api(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
  const url = new URL(request.url);

  if (url.pathname === "/api/todos" && request.method === "GET") {
    const todos = await env.DB.prepare(
      "SELECT id, title, completed FROM todos ORDER BY created_at DESC LIMIT 100"
    ).all<Todo>();
    return Response.json(todos.results);
  }

  return Response.json({ error: "not_found" }, { status: 404 });
}
```

## Cache policy

- Static hashed assets: long cache TTL and immutable headers.
- HTML shell/SSR: short TTL or no-store if personalized.
- API responses: cache only when auth, tenant, and freshness rules are explicit.
- Never cache user-specific HTML or JSON without varying by user/session/tenant.

## State placement

- D1: relational records for app data.
- Durable Objects: shared live state such as a room, document, cart, or session coordinator.
- R2: uploaded files, generated exports, media.
- KV: cached config, flags, denormalized public reads.
- Queues/Workflows: background jobs triggered by UI actions.

## Review checklist

- [ ] Asset route cannot shadow API routes unexpectedly.
- [ ] CORS and authentication are enforced for APIs.
- [ ] SSR code does not assume Node server globals.
- [ ] Data-fetching runs in parallel where safe.
- [ ] Error responses are user-safe and structured.
- [ ] Build output path matches the `assets.directory` binding.

