Zero-JS Client Architectures: The SvelteKit & Astro Philosophy
Modern web development has increasingly pushed back against monolithic single-page application (SPA) bundles that download megabytes of client JavaScript before users can render a simple form. SvelteKit and Astro lead this movement by adopting HTML-first, server-driven paradigms.
When handling contact forms, newsletter signups, or transactional notification triggers, sending emails from client components is a critical security antipattern that exposes API credentials. Both SvelteKit and Astro provide server primitives—SvelteKit Form Actions (+page.server.ts) and Astro API endpoints (pages/api/send.ts)—that process mutations on the server, validate inputs, and dispatch emails with zero client bundle overhead.
1. SvelteKit Form Action Implementation (+page.server.ts)
SvelteKit Form Actions execute exclusively on the server. Using $env/static/private guarantees that secret API keys are never bundled into client assets or leaked through source maps.
import { fail } from '@sveltejs/kit';
import type { Actions } from './$types';
import { SADASEND_API_KEY } from '$env/static/private';
export const actions: Actions = {
default: async ({ request }) => {
const data = await request.formData();
const email = data.get('email')?.toString();
const name = data.get('name')?.toString();
const message = data.get('message')?.toString();
if (!email || !message || !name) {
return fail(400, { missing: true, email, name, message });
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return fail(400, { invalidEmail: true });
}
const res = await fetch('https://api.sadasend.com/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${SADASEND_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': `sveltekit-${email}-${Date.now()}`,
},
body: JSON.stringify({
to: 'team@sadasend.com',
replyTo: email,
subject: `Inquiry from ${name}`,
text: `From: ${name} <${email}>\n\nMessage:\n${message}`,
}),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
return fail(500, { serverError: err.message || 'Email delivery failed' });
}
return { success: true };
},
};2. Astro Server Endpoint in Hybrid Mode (src/pages/api/send.ts)
Astro in hybrid rendering (output: "server" or prerender = false) enables lightweight edge endpoints that handle JSON requests with low-latency overhead.
import type { APIRoute } from 'astro';
export const prerender = false;
export const POST: APIRoute = async ({ request }) => {
const apiKey = import.meta.env.SADASEND_API_KEY;
if (!apiKey) {
return new Response(JSON.stringify({ error: 'Missing SADASEND_API_KEY' }), { status: 500 });
}
const { to, subject, body } = await request.json();
const res = await fetch('https://api.sadasend.com/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ to, subject, text: body }),
});
const data = await res.json();
return new Response(JSON.stringify(data), {
status: res.status,
headers: { 'Content-Type': 'application/json' },
});
};Architectural Comparison: SvelteKit vs Astro
| Feature | SvelteKit Form Actions | Astro Server Endpoints |
|---|---|---|
| Default Progressive Enhancement | Native (HTML <form> works without JS) | Requires form action target or client fetch |
| Secret Protection | $env/static/private (Build-time validation) | import.meta.env (Server-only secret checks) |
| Client Footprint | 0 bytes for server action code | 0 bytes of JavaScript shipped to browser |
| Edge Adapters | Cloudflare, Vercel, Node, Bun | Cloudflare, Vercel, Netlify, Node |
Building AI agents that send email?
Scoped API keys, per-key recipient allowlists, approval mode and a hosted MCP server with ten tools — on the free plan, without a card.