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

  1. Build frontend: pnpm buildbuild/ folder
  2. Copy static files to Apache2 → /var/www/myapp
  3. Run Spring Boot API → accessible at /api
  4. Frontend calls backend → SPA dashboard loads dynamically
  5. 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

About the author

Dejan Antanasković is a software developer with over two decades of experience in designing, developing, and maintaining robust backend and frontend systems – from scientific and geospatial applications to complex web and mobile platforms.