Summary
Add configuration presets that bundle sensible defaults for common deployment scenarios. This is a low-effort, high-impact improvement that reduces friction for new users while maintaining full customization flexibility.
Difficulty: 15/100
Estimated Effort: 1-2 days
Dependencies: None
Problem
Currently, users face 30+ configuration options without guidance on which combinations make sense for their use case. New users must:
- Read documentation to understand each option
- Decide which features they need
- Manually configure each setting
- Hope they didn't miss important combinations
This creates unnecessary friction, especially for common scenarios that have well-known "best" configurations.
Proposed Solution
Usage
# CLI flag
jss start --preset personal
jss start --preset community
jss start --preset federation
# With overrides (preset applies first, then overrides)
jss start --preset personal --port 8443 --notifications
# Config file
{
"preset": "personal",
"port": 8443 // overrides preset value
}
# Environment variable
JSS_PRESET=personal
Preset Definitions
minimal - Development & Testing
Quick local development, CI/CD testing, demos.
{
"port": 3000,
"host": "localhost",
"multiuser": false,
"singleUser": true,
"singleUserName": "dev",
"conneg": false,
"notifications": false,
"idp": false,
"mashlib": false,
"git": false,
"nostr": false,
"activitypub": false
}
| Setting |
Rationale |
localhost only |
Security for dev environment |
| Single user |
No registration complexity |
| Features off |
Fastest startup, minimal dependencies |
personal - Single-User Production
Personal data pod, self-hosted for one person.
{
"port": 443,
"host": "0.0.0.0",
"multiuser": false,
"singleUser": true,
"singleUserName": "me",
"conneg": true,
"notifications": true,
"idp": true,
"mashlib": true,
"mashlibCdn": false,
"git": false,
"nostr": false,
"activitypub": false,
"defaultQuota": "10GB"
}
| Setting |
Rationale |
| Port 443 |
Production HTTPS |
| IdP enabled |
Proper authentication |
| Conneg + Notifications |
Full Solid spec compliance |
| Mashlib |
Data browser for file management |
| Large quota |
Personal use, generous storage |
community - Multi-User Open Registration
Community server with open registration.
{
"port": 443,
"host": "0.0.0.0",
"multiuser": true,
"singleUser": false,
"conneg": true,
"notifications": true,
"idp": true,
"inviteOnly": false,
"mashlib": true,
"mashlibCdn": true,
"git": false,
"nostr": false,
"activitypub": false,
"defaultQuota": "100MB"
}
| Setting |
Rationale |
| Open registration |
Community growth |
| Mashlib CDN |
Reduce server bandwidth |
| 100MB quota |
Reasonable default for shared hosting |
private - Multi-User Invite-Only
Organization or private group server.
{
"port": 443,
"host": "0.0.0.0",
"multiuser": true,
"singleUser": false,
"conneg": true,
"notifications": true,
"idp": true,
"inviteOnly": true,
"mashlib": true,
"mashlibCdn": false,
"git": false,
"nostr": false,
"activitypub": false,
"defaultQuota": "1GB"
}
| Setting |
Rationale |
| Invite-only |
Controlled membership |
| Local mashlib |
Privacy, no CDN dependencies |
| 1GB quota |
Trusted users, more storage |
federation - Federated Social Server
Full federation with ActivityPub and Nostr.
{
"port": 443,
"host": "0.0.0.0",
"multiuser": true,
"singleUser": false,
"conneg": true,
"notifications": true,
"idp": true,
"inviteOnly": false,
"mashlib": true,
"mashlibCdn": true,
"git": false,
"nostr": true,
"nostrPath": "/relay",
"nostrMaxEvents": 5000,
"activitypub": true,
"defaultQuota": "500MB"
}
| Setting |
Rationale |
| ActivityPub + Nostr |
Full federation support |
| Higher event limit |
Social features need more storage |
| Open registration |
Federation requires discoverability |
developer - Full Features for Testing
All features enabled for development/testing.
{
"port": 3000,
"host": "0.0.0.0",
"multiuser": true,
"singleUser": false,
"conneg": true,
"notifications": true,
"idp": true,
"inviteOnly": false,
"mashlib": true,
"mashlibCdn": false,
"git": true,
"nostr": true,
"activitypub": true,
"webidTls": true,
"defaultQuota": "1GB"
}
| Setting |
Rationale |
| All features on |
Test all functionality |
| Port 3000 |
Dev-friendly, no sudo needed |
| Local mashlib |
Debug without CDN caching issues |
Implementation Details
Config Loading Changes
// src/config.js
const PRESETS = {
minimal: { /* ... */ },
personal: { /* ... */ },
community: { /* ... */ },
private: { /* ... */ },
federation: { /* ... */ },
developer: { /* ... */ }
};
function loadConfig(cliOptions, configPath) {
// 1. Start with defaults
let config = { ...DEFAULTS };
// 2. Apply preset if specified (NEW)
const presetName = cliOptions.preset || process.env.JSS_PRESET;
if (presetName) {
if (!PRESETS[presetName]) {
throw new Error(`Unknown preset: ${presetName}. Available: ${Object.keys(PRESETS).join(', ')}`);
}
config = { ...config, ...PRESETS[presetName] };
}
// 3. Apply config file
if (configPath) {
const fileConfig = JSON.parse(fs.readFileSync(configPath));
// Handle preset in config file too
if (fileConfig.preset && PRESETS[fileConfig.preset]) {
config = { ...config, ...PRESETS[fileConfig.preset] };
}
config = { ...config, ...fileConfig };
}
// 4. Apply environment variables
config = applyEnvOverrides(config);
// 5. Apply CLI arguments (highest priority)
config = { ...config, ...cliOptions };
return config;
}
CLI Addition
// bin/jss.js
program
.command('start')
.option('--preset <name>', 'Configuration preset (minimal, personal, community, private, federation, developer)')
// ... existing options
List Presets Command
program
.command('presets')
.description('List available configuration presets')
.action(() => {
console.log('\nAvailable presets:\n');
console.log(' minimal Development & testing (single user, no features)');
console.log(' personal Single-user production server');
console.log(' community Multi-user with open registration');
console.log(' private Multi-user with invite-only registration');
console.log(' federation Full ActivityPub + Nostr federation');
console.log(' developer All features enabled for testing');
console.log('\nUsage: jss start --preset <name>');
console.log('\nView preset details: jss presets --show <name>');
});
Show Preset Details
$ jss presets --show personal
Preset: personal
Description: Single-user production server
Configuration:
port: 443
host: 0.0.0.0
singleUser: true
singleUserName: me
conneg: true
notifications: true
idp: true
mashlib: true
defaultQuota: 10GB
Usage: jss start --preset personal
Enhanced jss init Integration
Update jss init to offer preset selection:
$ jss init
JavaScript Solid Server Setup
? Choose a starting point:
❯ Personal server (single user, simple setup)
Community server (multi-user, open registration)
Private server (multi-user, invite-only)
Federation server (ActivityPub + Nostr)
Minimal (development/testing)
Developer (all features enabled)
Custom (configure everything manually)
Using preset: personal
? Port (443):
? Data directory (./data):
? Domain name: example.com
Configuration saved to: ./config.json
Industry Comparison
| Software |
Preset System |
| Community Solid Server |
@css:config/file.json, @css:config/memory.json, @css:config/default.json - predefined config files |
| Nextcloud |
None - uses installation wizard |
| Mastodon |
None - single config model |
| Docker Compose |
Profiles (--profile dev, --profile prod) |
| Vite |
Modes (--mode development, --mode production) |
| webpack |
Mode option with preset behaviors |
| ESLint |
Extends (extends: ['eslint:recommended']) |
| Prettier |
None - but common in ecosystem |
| TypeScript |
Extends in tsconfig (extends: '@tsconfig/node18/tsconfig.json') |
The preset pattern is well-established in JavaScript tooling (Vite, webpack, ESLint, TypeScript) and aligns with CSS's approach of predefined configurations.
Preset Comparison Matrix
| Feature |
minimal |
personal |
community |
private |
federation |
developer |
| Port |
3000 |
443 |
443 |
443 |
443 |
3000 |
| Single User |
✅ |
✅ |
❌ |
❌ |
❌ |
❌ |
| Multi User |
❌ |
❌ |
✅ |
✅ |
✅ |
✅ |
| Invite Only |
- |
- |
❌ |
✅ |
❌ |
❌ |
| IdP |
❌ |
✅ |
✅ |
✅ |
✅ |
✅ |
| Conneg |
❌ |
✅ |
✅ |
✅ |
✅ |
✅ |
| Notifications |
❌ |
✅ |
✅ |
✅ |
✅ |
✅ |
| Mashlib |
❌ |
✅ |
✅ (CDN) |
✅ |
✅ (CDN) |
✅ |
| ActivityPub |
❌ |
❌ |
❌ |
❌ |
✅ |
✅ |
| Nostr |
❌ |
❌ |
❌ |
❌ |
✅ |
✅ |
| Git |
❌ |
❌ |
❌ |
❌ |
❌ |
✅ |
| Default Quota |
50MB |
10GB |
100MB |
1GB |
500MB |
1GB |
Documentation Updates
README.md Addition
## Quick Start with Presets
JSS provides presets for common deployment scenarios:
| Preset | Use Case |
|--------|----------|
| `minimal` | Local development and testing |
| `personal` | Single-user production server |
| `community` | Multi-user with open registration |
| `private` | Multi-user with invite-only access |
| `federation` | Full ActivityPub + Nostr support |
| `developer` | All features enabled for testing |
\`\`\`bash
# Start with a preset
jss start --preset personal
# Override specific settings
jss start --preset personal --port 8443
# List available presets
jss presets
# View preset details
jss presets --show federation
\`\`\`
Testing Plan
- Unit tests: Verify preset merging logic
- Integration tests: Start server with each preset, verify expected behavior
- Override tests: Ensure CLI/env/file overrides work correctly with presets
- Error handling: Unknown preset name, invalid combinations
// Example test
describe('presets', () => {
it('should apply personal preset defaults', () => {
const config = loadConfig({ preset: 'personal' });
expect(config.singleUser).toBe(true);
expect(config.idp).toBe(true);
expect(config.port).toBe(443);
});
it('should allow overrides on top of preset', () => {
const config = loadConfig({ preset: 'personal', port: 8443 });
expect(config.port).toBe(8443);
expect(config.singleUser).toBe(true); // from preset
});
it('should reject unknown preset', () => {
expect(() => loadConfig({ preset: 'invalid' })).toThrow(/Unknown preset/);
});
});
Related Issues
Open Questions
- Should presets be extensible (allow users to define custom presets in config)?
- Should there be a
--print-preset <name> to output preset as JSON for piping?
- Should presets warn about missing requirements (e.g., SSL certs for port 443)?
- Should
jss start with no arguments suggest using a preset?
Summary
Add configuration presets that bundle sensible defaults for common deployment scenarios. This is a low-effort, high-impact improvement that reduces friction for new users while maintaining full customization flexibility.
Difficulty: 15/100
Estimated Effort: 1-2 days
Dependencies: None
Problem
Currently, users face 30+ configuration options without guidance on which combinations make sense for their use case. New users must:
This creates unnecessary friction, especially for common scenarios that have well-known "best" configurations.
Proposed Solution
Usage
Preset Definitions
minimal- Development & TestingQuick local development, CI/CD testing, demos.
{ "port": 3000, "host": "localhost", "multiuser": false, "singleUser": true, "singleUserName": "dev", "conneg": false, "notifications": false, "idp": false, "mashlib": false, "git": false, "nostr": false, "activitypub": false }localhostonlypersonal- Single-User ProductionPersonal data pod, self-hosted for one person.
{ "port": 443, "host": "0.0.0.0", "multiuser": false, "singleUser": true, "singleUserName": "me", "conneg": true, "notifications": true, "idp": true, "mashlib": true, "mashlibCdn": false, "git": false, "nostr": false, "activitypub": false, "defaultQuota": "10GB" }community- Multi-User Open RegistrationCommunity server with open registration.
{ "port": 443, "host": "0.0.0.0", "multiuser": true, "singleUser": false, "conneg": true, "notifications": true, "idp": true, "inviteOnly": false, "mashlib": true, "mashlibCdn": true, "git": false, "nostr": false, "activitypub": false, "defaultQuota": "100MB" }private- Multi-User Invite-OnlyOrganization or private group server.
{ "port": 443, "host": "0.0.0.0", "multiuser": true, "singleUser": false, "conneg": true, "notifications": true, "idp": true, "inviteOnly": true, "mashlib": true, "mashlibCdn": false, "git": false, "nostr": false, "activitypub": false, "defaultQuota": "1GB" }federation- Federated Social ServerFull federation with ActivityPub and Nostr.
{ "port": 443, "host": "0.0.0.0", "multiuser": true, "singleUser": false, "conneg": true, "notifications": true, "idp": true, "inviteOnly": false, "mashlib": true, "mashlibCdn": true, "git": false, "nostr": true, "nostrPath": "/relay", "nostrMaxEvents": 5000, "activitypub": true, "defaultQuota": "500MB" }developer- Full Features for TestingAll features enabled for development/testing.
{ "port": 3000, "host": "0.0.0.0", "multiuser": true, "singleUser": false, "conneg": true, "notifications": true, "idp": true, "inviteOnly": false, "mashlib": true, "mashlibCdn": false, "git": true, "nostr": true, "activitypub": true, "webidTls": true, "defaultQuota": "1GB" }Implementation Details
Config Loading Changes
CLI Addition
List Presets Command
Show Preset Details
Enhanced
jss initIntegrationUpdate
jss initto offer preset selection:Industry Comparison
@css:config/file.json,@css:config/memory.json,@css:config/default.json- predefined config files--profile dev,--profile prod)--mode development,--mode production)extends: ['eslint:recommended'])extends: '@tsconfig/node18/tsconfig.json')The preset pattern is well-established in JavaScript tooling (Vite, webpack, ESLint, TypeScript) and aligns with CSS's approach of predefined configurations.
Preset Comparison Matrix
Documentation Updates
README.md Addition
Testing Plan
Related Issues
Open Questions
--print-preset <name>to output preset as JSON for piping?jss startwith no arguments suggest using a preset?