Replace public/icons/icon.svg, icon-192.png, icon-512.png, and og.png when branding your app (favicon, PWA, Open Graph).
npx create-skateboard-app
cd my-app
npm install
npm start # frontend http://localhost:5173
cd backend && cargo run # backend http://localhost:8000Frontend is Vite. Backend is Rust (cargo run). There is no npm run server.
Everything you need to ship a production-ready app:
- 95% less boilerplate - Focus on features, not infrastructure
- Shell + Content + Config - Framework provides structure, you provide content
- Update once, fix everywhere - All apps inherit improvements from skateboard-ui
- Routes-only
main.tsx- Define routes, passconstants.json, done - Convention over configuration - Sensible defaults with escape hatches everywhere
- Sign up / Sign in with native HS256 JWT in HttpOnly cookies
- Protected routes with automatic redirects
- User context management across your app
- Session persistence with secure cookies
- scrypt password hashing in the Rust backend (legacy bcrypt still verifies)
- Usage tracking with configurable limits for free users
- Checkout flows ready to go
- Subscription management portal
- Webhook handling for payment events
- Customer portal integration
- Shadcn/ui components via skateboard-ui
- Dark/Light mode with system detection
- Mobile-ready design with responsive sidebar and TabBar
- Landing page that converts - fully customizable via constants.json
- Settings page with user management
- Legal pages (Terms, Privacy, EULA)
- Vite 8 with esbuild JSX (full reload on edit; no
@vitejs/plugin-react-swc) - Zero-crate Rust backend - empty
[dependencies]; system libsqlite3 + libcurl - SQLite only - no Postgres, no Mongo
- constants.json - customize everything in one place
- TypeScript without a build step - strict mode, Node 24 runs
.tsnatively, Vite compiles.tsx - Typecheck gates -
npm run typecheckfor the frontend;cargo testfor the backend - Built-in hooks -
useListDatafor list fetching - API utilities - apiRequest with automatic auth and error handling
- Icons - named imports from
lucide-react(no@stevederico/skateboard-ui/icons)
Update src/constants.json to customize your app:
{
"appName": "Your App Name",
"tagline": "Your Tagline",
"cta": "Get Started"
}cd backend && cargo run # listen on :8000
cd backend && cargo test --lockedDatabase Configuration - Update backend/config.json:
{
"staticDir": "../dist",
"database": {
"db": "MyApp",
"dbType": "sqlite",
"connectionString": "./databases/MyApp.db"
}
}Auth Variables - add to backend/.env (use a unique random string):
JWT_SECRET=your-secret-key
STRIPE_KEY=sk_test_...
STRIPE_ENDPOINT_SECRET=whsec_...
FREE_USAGE_LIMIT=20 # Optional: monthly usage limit for free users (default: 20)Database: SQLite only ("dbType": "sqlite"). Postgres and Mongo are not supported.
To enable payments, configure your Stripe products:
-
Create Product in Stripe Dashboard
- Go to Product Catalog β Create Product
- Add Name and Amount
- Click More Pricing Options
- Scroll to Lookup Key at bottom
- Enter:
my_lookup_key - This allows future pricing changes on stripe.com without updating your code
-
Update Environment Variables
STRIPE_KEY=sk_live_your_secret_key
Security Note: Use your secret key OR create a restricted key with these permissions:
- Read/Write: Checkout Sessions
- Read: Customers, Prices, Products
-
Setup Webhook
- Go to stripe.com β Developers (lower left) β Webhooks
- Click Add Endpoint
- Add your endpoint URL:
https://yourdomain.com/api/payment - Select these events (every one the backend handles):
checkout.session.completed- Links the Stripe customer to the user after first purchasecustomer.subscription.created- Customer signed up for new plancustomer.subscription.updated- Subscription changes (plan switch, trial to active, etc.)customer.subscription.deleted- Customer's subscription endsinvoice.paid- Renewal succeeded; extends the paid-through dateinvoice.payment_failed- Renewal failed; marks the subscription past due
- Copy the Signing Secret to your environment:
STRIPE_ENDPOINT_SECRET=whsec_your_webhook_secret
Sign-in lockouts and the auth rate limiter live in process memory. That is fine for one instance. CSRF tokens are signed, not stored, so they survive restarts.
Multiple instances: move those stores to SQLite or another shared store. Until then each instance counts separately, so the effective auth rate limit is the per-instance limit times the instance count.
See Guide β Architecture for details.
Skateboard is intentionally lean β current footprint (counting what ships at runtime):
| Frontend runtime | Frontend dev | Backend crates | |
|---|---|---|---|
| Before (v2.x) | 12 | 4 | 7 |
| Now | 4 | 7 | 0 |
The backend is zero-crate Rust. JWT is HS256 HMAC, passwords are scrypt, leftover bcrypt hashes still verify then rehash. SQLite via system libsqlite3. Stripe via system libcurl. Do not cargo add.
The frontend pulls UI primitives from skateboard-ui. That package depends on react-router and (from 4.18+) lucide-react (pinned); peers are react and react-dom. Apps do not declare react-router. Navigate with useSafeNavigate(). Named-import icons from lucide-react (boilerplate also lists it). There is no @stevederico/skateboard-ui/icons path.
Frontend dev deps are Vite + Tailwind (@tailwindcss/vite) plus typescript + @types/* for the typecheck gate. No @vitejs/plugin-react-swc. No component-test runner. Node 24 strips types natively; Vite compiles .tsx via esbuild.
Built with the latest and greatest:
| Technology | Version | Purpose |
|---|---|---|
| React | v19 | UI Framework |
| skateboard | v5.10.0 | Boilerplate (this repo) |
| skateboard-ui | v5.1.0 | Application Shell, Components, Theming |
| Vite | v8 | Build Tool & Dev Server (esbuild JSX) |
| Tailwind CSS | v4.3+ | Styling |
| React Router | v7.18+ | Routing (via skateboard-ui) |
| lucide-react | v0.546+ | Icons (named imports) |
| Rust | 1.95 | Zero-crate backend |
| TypeScript | v7 | Frontend types (strict, no build step) |
| Node.js | v24+ | Frontend toolchain |
| SQLite | system lib | Database |
| Stripe | REST + libcurl | Payments |
Application Shell: skateboard-ui owns routing, auth, layout, and theming; your app
supplies routes, components, and constants.json. Full write-up:
docs/GUIDE.md.
import { createSkateboardApp } from '@stevederico/skateboard-ui/App';
import constants from './constants.json';
import HomeView from './components/HomeView';
createSkateboardApp({
constants,
appRoutes: [{ path: 'home', element: <HomeView /> }],
loadLegal: () => import('./legal.json'),
});Learn more: Documentation site for guides, or docs/GUIDE.md for the consolidated reference (Architecture, API, Schema, Deployment, Migration).
See Guide β Deployment for step-by-step instructions on deploying to your preferred platform.
Apps scaffolded from Skateboard can pull in upstream boilerplate updates with:
node scripts/update-skateboard.js # interactive β diff per file
node scripts/update-skateboard.js --yes # apply all without promptsUpdates only files in the safe allowlist (backend/src/*, vite.config.ts, Dockerfile, etc.) and merges new deps into your package.json. Never touches your constants.json, src/components/*, backend/config.json, or .env.
See docs/UPGRADE.md for the full guide. 5.0.0 is a breaking major β see AGENTS.md β Migrating 4.x β 5.0.
GitHub Actions (.github/workflows/ci.yml) runs on every push and PR:
- Frontend:
npm ci,npm run build,npm run test - Backend:
cargo test --lockedinbackend/
Node 24 matches package.json engines.
We love contributions!
# Fork the repo, then:
git clone https://github.com/YOUR_USERNAME/skateboard
cd skateboard
npm install
npm run start # frontend :5173
cd backend && cargo run # backend :8000- π¦ X: @stevederico
- π Issues: GitHub Issues
Built on the shoulders of giants:
- React - The library that powers the web
- Vite - Lightning fast build tool
- Tailwind CSS - Utility-first CSS
- Shadcn/ui - Beautiful components
- Rust - Zero-crate backend
- Stripe - Payment infrastructure
- skateboard-ui - Component library
- skateboard-blog - Blog template
- create-skateboard-app - CLI tool
npx create-skateboard-appMIT License - use it however you want! See LICENSE for details.
Built with β€οΈ by Steve Derico and contributors
β Star us on GitHub β it helps!