- Svelte 60.3%
- TypeScript 32.5%
- JavaScript 3.9%
- Dockerfile 1.6%
- CSS 0.9%
- Other 0.8%
| .vscode | ||
| e2e | ||
| src | ||
| static | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| .npmrc | ||
| AGENTS.md | ||
| bun.lock | ||
| docker-compose.yml | ||
| Dockerfile | ||
| eslint.config.js | ||
| opencode.json | ||
| package.json | ||
| playwright.config.ts | ||
| README.md | ||
| svelte.config.js | ||
| TODO.md | ||
| tsconfig.json | ||
| vite.config.ts | ||
Strapi 5 SvelteKit Showcase
A developer-friendly frontend for exploring and testing Strapi 5 CMS capabilities. This application demonstrates how to integrate Strapi with SvelteKit, showcasing article rendering, categories, dynamic content blocks, and media handling.
Features
- Article Management: Fetch, display, and navigate through articles with cover images, metadata, and dynamic content
- Dynamic Content Blocks: Render multiple block types including:
- Rich text blocks
- Media blocks (with image optimization)
- Quote blocks
- Extensible for custom block types
- Category System: Organize and browse content by categories with article counts
- Media Handling: Responsive image loading using Strapi's automatic image optimization (thumbnail, small, medium, large formats)
- TypeScript Integration: Full type safety for all Strapi data structures
- Server-Side Rendering: SEO-friendly initial page loads with SvelteKit SSR
- Developer-Friendly UI: Clear display of metadata and data structures for exploration
Architecture
Type Definitions (src/lib/types.ts)
Complete TypeScript interfaces for all Strapi entities:
Article,Category,Media,Author- Block types:
RichTextBlock,MediaBlock,QuoteBlock,AnyBlock - API response types:
StrapiResponse,StrapiCollectionResponse
Strapi Client (src/lib/server/strapi.ts)
Server-side API wrapper that:
- Handles authentication via private environment variable
- Provides typed methods:
getArticles(),getArticle(),getCategories(),getCategory() - Includes query builder for filters, sorting, pagination, and population
- Implements image URL helper using Strapi's format variants
Components
- Layout.svelte: Main navigation and footer with slot support
- ArticleCard.svelte: Card component for displaying article previews
- CategoryCard.svelte: Card component for displaying categories
- StrapiImage.svelte: Responsive image component with lazy loading
- BlockRenderer.svelte: Dynamic component that renders different block types
Routes
/- Home page with featured articles and category overview/articles- All articles listing/articles/[slug]- Individual article with full block rendering/categories- All categories with their articles/categories/[slug]- Category detail with filtered articles
Environment Variables
PUBLIC_STRAPI_URL=https://your-strapi-instance.com
STRAPI_TOKEN=your-api-token
PUBLIC_STRAPI_URL: Public Strapi instance URL (accessible on client)STRAPI_TOKEN: API token for authentication (server-side only, secure)
Strapi Configuration
This frontend expects following content types in your Strapi instance:
Article Content Type
title(string)description(text)slug(uid)cover(media, single)author(relation to Author)category(relation to Category)blocks(dynamic zone)
Category Content Type
name(string)slug(uid)description(text)articles(relation to Article)
Dynamic Blocks
shared.rich-textwithbodyfieldshared.mediawithmediafieldshared.quotewithtitleandbodyfields
Development
# Install dependencies
bun install
# Run development server
bun run dev
# Type checking
bun run check
# Linting
bun run lint
API Queries
The application uses Strapi's REST API with query parameters:
Fetch all articles with relations
GET /api/articles?populate[cover]=true&populate[author]=true&populate[category]=true&populate[blocks]=true&sort[createdAt]=desc
Fetch single article by slug
GET /api/articles/{slug}?populate=*
Fetch categories with articles
GET /api/categories?populate[articles]=true
Customization
Adding New Block Types
- Add the block type to
src/lib/types.ts:
interface CustomBlock extends BaseBlock {
__component: 'shared.custom-block';
customField: string;
}
- Update
BlockRenderer.svelteto render the new block type:
{:else if componentType === 'shared.custom-block'}
<section class="my-8">
<!-- Custom rendering logic -->
</section>
Styling
The application uses Tailwind CSS 4. Modify styles by editing component classes or adding custom styles in <style> blocks.
Security Considerations
- Strapi API token is stored in
STRAPI_TOKEN(private env var) and only accessible on the server - Token is never exposed to the client
- All API calls are made from server-side load functions
- Public URLs (like images) are handled via
PUBLIC_STRAPI_URL
Docker
This application is containerized using Docker with Bun for both build and runtime.
Prerequisites
- Docker and Docker Compose installed
.envfile configured (copy from.env.example)
Quick Start with Docker
# Copy environment variables
cp .env.example .env
# Edit .env with your Strapi credentials
# Build and run
docker-compose up -d --build
# View logs
docker-compose logs -f
# Stop
docker-compose down
Manual Docker Build
# Build image
docker build -t sveltekit-app .
# Run container
docker run -p 3000:3000 --env-file .env sveltekit-app
Docker Configuration
- Base Image:
oven/bun:alpine(both builder and runtime) - Multi-stage Build: Optimized for small image size
- Port: 3000 (configurable via HOST and PORT env vars)
- Health Check: Built-in HTTP health check on
/
Production Deployment
The Docker image is production-ready. Deploy to any container orchestration platform:
# Build for production
docker build -t your-registry/sveltekit-app:latest .
# Push to registry
docker push your-registry/sveltekit-app:latest
Environment variables must be provided at runtime:
PUBLIC_STRAPI_URL: Your Strapi instance URLSTRAPI_TOKEN: API authentication token
Browser Support
Modern browsers supporting:
- ES2020+ JavaScript
- CSS Grid and Flexbox
- CSS Custom Properties
- Tailwind CSS v4 features
License
MIT
Contributing
This is a showcase application. Feel free to fork and adapt it for your own Strapi + SvelteKit projects.