This repository contains an SAP CAP application with a SvelteKit frontend that runs server-side inside the CAP server. This lets the frontend call CAP services directly via cds.ql and the programmatic service APIs instead of going through OData or REST.
SvelteKit is a full-stack web framework, comparable to Next.js for React. It supports server-side rendering (SSR), meaning each page can have a server-side load function (+page.server.ts) that fetches data before the HTML is rendered. The browser receives a fully rendered page.
In this demo, SvelteKit runs inside the CAP server process. The server-side load functions therefore have direct access to CAP's programmatic APIs. Instead of calling an OData or REST endpoint, the frontend code uses cds.connect.to() and cds.ql (SELECT, INSERT, etc.) to query a CAP service directly. For example:
// app/sample/src/routes/po-tracker/+page.server.ts
import cds from "@sap/cds";
import PurchaseOrderService, { PurchaseOrders } from "#cds-models/PurchaseOrderService";
export const load: PageServerLoad = async () => {
const srv = await cds.connect.to(PurchaseOrderService);
const [totalCount, pendingCount, recentOrders] = await srv.run([
SELECT.one.from(PurchaseOrders).columns("count(*) as value"),
SELECT.one.from(PurchaseOrders).columns("count(*) as value").where({ status: "Pending" }),
SELECT.from(PurchaseOrders).orderBy("createdAt desc").limit(5),
]);
return { totalCount: totalCount.value, pendingCount: pendingCount.value, recentOrders };
};
The call still goes through the CAP service layer, so authorization, validations, and custom handlers behave as they normally would. The only difference is that it runs in-process via CAP's service API instead of being sent over HTTP/OData.
Because the data is fetched on the server, the browser receives fully rendered HTML with the data already included on first load.
cds.connect.to, SELECT.from, etc.) instead of OData or REST. All service handlers, validations, and authorization still apply.srv/
server.ts # CAP server, mounts SvelteKit as middleware
purchase-order-service.ts/cds # Sample service definition + custom handlers
db/
schema.cds # Domain model
app/sample/
src/routes/
+page.svelte # Start page with app selection
po-tracker/ # UI5 Web Components frontend
ssr-dashboard/ # Skeleton UI + Tailwind CSS frontend
Both routes show the same purchase order data (KPIs, charts, order list) and use the same CDS queries in their server-side load functions. They differ in how well they benefit from SSR:
npm i -g @sap/cds-dk)npm i -g mbt)npm ci
npm run dev
alice and password 123npm run build
cf login -a https://api.cf.<region>.hana.ondemand.com
npm run deploy
Development: Vite (SvelteKit’s dev server and build tool) is registered as Express middleware for the /app/sample path. When a request starts with /app/sample, it is forwarded to Vite. Vite then serves the SvelteKit pages, handles hot module replacement, and compiles the code on the fly. Other routes, such as /odata/..., are still handled directly by CAP as usual.
Production: vite build together with the SvelteKit Node adapter produces a Node.js request handler (handler.js). At startup, the CAP server imports this handler and mounts it for all non-OData/REST routes. In other words, CAP keeps handling /odata/..., while everything under /app/sample (and other UI routes) is rendered by SvelteKit inside the same Node.js process.