Store, Static & SPA Server Modes Explained
Server Modes
Section titled “Server Modes”Stowry supports three server modes that change how requests are handled. Choose the mode that fits your use case.
Overview
Section titled “Overview”| Mode | Use Case | Path Fallback |
|---|---|---|
store |
Object storage API | None (404 if not found) |
static |
Static file server | {path}.html → {path}/index.html |
spa |
Single-page application | /index.html |
Store Mode (Default)
Section titled “Store Mode (Default)”The default mode for object storage operations.
server: mode: storeBehavior
Section titled “Behavior”GET /{path}- Returns the exact file or 404GET /- Returns JSON list of objects- Full CRUD operations (PUT, DELETE)
- No automatic fallbacks
Use Cases
Section titled “Use Cases”- Backend file storage for applications
- User upload handling
- Asset management systems
- API-driven file operations
Example
Section titled “Example”# Start in store mode./stowry serve --mode store
# Upload a filecurl -X PUT -d "content" http://localhost:5708/documents/report.pdf
# Download - returns exact filecurl http://localhost:5708/documents/report.pdf # 200 OK
# Missing file - returns 404curl http://localhost:5708/documents/missing.pdf # 404 Not Found
# List objectscurl http://localhost:5708/ # JSON responseStatic Mode
Section titled “Static Mode”Serves static files with S3+CloudFront-style path resolution and clean URLs.
server: mode: static error_document: 404.html # optional custom error pageBehavior
Section titled “Behavior”GET /{path}- Tries exact match →{path}.html→{path}/index.htmlGET /{path}/- Tries{path}/index.html(trailing slash = directory index)GET /- Returns/index.html- Missing paths return an HTML 404 page (default Stowry-branded, or custom via
error_document) - Read-only: PUT and DELETE return
405 Method Not Allowed - Reads are public:
auth.read: privateis rejected at startup, andauth.writeis ignored with a warning - Put files in the storage directory and run
stowry populate; static and spa route no writes
Fallback Logic
Section titled “Fallback Logic”For /foo (no trailing slash):
- Try exact path
foo - Try
foo.html(clean URLs) - Try
foo/index.html(directory index) - Return 404 error page
For /foo/ (trailing slash):
- Try
foo/index.html(directory index) - Return 404 error page
Error Pages
Section titled “Error Pages”By default, Stowry serves a minimal HTML 404 page:
<html><head><title>404 Not Found</title></head><body><center><h1>404 Not Found</h1></center><hr><center>stowry</center></body></html>Configure a custom error page:
server: error_document: 404.htmlThe custom error document is served from storage with a 404 status code. If the custom document is not found, the default page is used.
Use Cases
Section titled “Use Cases”- Static website hosting
- Documentation sites
- Marketing pages
- Any site with traditional URL structure
Example
Section titled “Example”Given this storage structure:
data/├── index.html├── about.html├── docs/│ └── index.html├── blog/│ ├── index.html│ └── post-1.html└── assets/ └── style.cssRequest handling:
GET / → data/index.htmlGET /about → data/about.html (clean URL)GET /about.html → data/about.html (direct)GET /docs/ → data/docs/index.html (trailing slash)GET /docs → data/docs/index.html (fallback chain)GET /blog/post-1.html → data/blog/post-1.htmlGET /assets/style.css → data/assets/style.cssGET /missing → 404 HTML pageSPA Mode
Section titled “SPA Mode”Designed for single-page applications with client-side routing.
server: mode: spaBehavior
Section titled “Behavior”GET /{path}- Returns file if exists, otherwise/index.html- Enables client-side routing (React Router, Vue Router, etc.)
- Read-only: PUT and DELETE return
405 Method Not Allowed - Reads are public:
auth.read: privateis rejected at startup, andauth.writeis ignored with a warning - Put files in the storage directory and run
stowry populate; static and spa route no writes
Fallback Logic
Section titled “Fallback Logic”- Try exact path
- If not found, return
/index.html - Client-side JavaScript handles routing
Use Cases
Section titled “Use Cases”- React applications
- Vue.js applications
- Angular applications
- Any SPA with client-side routing
Example
Section titled “Example”Given this storage structure:
dist/├── index.html├── assets/│ ├── main.js│ └── style.css└── favicon.icoRequest handling:
GET / → dist/index.htmlGET /dashboard → dist/index.html (SPA handles route)GET /users/123 → dist/index.html (SPA handles route)GET /assets/main.js → dist/assets/main.jsGET /favicon.ico → dist/favicon.icoClient-Side Router Setup
Section titled “Client-Side Router Setup”Ensure your SPA handles the current URL on load:
React Router:
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Home />} /> <Route path="/dashboard" element={<Dashboard />} /> <Route path="/users/:id" element={<UserProfile />} /> </Routes> </BrowserRouter> );}Vue Router:
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', component: Home }, { path: '/dashboard', component: Dashboard }, { path: '/users/:id', component: UserProfile }, ],});Comparing Modes
Section titled “Comparing Modes”GET Request Behavior
Section titled “GET Request Behavior”| Request | Store | Static | SPA |
|---|---|---|---|
GET / |
List objects (JSON) | /index.html |
/index.html |
GET /about |
Exact file or 404 | about → about.html → about/index.html |
/index.html |
GET /about/ |
Exact file or 404 | about/index.html |
/index.html |
GET /file.txt |
Exact file or 404 | Exact file or 404 | Exact file or 404 |
GET /missing |
404 (JSON) | 404 (HTML) | /index.html |
Write Operation Availability
Section titled “Write Operation Availability”| Operation | Store | Static | SPA |
|---|---|---|---|
PUT /{path} |
Allowed | 405 | 405 |
DELETE /{path} |
Allowed | 405 | 405 |
GET / (list) |
JSON list | index.html | index.html |
When to Use Each
Section titled “When to Use Each”Use Store when:
- Building an API-driven application
- You need full control over responses
- Implementing custom 404 handling on the client
- File paths are dynamic/generated
Use Static when:
- Hosting a traditional static website
- Each URL corresponds to a specific page
- You want automatic directory index resolution
- SEO is important (each route has its own file)
Use SPA when:
- Building a single-page application
- Using client-side routing
- All routes should load the same entry point
- Deep linking should work for all routes
Populating Content
Section titled “Populating Content”Since static and SPA modes are read-only, use one of these methods to add files:
# Record files already in the storage directorystowry populate # after copying ./dist into the storage directory
# Using store mode temporarilystowry serve --mode store# Upload files via PUT, then restart in static/spa modeSwitching Modes
Section titled “Switching Modes”You can change modes without modifying your stored files:
# Development with SPA mode./stowry serve --mode spa
# Production static hosting./stowry serve --mode static
# API mode for backend./stowry serve --mode storeOr via configuration:
server: mode: storeThe config file is not shell-expanded, so ${VAR} in it is a literal string.
To take the mode from the environment, set STOWRY_SERVER_MODE instead.