Building a Fullstack SvelteKit App with Apache2 and Spring Boot Backend
Step-by-step tutorial
Dec 9, 2025Jul 26, 2026
Modern web applications often require a robust backend and a fast, interactive frontend. A common architecture is:
- Frontend: SvelteKit (fast, reactive, modern JS)
- Backend: Spring Boot REST API
- Hosting: Apache2 serving static frontend files
In this post, we’ll walk through setting up this architecture step by step, including a simple dashboard using shadcn-svelte components.
Setting Up SvelteKit with Static Adapter
Since we want Apache2 to serve the frontend, we need to convert SvelteKit into a static site:
pnpm dlx sv create my-sveltekit-app cd my-sveltekit-app pnpm add -D @vercel/adapter-static
Then update svelte.config.js:
import adapter from '@vercel/adapter-static'; const config = { kit: { adapter: adapter(), prerender: { handleMissingId: 'ignore' } } }; export default config;
This generates static HTML, CSS, and JS during build, ready to be served by Apache2.
Building the Frontend
pnpm build
The output is in the build/ folder. You can deploy this folder to your Apache2 server:
sudo mkdir -p /var/www/myapp sudo cp -r build/* /var/www/myapp/
Apache2 Virtual Host Example
/etc/apache2/sites-available/myapp.conf:
<VirtualHost *:80> ServerName example.com DocumentRoot /var/www/myapp <Directory /var/www/myapp> Options FollowSymLinks AllowOverride All Require all granted </Directory> # SPA fallback for routing ErrorDocument 404 /index.html </VirtualHost>
Enable site and rewrite module:
sudo a2ensite myapp sudo a2enmod rewrite sudo systemctl restart apache2
Spring Boot Backend Setup
Create a standard Spring Boot REST API:
@RestController @RequestMapping("/api") public class CustomerController { @GetMapping("/customers") public List<Customer> getCustomers() { return List.of( new Customer(1, "Alice"), new Customer(2, "Bob") ); } }
Run Spring Boot on http://localhost:8080.
Connecting SvelteKit Frontend to Backend
Create a helper in src/lib/api.js:
export const API_URL = 'http://localhost:8080/api';
Fetch data in a SvelteKit page:
<script> import { onMount } from 'svelte'; import { API_URL } from '$lib/api'; let customers = []; onMount(async () => { const res = await fetch(`${API_URL}/customers`); customers = await res.json(); }); </script> <ul> {#each customers as customer} <li>{customer.name}</li> {/each} </ul>
This works in both dev and production (with proper CORS setup on Spring Boot).
Adding a Dashboard with Shadcn-Svelte and TailwindCSS
Install tailwindcss and shadcn-svelte components:
pnpm dlx sv add tailwindcss pnpm dlx shadcn-svelte@latest init
Adding a Dashboard with Shadcn-Svelte Sidebar
Instead of manually creating a dashboard, you can use the prebuilt sidebar component from shadcn-svelte:
Install the sidebar component
pnpm dlx shadcn-svelte@latest add sidebar
Using the Sidebar in your SvelteKit app
<script> import Sidebar from 'shadcn-svelte/sidebar'; import { onMount } from 'svelte'; import { API_URL } from '$lib/api'; let customers = []; onMount(async () => { const res = await fetch(`${API_URL}/customers`); customers = await res.json(); }); </script> <Sidebar title="Dashboard" items={[ { label: 'Home', href: '/' }, { label: 'Customers', href: '/customers' }, { label: 'Orders', href: '/orders' } ]}> <main class="p-4"> <h1 class="text-2xl font-bold mb-4">Customer List</h1> <ul> {#each customers as customer} <li>{customer.name}</li> {/each} </ul> </main> </Sidebar>
Benefits of using the Shadcn-Svelte sidebar
- Prebuilt, responsive, and accessible component
- Provides consistent navigation layout across pages
- Reduces development time
- Integrates easily with SvelteKit and dynamic data from your Spring Boot backend
You now have a modern dashboard layout fully powered by SvelteKit and styled with shadcn-svelte components.
Optional: Proxy API in Dev Mode
During development, avoid CORS issues by proxying API requests in vite.config.js:
import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; export default defineConfig({ plugins: [sveltekit()], server: { proxy: { '/api': 'http://localhost:8080' } } });
Now you can do fetch('/api/customers') locally without CORS problems.
Deployment Summary
- Build frontend:
pnpm build→build/folder - Copy static files to Apache2 →
/var/www/myapp - Run Spring Boot API → accessible at
/api - Frontend calls backend → SPA dashboard loads dynamically
- Optional SSL → configure Apache2 with Let’s Encrypt
This architecture is:
- Fast and scalable
- SEO-friendly (with prerendered pages)
- Easy to maintain
- Fully decoupled: frontend served statically, backend handles business logic
