Skip to content
Back to skills

Sveltekit Project Architect

ASecurity

Production-ready SvelteKit project structure with load functions, form actions, and server routes. Use when scaffolding, structuring, or architecting sveltekit projects.

  • 8 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 8, 2026
developmentjavascripttypescriptgojavanodeapidatabasefullstack

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 8, 2026

npx -y skills add anubhavg-icpl/vibe --skill sveltekit-project-architect --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sveltekit Project Architect?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sveltekit Project Architect
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/anubhavg-icpl-sveltekit-project-architect/badge)](https://www.skillsdirectory.com/skills/anubhavg-icpl-sveltekit-project-architect)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sveltekit-project-architect
description: Production-ready SvelteKit project structure with load functions, form actions, and server routes. Use when scaffolding, structuring, or architecting sveltekit projects.
license: CC-BY-NC-SA-4.0
metadata:
  risk: unknown
  source: community
  kind: mode
  category: project-structure
  tags: [sveltekit, svelte, typescript, fullstack, project-structure]
---

# SvelteKit Project Architect Mode

You are an expert in structuring production-ready SvelteKit applications with file-based routing, load functions, and form actions.

## Project Structure

```text
sveltekit-project/
├── src/
│   ├── app.html                    # HTML template
│   ├── app.d.ts                    # Type declarations
│   ├── hooks.server.ts             # Server hooks
│   ├── hooks.client.ts             # Client hooks
│   │
│   ├── routes/
│   │   ├── +page.svelte            # Home page
│   │   ├── +page.server.ts         # Home loader
│   │   ├── +layout.svelte          # Root layout
│   │   ├── +layout.server.ts       # Root layout loader
│   │   ├── +error.svelte           # Error page
│   │   │
│   │   ├── (auth)/                 # Auth group
│   │   │   ├── +layout.svelte
│   │   │   ├── login/
│   │   │   │   ├── +page.svelte
│   │   │   │   └── +page.server.ts
│   │   │   └── register/
│   │   │       ├── +page.svelte
│   │   │       └── +page.server.ts
│   │   │
│   │   ├── (app)/                  # App group (protected)
│   │   │   ├── +layout.svelte
│   │   │   ├── +layout.server.ts
│   │   │   ├── dashboard/
│   │   │   │   └── +page.svelte
│   │   │   └── users/
│   │   │       ├── +page.svelte
│   │   │       ├── +page.server.ts
│   │   │       ├── [id]/
│   │   │       │   ├── +page.svelte
│   │   │       │   ├── +page.server.ts
│   │   │       │   └── edit/
│   │   │       │       ├── +page.svelte
│   │   │       │       └── +page.server.ts
│   │   │       └── new/
│   │   │           ├── +page.svelte
│   │   │           └── +page.server.ts
│   │   │
│   │   └── api/
│   │       ├── users/
│   │       │   ├── +server.ts
│   │       │   └── [id]/
│   │       │       └── +server.ts
│   │       └── auth/
│   │           └── +server.ts
│   │
│   ├── lib/
│   │   ├── index.ts                # $lib exports
│   │   ├── server/
│   │   │   ├── db.ts               # Database client
│   │   │   ├── auth.ts             # Auth utilities
│   │   │   └── email.ts            # Email service
│   │   ├── components/
│   │   │   ├── ui/
│   │   │   │   ├── Button.svelte
│   │   │   │   ├── Input.svelte
│   │   │   │   ├── Card.svelte
│   │   │   │   └── Modal.svelte
│   │   │   ├── forms/
│   │   │   │   ├── UserForm.svelte
│   │   │   │   └── LoginForm.svelte
│   │   │   └── layout/
│   │   │       ├── Header.svelte
│   │   │       ├── Sidebar.svelte
│   │   │       └── Footer.svelte
│   │   ├── stores/
│   │   │   ├── user.ts
│   │   │   └── theme.ts
│   │   └── utils/
│   │       ├── validation.ts
│   │       └── format.ts
│   │
│   └── params/
│       └── id.ts                   # Param matcher
│
├── static/
│   ├── favicon.png
│   └── images/
│
├── prisma/
│   ├── schema.prisma
│   └── migrations/
│
├── tests/
│   ├── unit/
│   └── e2e/
│
├── .env.example
├── package.json
├── svelte.config.js
├── tsconfig.json
├── vite.config.ts
└── README.md
```

## Core Files

```svelte
<!-- src/routes/+layout.svelte -->
<script lang="ts">
  import { page } from '$app/stores';
  import Header from '$lib/components/layout/Header.svelte';
  import '../app.css';

  export let data;
</script>

<svelte:head>
  <title>{$page.data.title || 'SvelteKit App'}</title>
</svelte:head>

<div class="min-h-screen bg-gray-50">
  <Header user={data.user} />

  <main class="container mx-auto py-8">
    <slot />
  </main>
</div>
```

```typescript
// src/routes/+layout.server.ts
import type { LayoutServerLoad } from "./$types";
import { getUser } from "$lib/server/auth";

export const load: LayoutServerLoad = async ({ cookies }) => {
  const sessionId = cookies.get("session");
  const user = sessionId ? await getUser(sessionId) : null;

  return { user };
};
```

```svelte
<!-- src/routes/(app)/users/+page.svelte -->
<script lang="ts">
  import { enhance } from '$app/forms';
  import { invalidateAll } from '$app/navigation';
  import Button from '$lib/components/ui/Button.svelte';

  export let data;
  export let form;

  let deleting: string | null = null;
</script>

<div class="space-y-6">
  <div class="flex justify-between items-center">
    <h1 class="text-2xl font-bold">Users ({data.total})</h1>
    <a href="/users/new">
      <Button>Add User</Button>
    </a>
  </div>

  {#if form?.error}
    <div class="bg-red-100 text-red-700 p-4 rounded">
      {form.error}
    </div>
  {/if}

  <div class="bg-white rounded-lg shadow overflow-hidden">
    <table class="min-w-full">
      <thead class="bg-gray-50">
        <tr>
          <th class="px-6 py-3 text-left text-sm font-medium">Name</th>
          <th class="px-6 py-3 text-left text-sm font-medium">Email</th>
          <th class="px-6 py-3 text-left text-sm font-medium">Role</th>
          <th class="px-6 py-3 text-right text-sm font-medium">Actions</th>
        </tr>
      </thead>
      <tbody class="divide-y">
        {#each data.users as user (user.id)}
          <tr>
            <td class="px-6 py-4">
              <a href="/users/{user.id}" class="hover:underline">
                {user.name}
              </a>
            </td>
            <td class="px-6 py-4">{user.email}</td>
            <td class="px-6 py-4">
              <span class="px-2 py-1 text-xs rounded-full bg-gray-100">
                {user.role}
              </span>
            </td>
            <td class="px-6 py-4 text-right space-x-2">
              <a href="/users/{user.id}/edit" class="text-blue-600 hover:underline">
                Edit
              </a>
              <form
                method="POST"
                action="?/delete"
                use:enhance={() => {
                  deleting = user.id;
                  return async ({ update }) => {
                    await update();
                    deleting = null;
                  };
                }}
                class="inline"
              >
                <input type="hidden" name="id" value={user.id} />
                <button
                  type="submit"
                  disabled={deleting === user.id}
                  class="text-red-600 hover:underline disabled:opacity-50"
                >
                  {deleting === user.id ? 'Deleting...' : 'Delete'}
                </button>
              </form>
            </td>
          </tr>
        {/each}
      </tbody>
    </table>
  </div>

  <!-- Pagination -->
  {#if data.totalPages > 1}
    <div class="flex justify-center gap-2">
      {#each Array(data.totalPages) as _, i}
        <a
          href="?page={i + 1}"
          class="px-3 py-1 rounded {data.page === i + 1 ? 'bg-blue-600 text-white' : 'bg-gray-200'}"
        >
          {i + 1}
        </a>
      {/each}
    </div>
  {/if}
</div>
```

```typescript
// src/routes/(app)/users/+page.server.ts
import type { PageServerLoad, Actions } from "./$types";
import { fail, redirect } from "@sveltejs/kit";
import { db } from "$lib/server/db";
import { z } from "zod";

const PER_PAGE = 10;

export const load: PageServerLoad = async ({ url }) => {
  const page = parseInt(url.searchParams.get("page") || "1");
  const search = url.searchParams.get("q") || "";

  const where = search
    ? {
        OR: [{ name: { contains: search, mode: "insensitive" } }, { email: { contains: search, mode: "insensitive" } }],
      }
    : {};

  const [users, total] = await Promise.all([
    db.user.findMany({
      where,
      skip: (page - 1) * PER_PAGE,
      take: PER_PAGE,
      orderBy: { createdAt: "desc" },
    }),
    db.user.count({ where }),
  ]);

  return {
    users,
    total,
    page,
    totalPages: Math.ceil(total / PER_PAGE),
  };
};

export const actions: Actions = {
  delete: async ({ request }) => {
    const formData = await request.formData();
    const id = formData.get("id") as string;

    try {
      await db.user.delete({ where: { id } });
      return { success: true };
    } catch (error) {
      return fail(500, { error: "Failed to delete user" });
    }
  },

  create: async ({ request }) => {
    const formData = await request.formData();
    const data = Object.fromEntries(formData);

    const schema = z.object({
      name: z.string().min(2),
      email: z.string().email(),
      role: z.enum(["user", "admin"]),
    });

    const result = schema.safeParse(data);
    if (!result.success) {
      return fail(400, {
        errors: result.error.flatten().fieldErrors,
        data,
      });
    }

    const user = await db.user.create({ data: result.data });
    throw redirect(303, `/users/${user.id}`);
  },
};
```

```typescript
// src/hooks.server.ts
import type { Handle } from "@sveltejs/kit";
import { db } from "$lib/server/db";

export const handle: Handle = async ({ event, resolve }) => {
  // Get session from cookie
  const sessionId = event.cookies.get("session");

  if (sessionId) {
    const session = await db.session.findUnique({
      where: { id: sessionId },
      include: { user: true },
    });

    if (session && session.expiresAt > new Date()) {
      event.locals.user = session.user;
    } else {
      // Clear expired session
      event.cookies.delete("session", { path: "/" });
    }
  }

  // Protected routes
  if (event.url.pathname.startsWith("/dashboard") || event.url.pathname.startsWith("/users")) {
    if (!event.locals.user) {
      return new Response(null, {
        status: 303,
        headers: { location: "/login" },
      });
    }
  }

  return resolve(event);
};
```

```typescript
// src/routes/api/users/+server.ts
import type { RequestHandler } from "./$types";
import { json } from "@sveltejs/kit";
import { db } from "$lib/server/db";

export const GET: RequestHandler = async ({ url }) => {
  const page = parseInt(url.searchParams.get("page") || "1");
  const limit = parseInt(url.searchParams.get("limit") || "10");

  const users = await db.user.findMany({
    skip: (page - 1) * limit,
    take: limit,
    select: {
      id: true,
      name: true,
      email: true,
      role: true,
      createdAt: true,
    },
  });

  return json({ users });
};

export const POST: RequestHandler = async ({ request }) => {
  const data = await request.json();

  const user = await db.user.create({
    data,
    select: {
      id: true,
      name: true,
      email: true,
      role: true,
    },
  });

  return json(user, { status: 201 });
};
```

```javascript
// svelte.config.js
import adapter from "@sveltejs/adapter-node";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";

/** @type {import('@sveltejs/kit').Config} */
const config = {
  preprocess: vitePreprocess(),
  kit: {
    adapter: adapter(),
    alias: {
      $components: "src/lib/components",
    },
  },
};

export default config;
```

## Best Practices

- Use load functions for data fetching
- Use form actions for mutations
- Group routes with (parentheses)
- Use +page.server.ts for server-only code
- Implement hooks for auth/middleware
- Use $lib for shared code
- Validate with Zod on server
- Use enhance for progressive enhancement

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…