Builds full-stack applications with SolidStart, combining Solid's fine-grained reactivity with server functions and multiple rendering modes. Use when creating SolidJS applications with SSR/SSG, server functions, or when user mentions SolidStart or Solid meta-framework.
Builds full-stack SolidJS applications with SSR, SSG, and server functions. Use when creating SolidStart projects or when user mentions SolidStart, Solid meta-framework, or fine-grained reactivity with server-side rendering.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/server-patterns.mdreferences/streaming-ssr.mdMeta-framework for SolidJS combining fine-grained reactivity with full-stack capabilities, built on Vinxi (Vite + Nitro).
# Create new project
npm init solid@latest my-app
# Select:
# - SolidStart
# - TypeScript (recommended)
# - SSR (default)
cd my-app
npm install
npm run dev
my-app/
app.config.ts # App configuration
src/
app.tsx # Root component
entry-client.tsx # Client entry
entry-server.tsx # Server entry
routes/ # File-based routing
index.tsx # /
about.tsx # /about
blog/
index.tsx # /blog
[slug].tsx # /blog/:slug
api/
users.ts # /api/users endpoint
components/ # Shared components
lib/ # Utilities
public/ # Static assets
// app.config.ts
import { defineConfig } from "@solidjs/start/config";
export default defineConfig({
server: {
preset: "vercel", // netlify, cloudflare-pages, node, etc.
},
vite: {
// Vite configuration
plugins: [],
},
});
// src/routes/index.tsx
export default function Home() {
return (
<main>
<h1>Welcome to SolidStart</h1>
<p>Fine-grained reactivity meets full-stack</p>
</main>
);
}
routes/
index.tsx # /
about.tsx # /about
blog.tsx # /blog (layout)
blog/
index.tsx # /blog
[slug].tsx # /blog/:slug
[...rest].tsx # /blog/* (catch-all)
(auth)/ # Route group (no URL segment)
login.tsx # /login
register.tsx # /register
// src/routes/blog/[slug].tsx
import { useParams } from "@solidjs/router";
export default function BlogPost() {
const params = useParams<{ slug: string }>();
return (
<article>
<h1>Post: {params.slug}</h1>
</article>
);
}
// src/routes/blog.tsx - Layout for /blog/*
import { RouteSectionProps } from "@solidjs/router";
export default function BlogLayout(props: RouteSectionProps) {
return (
<div class="blog-layout">
<aside>
<nav>Blog Navigation</nav>
</aside>
<main>{props.children}</main>
</div>
);
}
import { A, useNavigate } from "@solidjs/router";
function Navigation() {
const navigate = useNavigate();
return (
<nav>
{/* Link component with active states */}
<A href="/" activeClass="active" end>Home</A>
<A href="/blog" activeClass="active">Blog</A>
{/* Programmatic navigation */}
<button onClick={() => navigate("/dashboard")}>
Go to Dashboard
</button>
</nav>
);
}
query// src/routes/users/index.tsx
import { createAsync, query } from "@solidjs/router";
import { For, Suspense } from "solid-js";
// Define server query
const getUsers = query(async () => {
"use server";
const users = await db.users.findMany();
return users;
}, "users");
export default function UsersPage() {
const users = createAsync(() => getUsers());
return (
<Suspense fallback={<div>Loading users...</div>}>
<ul>
<For each={users()}>
{(user) => <li>{user.name}</li>}
</For>
</ul>
</Suspense>
);
}
// src/routes/users/[id].tsx
import { createAsync, query, useParams } from "@solidjs/router";
import { Show, Suspense } from "solid-js";
const getUser = query(async (id: string) => {
"use server";
const user = await db.users.findUnique({ where: { id } });
return user;
}, "user");
export default function UserPage() {
const params = useParams<{ id: string }>();
const user = createAsync(() => getUser(params.id));
return (
<Suspense fallback={<div>Loading...</div>}>
<Show when={user()} fallback={<div>User not found</div>}>
{(u) => (
<div>
<h1>{u().name}</h1>
<p>{u().email}</p>
</div>
)}
</Show>
</Suspense>
);
}
// src/routes/products/[id].tsx
import { createAsync, query, type RouteDefinition } from "@solidjs/router";
const getProduct = query(async (id: string) => {
"use server";
return await db.products.findUnique({ where: { id } });
}, "product");
// Preload on hover/focus
export const route = {
preload: ({ params }) => getProduct(params.id),
} satisfies RouteDefinition;
export default function ProductPage() {
const params = useParams<{ id: string }>();
const product = createAsync(() => getProduct(params.id));
return (
<Suspense>
<Show when={product()}>
{(p) => <ProductDetail product={p()} />}
</Show>
</Suspense>
);
}
// src/routes/contact.tsx
import { action, useSubmission } from "@solidjs/router";
const submitContact = action(async (formData: FormData) => {
"use server";
const email = formData.get("email") as string;
const message = formData.get("message") as string;
await sendEmail({ to: "support@example.com", from: email, body: message });
return { success: true };
});
export default function ContactPage() {
const submission = useSubmission(submitContact);
return (
<form action={submitContact} method="post">
<input name="email" type="email" required />
<textarea name="message" required />
<button type="submit" disabled={submission.pending}>
{submission.pending ? "Sending..." : "Send"}
</button>
<Show when={submission.result?.success}>
<p class="success">Message sent!</p>
</Show>
</form>
);
}
import { action, redirect } from "@solidjs/router";
import { z } from "zod";
const createPostSchema = z.object({
title: z.string().min(1).max(100),
content: z.string().min(10),
});
const createPost = action(async (formData: FormData) => {
"use server";
const data = Object.fromEntries(formData);
const result = createPostSchema.safeParse(data);
if (!result.success) {
return { errors: result.error.flatten().fieldErrors };
}
const post = await db.posts.create({
data: result.data,
});
throw redirect(`/blog/${post.slug}`);
});
export default function NewPost() {
const submission = useSubmission(createPost);
const errors = () => submission.result?.errors;
return (
<form action={createPost} method="post">
<div>
<input name="title" placeholder="Title" />
<Show when={errors()?.title}>
<span class="error">{errors()!.title![0]}</span>
</Show>
</div>
<div>
<textarea name="content" placeholder="Content" />
<Show when={errors()?.content}>
<span class="error">{errors()!.content![0]}</span>
</Show>
</div>
<button type="submit">Create Post</button>
</form>
);
}
import { action, revalidate } from "@solidjs/router";
const deletePost = action(async (id: string) => {
"use server";
await db.posts.delete({ where: { id } });
// Revalidate cached queries
revalidate("posts");
revalidate("user-posts");
});
// Usage
<button onClick={() => deletePost(post.id)}>Delete</button>
// src/routes/api/users.ts
import { json } from "@solidjs/router";
import type { APIEvent } from "@solidjs/start/server";
export async function GET(event: APIEvent) {
const users = await db.users.findMany();
return json(users, {
headers: {
"Cache-Control": "public, max-age=60",
},
});
}
// src/routes/api/users.ts
export async function POST(event: APIEvent) {
const body = await event.request.json();
const user = await db.users.create({
data: body,
});
return json(user, { status: 201 });
}
// src/routes/api/users/[id].ts
import { json } from "@solidjs/router";
import type { APIEvent } from "@solidjs/start/server";
export async function GET(event: APIEvent) {
const id = event.params.id;
const user = await db.users.findUnique({ where: { id } });
if (!user) {
return json({ error: "Not found" }, { status: 404 });
}
return json(user);
}
export async function DELETE(event: APIEvent) {
const id = event.params.id;
await db.users.delete({ where: { id } });
return new Response(null, { status: 204 });
}
// src/middleware.ts
import { createMiddleware } from "@solidjs/start/middleware";
export default createMiddleware({
onRequest: [
// Authentication middleware
async (event) => {
const session = event.request.headers.get("Authorization");
if (event.request.url.includes("/api/protected")) {
if (!session) {
return new Response("Unauthorized", { status: 401 });
}
}
},
// Logging middleware
async (event) => {
console.log(`${event.request.method} ${event.request.url}`);
},
],
});
// src/lib/auth.ts
import { query, action, redirect } from "@solidjs/router";
import { getRequestEvent } from "solid-js/web";
export const getUser = query(async () => {
"use server";
const event = getRequestEvent()!;
const session = event.request.headers.get("cookie");
if (!session) return null;
return await validateSession(session);
}, "user");
export const login = action(async (formData: FormData) => {
"use server";
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const user = await authenticateUser(email, password);
if (!user) {
return { error: "Invalid credentials" };
}
const event = getRequestEvent()!;
// Set cookie
event.response.headers.set(
"Set-Cookie",
`session=${user.sessionId}; HttpOnly; Path=/`
);
throw redirect("/dashboard");
});
export const logout = action(async () => {
"use server";
const event = getRequestEvent()!;
event.response.headers.set(
"Set-Cookie",
"session=; HttpOnly; Path=/; Max-Age=0"
);
throw redirect("/");
});
// src/routes/blog/[slug].tsx
import { Title, Meta } from "@solidjs/meta";
import { createAsync, query, useParams } from "@solidjs/router";
const getPost = query(async (slug: string) => {
"use server";
return await db.posts.findUnique({ where: { slug } });
}, "post");
export default function BlogPost() {
const params = useParams<{ slug: string }>();
const post = createAsync(() => getPost(params.slug));
return (
<Suspense>
<Show when={post()}>
{(p) => (
<>
<Title>{p().title} | My Blog</Title>
<Meta name="description" content={p().excerpt} />
<Meta property="og:title" content={p().title} />
<Meta property="og:description" content={p().excerpt} />
<Meta property="og:image" content={p().image} />
<article>
<h1>{p().title}</h1>
<div innerHTML={p().content} />
</article>
</>
)}
</Show>
</Suspense>
);
}
// src/routes/[...404].tsx
export default function NotFound() {
return (
<main>
<h1>404 - Page Not Found</h1>
<A href="/">Go Home</A>
</main>
);
}
// Error boundary in layout
import { ErrorBoundary } from "solid-js";
export default function RootLayout(props: RouteSectionProps) {
return (
<ErrorBoundary
fallback={(err, reset) => (
<div class="error">
<h1>Something went wrong</h1>
<pre>{err.message}</pre>
<button onClick={reset}>Try Again</button>
</div>
)}
>
{props.children}
</ErrorBoundary>
);
}
// app.config.ts
export default defineConfig({
server: {
preset: "node",
},
});
// app.config.ts
export default defineConfig({
server: {
preset: "static",
prerender: {
routes: ["/", "/about", "/blog"],
// Or crawl from root
crawlLinks: true,
},
},
});
import { clientOnly } from "@solidjs/start";
const Chart = clientOnly(() => import("./Chart"));
export default function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<Chart fallback={<div>Loading chart...</div>} />
</div>
);
}
# Build for production
npm run build
# Deployment presets:
# - vercel
# - netlify
# - cloudflare-pages
# - cloudflare-workers
# - node
# - static
# - aws-lambda
# - deno
# Example: Vercel
npm run build
vercel deploy
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.