# Elements vs SvelteKit SvelteKit is an open-source web app framework for Svelte, made by the Svelte team. Svelte is a UI framework with its own compiler: you write components in `.svelte` files that combine a script, HTML-like markup and styles, and mark reactive state with [runes](https://svelte.dev/docs/svelte/what-are-runes) such as `$state` and `$derived`. SvelteKit adds [routing](https://svelte.dev/docs/kit/routing) based on folders and `+page` and `+layout` files, `load` functions that fetch a page's data, [form actions](https://svelte.dev/docs/kit/form-actions) that handle submissions, and rendering on the server, in the browser, or ahead of time as static files. It runs on Vite, and [adapters](https://svelte.dev/docs/kit/adapters) package the built app for a Node.js server, static hosting, Vercel, Netlify or Cloudflare. Elements builds the same kind of app. It is an integrated app environment, made for people and their agents: a project server that runs while you work, installing packages, running tests and migrations, and reporting every build error, with Postgres bundled and a deploy command for any Ubuntu server over SSH. It ships with a default framework that just works, with routing, server rendering and pages that update when their data changes, and with typed server functions, sessions, realtime data, background jobs and email. Pages are written in Elements HTML, plain HTML with reactive expressions that the build compiles and checks. The apps are TypeScript and run on Node.js. A SvelteKit app comes together from add-ons. Past routing and rendering, `sv add` brings in Drizzle and drizzle-kit for the database and migrations, Better Auth for sign-in, Vitest and Playwright for tests, and an adapter for the host, and background jobs and email are yours to find. Each is its own project with its own config file and its own API, and each seam is a place to break: a Better Auth setup whose tables have to match the Drizzle schema, or a type error that the dev server never reports and that surfaces only when `svelte-check` runs. Elements is ready out of the box. Postgres, migrations, sessions, tests, jobs, email, realtime and deploy are engineered as one coherent system, so you build productively from the first minute. Between you and the platform there is only a thin layer: pages are HTML and CSS, queries are SQL, server calls are TypeScript function calls, and the framework words to learn are `app.route()`, `session.login()`, `sql()`, `@rpc` and tests. ## At a Glance | | Elements | SvelteKit | |---|---|---| | What it is | A project server and a default framework, with Postgres, tests and deploy | A Svelte framework with routing and rendering, run on Vite | | Templates | [Elements HTML](/learn/man/html): standard HTML with typed reactive expressions | Svelte components, with runes marking reactive state | | Routing | [Declared in `index.ts`](/learn/man/router) with web standard `URLPattern` | Folders and `+page`, `+layout` and `+server` files | | Server functions | [`@rpc`](/learn/man/rpc): typed calls for reads and writes, built in | Remote functions, turned on by two config flags; form actions for POST | | Sign-in and sessions | [Built in](/learn/man/session), the same over HTTP and WebSockets | Not included; the CLI can set up Better Auth | | Database | [Postgres, bundled](/learn/man/database), with `sql()` built in | Not included; the CLI can add Drizzle | | Migrations | [Applied when you save them](/learn/man/migrations) | Not included | | Build errors | [One build](/learn/man/build) reports type errors, failing tests, migration errors and server code reachable from the browser | `svelte-check`, Vitest and Playwright, each run on its own | | Tests | [Part of the build](/learn/man/tests) | Not included; the CLI can add Vitest and Playwright | | Realtime | [LiveTable](/learn/man/livetable) and [channels](/learn/man/channel) | `query.live` streams values to one page; reaching other users is yours to build | | Background jobs and cron | [Built in](/learn/man/jobs) | Not included | | Email | [Built in](/learn/man/email); messages are Elements HTML templates | Not included | | Deploy | [`elements deploy`](/learn/man/deploy) to any Ubuntu server over SSH, usually under a second | An adapter packages the build; hosting and the pipeline are yours | ## One Environment, Not a Stack of Add-Ons Beyond routing and rendering, SvelteKit leaves each part of an app to an add-on. Its CLI, `sv`, [adds them to a project](https://svelte.dev/docs/cli/sv-add): Drizzle for the database, Better Auth for sign-in, Vitest and Playwright for tests, Tailwind for styles, and an adapter for the host. Each is a separate project with its own configuration, its own docs and its own API. For background jobs, email and realtime, there is no add-on at all. In Elements the database, sessions, the test runner, jobs, email and realtime ship together, and one build checks all the code that uses them. Styles are covered too: [`@elements/style`](/learn/man/style) is a design system of tokens, components and utilities, and `elements create` [sets it up in every new app](/learn/man/style/install). An add-on saves an agent time only when it does something the agent cannot write quickly from standards. Tailwind is a case in point: an agent writes plain CSS fluently, so a utility vocabulary is one more thing to look up. Every add-on past that line is another config file and another seam. Leaving the `sv add` catalog does not mean leaving npm: Stripe, the AWS SDK and other packages install unchanged. A framework still earns its keep. On a line from machine code to a package that subtracts two numbers, an agent wants the point in between where routing, typed server calls, sessions and a database driver are handled as plumbing, so the Elements app framework ships them as `app.route()`, `@rpc`, `session.login()` and `sql()`. Beyond that plumbing returns diminish, and each extra rune, block syntax or add-on API costs an agent more to learn and get right than it saves. There, the payoff is correction, knowing what it got wrong as soon as it gets it wrong, and in a stack of add-ons that answer is spread across `svelte-check`, Vitest and the dev server. Elements keeps the rest to HTML and CSS pages and TypeScript function calls, and spends its engineering on correction. One coherent system checks every template, function, query, test and migration, so every build error, from type checking, tests, migrations and program analysis, turns up in milliseconds. Its project server runs while you work and holds the build graph and build state in memory, so on every save the build state is updated almost instantly, and `elements build -json` answers agents and humans in microseconds ([build](/learn/man/build)). The editor, the terminal and every agent share that build, and server code has no `async` or `await` for an agent to forget. ## Templates Are Standard HTML, Not Svelte Components Svelte writes reactive pages as components in its own file format. Markup uses its own template syntax, `{#if}`, `{:else}`, `{#each}` and `{@render}`, and reactive values are declared with runes, keywords that only work in `.svelte`, `.svelte.js` and `.svelte.ts` files ([runes](https://svelte.dev/docs/svelte/what-are-runes)). Elements uses [Elements HTML](/learn/man/html): standard HTML tags, TypeScript expressions in `{}`, and a few `e:` attributes for conditions and loops. A page declares its data as typed attributes on its opening tag, and when that data changes, the page updates. Nothing marks a value as reactive. ```ehtml interface Task { title: string; } function addTask(tasks: Task[], form: { title: string }) { tasks.push({ title: form.title }); form.title = ""; }
Nothing to do.
``` The handler is a plain TypeScript function. Pushing onto the array adds the row, and clearing the field empties the input, because form inputs bind both ways by default. Where Svelte needs `$state` to know what to track, the Elements runtime works it out from the expressions and [patches only the markup](/learn/man/html/reactivity) that reads the changed value, after a server render that sends finished HTML. The build checks templates with the rest of the code, so a mistake in a template shows up in the same build report as any other, with no separate checker to run. ## Server Functions Are Built In, for Reads and Writes SvelteKit has several ways to reach the server: `load` functions for reading a page's data, form actions that take a POST from a `